From 3f39a4fbdf08fa724e5047b82e3437ddf9b83bf4 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 24 Sep 2009 00:09:27 +0000 Subject: etextools update (23sep09) git-svn-id: svn://tug.org/texlive/trunk@15437 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/etextools/README | 26 +- .../doc/latex/etextools/etextools-examples.pdf | Bin 80209 -> 0 bytes .../doc/latex/etextools/etextools-examples.tex | 131 +- .../texmf-dist/doc/latex/etextools/etextools.pdf | Bin 635108 -> 1041283 bytes .../source/latex/etextools/etextools.drv | 62 + .../source/latex/etextools/etextools.dtx | 5126 +++++++++++++++----- .../source/latex/etextools/etextools.ins | 9 +- .../texmf-dist/tex/latex/etextools/etextools.sty | 1260 +++-- 8 files changed, 5152 insertions(+), 1462 deletions(-) delete mode 100644 Master/texmf-dist/doc/latex/etextools/etextools-examples.pdf create mode 100644 Master/texmf-dist/source/latex/etextools/etextools.drv 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 Binary files a/Master/texmf-dist/doc/latex/etextools/etextools-examples.pdf and /dev/null 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 Binary files a/Master/texmf-dist/doc/latex/etextools/etextools.pdf and b/Master/texmf-dist/doc/latex/etextools/etextools.pdf 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 +%% +%% 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}. +% +% \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.}. % -% 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. +% 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. % -% \subsection{The example file} +% \Subsection{The example file} % -% The example file provided with \thispackage\ illustrates the macros defined here. +% The \hyperref{file:etextools-examples}{ettlex}{toc}{example file} provided with \thispackage\ illustrates the macros defined here. % -% \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-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. % -% \subsection{Acknowledgements -- Thank You !} +% \Subsection{Acknowledgements -- Thank You !} % -% Thanks to Philipp Lehman for the \sty{etoolbox} package (and also for this nice class of documentation). +% 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). +% +% \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} +% +% {\rmk \cs{@swap} is used in the definitions of \cmdref{expandaftercmds} and \cmdref{protectspace}.} +% +% \cmditem-{@swaparg}{ code }{ command } +% +% 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}}. % -% 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: +% \cmditem-{@swaplast}{ token1 }{ token2 }{ token3 } % -% \qquad |\expandafter\ifblank\expandafter{\foo}{|\prm{true part}|}{|\prm{false part}|}| +% \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 % -% With |\expandnext| you'll just have to say: +% {\rmk \cs{@swaplast} is used in the definition of the command-list-parser defined with \cmdref{DeclareCmdListParser}.} % -% \qquad |\expandnext\ifblank{\foo}{|\prm{true part}|}{|\prm{false part}|}| +% \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 } % -% \cmditem{noexpandcs}{csname} \cmdlabel{noexpandcs}\seeimpl{noexpandcs} +% \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} % -% In an \FE expansion context (|\edef|) we often want a control sequence whose name results +% \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}!} +% +% In fact, it is possible because \CSbf{naturalloop} is defined in terms of \CSbf{ExpandNext}. +% +% {\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{}}|§ @@ -363,1413 +845,3762 @@ 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{ifempty}{string}{true}{false} \cmdlabel{ifempty} \seeimpl{ifempty} +% \cmditem{showcs}{ csname } % -% |\ifempty|\FE 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} +% \cs{showcs}\FE does \cs{show} on the named control sequence. % -% |\ifempty| is based on |\detokenize| and accept anything in its argument. +% \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{xifempty}{string or cs-token}{true}{false} \cmdlabel{xifempty} \seeimpl{xifempty} +% \cmditem{strip@meaning}{ cs-token } +% \cmditem*{strip@meaningcs}{ csname } \FEII* % -% |\xifempty|\pdfFE is similar to |\ifempty| but the argument is expanded during comparison. +% \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} % -% \begin{tabbing} -% \quad\=|\def\x{\@empty}\def\y{}| \\ -% \>|\xifempty{\x\y}| \prm{true}\prm{false} -% \end{tabbing} +% \cs{strip@meaningcs} does the same for named control sequences. % -% {\rmk The macro is based on the \cs{pdfstrcmp} primitive.} +% \cmditem{parameters@meaning}{ cs-token } +% \cmditem*{parameters@meaningcs}{ csname } \FEII* % -% \cmditem{ifnotempty}{string}{true}{false} \cmdlabel{ifnotempty}\seeimpl{ifnotempty} +% \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. % -% |\ifnotempty|\FE reverses the test of |\ifempty| +% \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§ % -% \cmditem{xifblank}{string}{true}{false} \seeimpl{xifblank} +% {\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$). % -% |\xifblank| is similar to |\ifblank| except that the \prm{string} is first expanded -% with |\protected@edef|. -% \medbreak % -% \cmditem{iffirstchar}{string1}{string2}{true}{false} \cmdlabel{iffirstchar}\seeimpl{iffirstchar} -% \cmditem*{iffirstchar}{}{string}{true}{false} +% \Subsection{The \cs{ifx} test and the character test} +% \cmdlabel{character-test} % -% |\iffirstchar| \FE compares the character codes of the \textbf{first} characters of each \prm{string}. The +% 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. % -% 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} +% \qquad|\iffirstchar|\mprm{}\mprm{whatever}¤expands\prmb{true} only if \prmb{whatever} is empty. % -% 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 +% \ClearPage* +% \cmditem+{ifiscs}{ string }{ true }{ false } % -% \cmditem{ifsinglechar}{string1}{string2}{true}{false} \cmdlabel{ifsinglechar}\seeimpl{ifsinglechar} +% \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} % -% |\ifsinglechar|\FE performs the test |\iffirstchar| but only if \prm{string2} has one single character. +% \cs{ifiscs} is an optimized form of: ``\cs{ifOneToken} AND NOT \cs{ifOneChar}''. % -% 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 +% {\rmk \cs{ifiscs} is used in the definition of the \cmdref=[DeclareCmdListParser]{command-list parsers}.} % -% \MakeShortVerb{\|} -% But: \cs{ifsinglechar} *\{*\textvisiblespace\}\quad is \textbf{always false}. +% \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} % -% \cmditem{iflastchar}{string1}{string2}{true}{false} \cmdlabel{iflastchar}\seeimpl{impl:iflastchar} +% {\rmk \cs{detokenizeChars} is used in the normal form of \cmdref{futuredef}.} % -% |\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). +% \cmditem{protectspace}{ code } % -% |\iflastchar| is NOT purely expandable (use \cmdref{ifstrmatch} for purely expandable test). +% \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}... % -% \cmditem{ifstrcmp}{string1}{string2}{true}{false} \cmdlabel{ifstrcmp}\seeimpl{ifstrcmp} +% {\rmk \cs{protectspace} is used in \cmdref{detokenizeChars}.§ +% \cs{protectspace} is an example of a \textbf{recursive macro which is 2-purely expandable. }} % -% |\ifstrcmp|\pdfFE is the \LaTeX{} form of |\pdfstrcmp| primitive. +% \end{ltxsyntax} % -% Neither \prm{string1} not \prm{string2} is expanded during comparison. The comparison is -% \textit{catcode agnostic} (use of |\detokenize |). +% \Section{Characters and Strings} % -% \cmditem{ifstrmatch}{pattern}{string}{true}{false} \cmdlabel{ifstrmatch}\seeimpl{ifstrmatch} +% \begin{ltxsyntax} % -% |\ifstrmatch|\pdfFE is based on the |\pdfmatch| primitive that implements POSIX-regex. +% \cmditem+{ifempty}{ string }{ true }{ false } % -% 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}. -% \end{ltxsyntax} +% \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}: % -% \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} +% \quad\=|\expandnext\ifempty{\macro}| \prm{true}\prm{false} % \end{tabbing} % -% Moreover (in the style of |\@testopt|): +% |\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 } +% +% |\xifempty|\pdfFE is similar to |\ifempty| but the argument is expanded during comparison. +% % \begin{tabbing} -% \qquad\= |\def\MacroWithOption#1{\ifsing|\=|lechar|\=|[{#1}|\\ -% \>\>|{\MacroHasOption#1}|\\ -% \>\>|{\MacroHasOption[default]{#1}}}| +% \quad\=|\def\x{\@empty}\def\y{}| \\ +% \>|\xifempty{\x\y}| \prm{true}\prm{false}¤¤ will expand \prm{true} % \end{tabbing} % -% \begin{ltxsyntax} +% {\rmk If pdf\TeX{} is in use, the macro is based on the \cs{pdfstrcmp} primitive.} % -% \cmditem{FE@testopt}{argument to be tested}{commands}{default option} \cmdlabel{FE@testopt}\seeimpl{FE@testopt} +% \cmditem{ifnotempty}{ string }{ true }{ false } % -% |\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{ifnotempty}\FEII reverses the test of |\ifempty|. % -% Note that |\MacroWithOption| \textbf{must have at least one mandatory argument.}\medbreak % -% {\rmk |\FE@testopt| is used in the definition of \cmdref{DeclareCmdListParser}.} +% \cmditem{xifblank}{ string }{ true }{ false } % -% \cmditem{FE@ifstar}{argument to be tested}{star-commands}{non-star commands} \cmdlabel{FE@ifstar}\seeimpl{FE@ifstar} +% |\xifblank|\notFE\\ is similar to |\ifblank| except that the \prm{string} is first expanded +% with \cs{protected@edef}. % -% 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{ifnotblank}{ string }{ true }{ false } % -% Remember that |\StarredCommand| and |\NotStarredCommand| \textbf{must have at least one mandatory argument.} +% \csbf{ifnotblank} \FEII reverses the test of |\ifblank|. % -% {\rmk |\FE@ifstar| is used in the definitions of \cmdref{DeclareCmdListParser}, \cmdref{csvloop}, \cmdref{listloop} -% and \cmdref{toksloop}.} +% {\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}.} % -% \cmditem{FE@ifchar}{Variant Mark Character}{argument to be tested}{special-commands}{normal-commands}\cmdlabel{FE@ifchar}\seeimpl{FE@ifchar} % -% As a\FE generalisation of \cs{FE@ifstar} \sty{etextools} provides \cmd{FE@ifchar} for use with other variants than the star-form. +% \cmditem+{deblank}{ string } % -% For example, to define a `\,$\boldsymbol{+}$\,` variant: -% \begin{tabbing} -% \qquad\=|\def\SpecialMacro#1{\FE@|\=|ifchar|{+}\=|{#1}|\\ -% \>\>|{\SpecialFormMacro}|\\ -% \>\>|{\NormalFormMacro}}| -% \end{tabbing} +% |\deblank|\FEII removes all leading and trailing blank spaces from its argument.\medbreak % -% |\SpecialMacro| must have at least one mandatory argument. +% 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} % -% \end{ltxsyntax} +% 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}. % -% \section{Lists management} +% 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. % -% \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. -% \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...}. -% \fi +% \cmditem{ifstrcmp}{ string1 }{ string2 }{ true }{ false } % -% 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. +% \csbf{ifstrcmp}\pdfFE is based on the |\pdfstrcmp| primitive (or the XeTeX-|\strcmp|) if available. Otherwise, +% |\ifstrcmp| is |\let| to \xpackage{etoolbox}-\cs{ifstrequal}. % -% 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. +% Neither \prm{string1} nor \prm{string2} is expanded during comparison. The comparison is +% \emph{catcode agnostic} (use of |\detokenize |). % -% {\rmk The star-form of \cmdref{csvloop} will be explained below.} +% \cmditem{xifstrequal}{ string1 }{ string2 }{ true }{ false } % -% \begin{ltxsyntax} +% |\xifstrequal|\notFE\ is the same as \xpackage{etoolbox}-|\ifstrequal| apart that each parameter string is expanded +% (with |\protected@edef|) before comparison. % -% \cmditem{DeclareCmdListParser}{command}{separator}\cmdlabel{DeclareCmdListParser}\seeimpl{DeclareCmdListParser} +% \cmditem{xifstrcmp}{ string1 }{ string2 }{ true }{ false } % -% |\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)}. +% |\xifstrcmp|\pdfFE is the \LaTeX{} form of |\pdfstrcmp| primitive. If this primitive is not available, +% |\xifstrcmp| is |\let| to |\xifstrequal|. % -% 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. +% \prm{string1} and \prm{string2} are expanded during comparison. % -% 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} +% \cmditem[ifcharupper]@{ifcharupper\tsptb ifcharlower} +% \cmditem-{ifcharupper}{ single char }{ true }{ false } +% \cmditem-{ifcharlower}{ single char }{ true }{ false } \FEII* +% +% \csbf{ifcharupper}\FEII compares with |\ifnum| the character code of \prm{single char} with its |\uccode|. +% +% \csbf{ifcharlower} compares with |\ifnum| the character code of \prm{single char} with its |\lccode|. % -% \subsection{Loops into lists} +% \cmditem{ifuppercase}{ string }{ true }{ false } +% \cmditem-{iflowercase} {string }{ true }{ false } % -% Now we have to declare two command-list-parsers : |\listloop| for \sty{etoolbox} lists -% and |\csvloop| for comma-separated lists. +% \csbf{ifuppercase}\notFE\ compares the \prm{string} with |\uppercase{|\prm{string}|}|. % -% \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} +% \csbf{iflowercase} compares the \prm{string} with |\lowercase{|\prm{string}|}|. % -% |\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 : +% The commands are robust. +% +% \cmditem{ifstrmatch}{ pattern }{ string }{ true }{ false } +% +% \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} -% \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}| +% \quad\=\cs{ifstrmatch}\{[\textasteriskcentered]\$\}\{\prm{string}\} % \end{tabbing} +% 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} % -% The token list is a list without delimiter. +% {\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)) % -% \subsection{Converting csv lists to \sty{etoolbox}-lists} +% ($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") % -% \cmditem{csvtolist}{listmacro}{csvlistmacro} \cmdlabel{csvtolist}\seeimpl{csvtolist} -% \cmditem*{csvtolist*}{listmacro}{item,item,item...} +% ($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") % -% |\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|... +% ($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") % -% It's also the first application of the \cmdref{csvloop} macro just defined. +% ($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" % -% \cmditem{csvtolistadd}{listmacro}{csvlistmacro} \cmdlabel{csvtolistadd}\seeimpl{csvtolistadd} -% \cmditem*{csvtolistadd*}{listmacro}{item,item,item...} +% ($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} % -% |\csvtolistadd| acts similarly but does not reset the \prm{listmacro} to |\@empty|. +% \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] % -% \subsection{Converting lists of tokens to \sty{etoolbox}-lists} +% {\rmk \cs{CompareYES} and each of its form are purely expandable thank to \cmdref{FE@modifiers}.} % -% \cmditem{tokstolist}{listmacro}{tokenslistmacro} \cmdlabel{tokstolist}\seeimpl{tokstolist} -% \cmditem*{tokstolist*}{listmacro}{list of tokens} +% 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 % -% |\tokstolist| converts a list of tokens (no separator) into an internal \sty{etoolbox} list. +% \end{ltxsyntax} % -% It's also the first application of the \cmdref{toksloop} macro just defined. +% \ClearPage* % -% \cmditem{tokstolistadd}{listmacro}{tokslistmacro} \cmdlabel{tokstolistadd}\seeimpl{tokstolistadd} -% \cmditem*{tokstolistadd*}{listmacro}{list of tokens} +% \Section{Fully expandable macros with options and modifiers} % -% |\tokstolistadd| acts similarly but does not reset the \prm{listmacro} to |\@empty|. - +% 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. % -% \subsection{Removing elements from \sty{etoolbox}-lists} +% \begin{ltxsyntax} % -% 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{FE@testopt}{\#1}{ commands }{ default option } % +% \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} % -% \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} +% \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}). % -% The |\listdel| command removes the element \prm{item} from the list \prm{listmacro}. Note that the -% \prm{listmacro} is redefined after deletion: +% Just like \cs{@testopt}, \cs{FE@testopt} is sensitive to the category code of \CH{\chcat\textasteriskcentered{12}} which must be \textvb{other}. % -% 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|: +% {\rmk |\FE@testopt| is used in the definition of \cmdref{DeclareStringFilter}, \cmdref{avoidvoid}, \cmdref{ettl@supergobble} +% and \cmdref{csvtolist}.} % -% \end{ltxsyntax} +% \cmditem{FE@ifstar}{\#1}{ star-commands }{ non-star commands } % -% \subsection{Index of an element in a list} +% 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} % -% \subsubsection{\sty{etoolbox}-lists} +% Just like \cs{@ifstar}, \cs{FE@ifstar} is sensitive to the category code of \stform* which must be \textvb{other}. % -% \begin{ltxsyntax} +% {\rmk |\FE@ifstar| is used in the definitions of \cmdref{csvtolist}, \cmdref{listtocsv} and \cmdref{tokstolist}.} % -% \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} +% \cmditem{FE@ifchar}{ Variant Character }{\#1}{ special-commands }{ normal-commands } % -% \end{ltxsyntax} +% As a\FE generalisation of \cs{FE@ifstar} \thispackage provides \csbf{FE@ifchar} for use with other variants than the \stform*-form. % -% 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. +% 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} % -% The comparison is \textit{catcode agnostic}. +% 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). % -% As for the command-list-parser, the star versions are designed in case the list (in the second argument) is already expanded. +% \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... % -% When used\pdfFE on pdf\TeX{}, |\pdfstrcmp| does the comparison and the macros are 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} +% \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. % -% 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: -% \begin{tabbing} -% \qquad\=|\getlistindex[\myindex]{|\prm{item}|}{|\prm{listmacro}|}| \\ -% \end{tabbing} +% 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) {(&red\FE@modifiers{(&blue * + - )}){} +% {(&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 +% 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} % -% \textbf{N.B. If \cs{myindex} is not a counter it is (possibly \textit{re-})defined as macro.} +% \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. % -% \subsubsection{Comma-separated lists} +% {\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}.} % -% \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,...} -% \end{ltxsyntax} +% \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}$} % -% This is the same as \cmdref{getlistindex} but for comma-separated lists. +% \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} % -% As for the command-list-parser, the star versions are designed in case the list (in the second argument) is already expanded. +% 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. % -% Those macros\pdfFE are purely expandable only if |\pdfstrcmp| exists. +% Now if \PRM[\blue]{$\mathbf{n}$}$=$\PRM[\blue]{$\mathbf{N}$}, \csbf{ettl@supergobble} +% gobbles the \PRM[\blue]{$\mathbf{N}$} tokens (including the last). % -% Otherwise, use the optional argument to let the result in: -% \begin{tabbing} -% \qquad\=|\getcsvlistindex*[\myindex]{|\prm{item}|}{|\prm{item,item,item...}|}| \\ -% \end{tabbing} +% 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). % -% If \cs{myindex} is not a counter it is (possibly \textit{re-})defined as macro. +% 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$...). % -% \subsubsection{Lists of tokens} +% {\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!} % -% \begin{ltxsyntax} -% \cmditem{gettokslistindex}[myindex]{item}{tokenslistmacro} \cmdlabel{gettokslistindex}\seeimpl{gettokslistindex} -% \cmditem*{gettokslistindex*}[myindex]{item}{list of tokens} % \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* +% \Section{Define control sequences through groups} % -% Therefore, \cs{gettokslistindex} is \textbf{always purely expandable}, but for symmetry reasons, the optional form:§ -% \begin{tabbing} -% \qquad\=|\gettokslistindex[\myindex]{|\prm{item}|}{|\prm{tokenslistmacro}|}| \\ -% and:\> |\gettokslistindex*[\myindex]{|\prm{item}|}{|\prm{list of tokens}|}| -% \end{tabbing} -% are defined. +% \begin{ltxsyntax} % -% An interesting application is the following: +% \cmditem[AfterGroup]@{AfterGroup\tsptb AfterGroup\stform*} +% \cmditem-{AfterGroup}{ code } +% \cmditem-{AfterGroup\stform*}{ code } % -% \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} +% 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. % -% Please, refer to the examples... +% 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{Extract by index from a list} +% \cmditem{AfterAssignment}{ code } % -% \begin{ltxsyntax} +% In the same order of idea,\notFE\ \csbf{AfterAssignment} allows arbitrary \prm{code} to be expanded \cs{afterassignment}. % -% \subsubsection{\sty{etoolbox}-lists} +% \cmditem+{aftergroup@def}{ command } % -% \cmditem{getlistitem}{index [numexpr expression]}{listmacro} \cmdlabel{getlistitem}\seeimpl{getlistitem} -% \cmditem*{getlistitem*}{index [numexpr expression]}{list} +% 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. % -% 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} +% 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}). % -% \subsubsection{Comma-separated lists} +% \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} % -% \cmditem{getcsvlistitem}{index [numexpr expression]}{csvlistmacro} \cmdlabel{getcsvlistitem}\seeimpl{getcsvlistitem} -% \cmditem*{getcsvlistitem*}{index [numexpr expression]}{item,item,item,...} % -% This is\FE the same as \cmdref{getlistitem} but for comma-separated lists. +% \end{ltxsyntax} % -% \subsubsection{Lists of tokens} +% \ClearPage* % -% \cmditem{gettokslistitem}{index [numexpr expression]}{tokenslistmacro} \cmdlabel{gettokslistitem}\seeimpl{gettokslistitem} -% \cmditem*{gettokslistitem*}{index [numexpr expression]}{list of tokens} +% \Section[{Vectorized \texorpdfstring{\cs[\sfbf]{futurelet}}{\cs{futurelet}}}]{Vectorized \csbf{future{\blue let}}: \csbf{future{\spot def}}} % -% The same\FE as \cmdref{getlistitem} for list of tokens. -% \end{ltxsyntax} +% \begin{ltxsyntax} +% +% \cmditem+{@ifchar}{ single token }{ true }{ false } +% +% \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}. +% +% \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} % -% \section{Vectorized \cmd{futurelet}} +% {\rmk Unless \cs{@ifstar}, \cs{@ifchar} is a |\long| macro...} % +% \cmditem{ettl@ifnextchar}{ single token }{ true }{ false } % -% \sty{etextools} defines a vectorized version of \cs{futurelet}. The idea is to say: +% \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 % -% \quad|\collecttoks\macro{|\prm{list of allowed tokens}|}{|\prm{commands to execute next}|}| +% \thispackage defines a vectorized version of \cs{futurelet}. The idea is to say: % -% Then \cs{collecttoks} is a kind of simple scanner for tokens. It can be used to define an \textbf{\textit{undelimited macro}} +% \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. % -% \begin{ltxsyntax} -% \cmditem{collecttoks}{cs-token}{list of tokens}{commands to expand after} \cmdlabel{collecttoks}\seeimpl{collecttoks} -% \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. +% \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} % -% 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. +% \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} % % \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: +% 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} % % 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: -% -% \begin{Verbatim}[gobble=1,commandchars=!()] -% !textbf(\switch[\pdfstrcmp{\nexttokens}]) +% \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]% +% \case{{.-.}}\hdashline[parameters]% % \otherwise \original@hline% -% !textbf(\endswitch) -% \end{Verbatim} +% \endswitch +% \end{VerbLines} % -% \CSbf{switch} is purely expandable. +% \CSbf{switch} is purely expandable when used with \cs{pdfstrcmp} (pdf\TeX{}). % -% If you replace \cs{pdfstrcmp} by |\ifstrequal|, \cs{switch} works but is not purely expandable. +% See \xpackage{boolexpr} (\CTAN{macros/latex/contrib/boolexpr/}) for more information on \cs{switch}. % -% See \sty{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} % +% 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}. % +% 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}. % +% {\rmk You may use indifferently \cs{futuredef\stform*\stform=} or \cs{futuredef\stform=\stform*}.} % -% \StopEventually{ -% } +% \ClearPage* +% \Section{Lists management} % -% \part*{\LaTeX{} code} -% \addtocontents{toc}{\protect\contentsline{part}{\large\LaTeX{} code}{}{}} +% \Subsection{The natural loop} % -% \section{Implementation} +% \begin{ltxsyntax} +% \cmditem{naturalloop}[auxiliary commands]{ number of times }{ argument } % -% \subsection{Package identification} +% {\bfseries The \csbf{naturalloop}\FE macro applies the \prmb{auxiliary commands} exactly $n$ times onto the +% \prmb{argument},} \ie:§ +% \begin{framed} +% \begin{tabbing} +% ¤¤\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. % -% \begin{macrocode} -%<*package> -\NeedsTeXFormat{LaTeX2e}[1996/12/01] -\ProvidesPackage{etextools} - [2009/08/14 v2h e-TeX more useful tools for LaTeX package writers] -\csname ettl@onlyonce\endcsname\let\ettl@onlyonce\endinput -% \end{macrocode} +% \end{ltxsyntax} % -% \subsection{Requirements} % -% This package requires the packages \sty{etex} package by David Carlisle and -% \sty{etoolbox} by Philipp Lehman. +% \Subsection{Lists of single tokens / characters} \cmdlabel{list of single tokens} % -% \begin{macrocode} -\RequirePackage{etex,etoolbox} -% \end{macrocode} +% 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. % -% Furthermore, the space token must have its natural catcode (10) all along this package. +% 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). % -% \begin{macrocode} -\let\ettl@AtEnd\@empty -\def\TMP@EnsureCode#1#2{% - \edef\ettl@AtEnd{% - \ettl@AtEnd - \catcode#1 \the\catcode#1\relax - }% - \catcode#1 #2\relax -} -\TMP@EnsureCode{32}{10}% space -\ifundef\pdfstrcmp{% - \TMP@EnsureCode{33}{9}% ! ignore - \TMP@EnsureCode{34}{14}% " comment -}{\TMP@EnsureCode{33}{14}% ! comment - \TMP@EnsureCode{34}{9}% " ignore -} -\AtEndOfPackage{\ettl@AtEnd\undef\ettl@AtEnd} -% \end{macrocode} +% 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. % -% \subsection{A few (7) ``helper'' macros} +% 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}). % -% \iffalse -% -%% A few helper macros -% \fi -% \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} -% \end{macrocode} +% \begin{ltxsyntax} % -% \iffalse -% -% \fi +% \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* % -% \begin{macro}{\ettl@ifstrcmp} -% Use of the pdf\TeX{} primitive \cs{pdfstrcmp} and design a \LaTeX{} form. -% \begin{macrocode} -\def\ettl@ifstrcmp#1#2{\csname @% - \ifnum\pdfstrcmp{#1}{#2}=0 first\else second\fi oftwo\endcsname} -% \end{macrocode} -% \end{macro} +% \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}. % -% \begin{macro}{\@gobblescape} +% {\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.} % -% This sequence of command 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} -% \end{macrocode} -% {\rmk May be we could do better, testing first if the next token is a control sequence...} -% \end{macro} +% \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* % -% \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)}}} - {}} -% \end{macrocode} +% 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} % -% \subsection{Expansion control} +% {\rmk \cs{ifincharlist} is used in the definition of \cmdref{futuredef}.} % +% \begin{ltxsyntax} +% \cmditem+{gettokslistindex}{item}{list of single tokens} % -% \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{macrocode} -\newcommand*\noexpandcs[1]{\expandafter\noexpand\csname #1\endcsname} -% \end{macrocode} -% \end{macro} +% \csbf{gettokslistindex}\FEII expands to the index of \prmb{item} in the list of single tokens given as a second argument. % -% \begin{macro}{\noexpandafter}\cmdlabel{impl:noexpandafter} -% {\rmk \cmd{noexpandafter} only means \cmd{noexpand}\cmd{expandafter} and is shorter to type.}\seedesc{noexpandafter} -% \begin{macrocode} -\newcommand\noexpandafter{\noexpand\expandafter} -% \end{macrocode} % -% \end{macro} +% \textbf{Note that the \opt{index} is $\mathbf0-$based} for consistency with |\ifcase| ({\mdfs and also with +% \cmdref{ettl@supergobble}}). +% \ClearPage % -% \begin{macro}{\expandnext}\cmdlabel{impl:expandnext} +% 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 % -% This code is not properly \seedesc{expandnext} tricky but if you're eager to understand the job of each expandafter, -% it's best to go straight at the log. +% Please, refer to the examples... % -% Note that the first argument of |\expandnext| must be a single \prm{cstoken} (for \cmd{expandafter} acts -% only on the first following token). +% This feature is extensively used in \cmdref{FE@modifiers}. % -% \iffalse -% -%% \expandnext : expansion control -%% level 1 : \expandnext#1{...} <=> \expandafter#1\expandafter{...} -%% level 2 : \expandnext\expandnext#1{...} etc. -% \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} -\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} -% \end{macrocode} -% \end{macro} -% \iffalse -% -% \fi +% {\rmk \cmdref*{gettokslistindex} is kind of masterpiece of purely expandable programming with \eTeX} % +% \cmditem+{getcharlistindex}{item}{list of single tokens} % -% \subsection{Character and Strings} +% \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}). % -% \iffalse -% -%% \ifempty{ text }{ true }{ false } -% \fi +% {\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 +% +% \Subsection[The General Command-List-Parser]{The General Command-List Parser Constructor} +% +% 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 +% +% 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. +% +% 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\= |\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. +% +% {\rmk The star-form of \cmdref{csvloop} will be explained below.} +% +% \begin{ltxsyntax} +% \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} +% +% \ClearPage +% \Subsection{Loops into lists} +% +% 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\=|\forcsvloop|\stform*|{|\=|\relax\meaning|\=|\csname|\=|,%|\\ +%\>\> |\afterassignment\global\count,%|\\ +% \>\>|\endgroup\topskip}\do{%|\\ +% \>\>\> |\fortoksloop|\stform*|{|\#1|}\do{\meaning|\#{\#1}|}}| +% \end{tabbing} +% +% 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. +% +% \end{ltxsyntax} +% +% \Subsection{Adding elements to csv lists} +% +% \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} +% +% \end{ltxsyntax} +% \ClearPage* +% +% \Subsection{Test if an element is in a list} +% +% \xpackage{etoolbox} provides \cmd{ifinlist} and \cmd{xifinlist}. Similarly, \thispackage provides: +% +% \begin{ltxsyntax} +% +% \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} +% +% These macros\notFE\ are not purely expandable. The search is sensitive to the category code +% of the characters in \prm{item}. +% +% \end{ltxsyntax} +% +% \Subsection{Removing elements from lists} +% +% \subsubsection{\xpackage{etoolbox} lists} +% +% 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} +% +% \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} +% +% \end{ltxsyntax} +% +% \subsubsection{csv-lists} +% +% \begin{ltxsyntax} +% +% \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} +% +% \Subsection{Index of an element in a list} +% +% \subsubsection{\xpackage{etoolbox}-lists} +% +% \begin{ltxsyntax} +% +% \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} +% +% \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. +% +% \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} +% +% Those macros are not purely expandable. +% +% 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*{{\spot\smiley}\hfill \LaTeX{} code\hfill{\spot\smiley}} +% \addtocontents{toc}{\protect\contentsline{part}{\LaTeX{} code}{}{}} +% \implementationsubsecformat +% +% \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} % -% \begin{macro}{\ifempty} \cmdlabel{impl:ifempty} -% |\ifempty| is based on |\detokenize| and can manage with any argument.\seedesc{ifempty} % \begin{macrocode} -\newcommand\ifempty[1]{\csname @\expandafter\ifx - \expandafter\relax\detokenize{#1}\relax - first\else second\fi oftwo\endcsname} +%<*package> +\NeedsTeXFormat{LaTeX2e}[1996/12/01] +\ProvidesPackage{etextools} + [2009/08/27 v3.0 e-TeX more useful tools for LaTeX package writers] +\csname ettl@onlyonce\endcsname\let\ettl@onlyonce\endinput % \end{macrocode} -% \end{macro} +% +% \Subsection{Requirements} +% +% 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,letltxmacro} +% \end{macrocode} +% +% 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{% + \edef\ettl@AtEnd{% + \ettl@AtEnd + \catcode#1 \the\catcode#1\relax + }% + \catcode#1 #2\relax +} +\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{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{Some ``helper'' macros} % % \iffalse % -%% \ifnotempty{ text }{ true }{ false } +%% A few helper macros % \fi % -% \begin{macro}{\ifnotempty} \cmdlabel{impl:ifnotempty} -% |\ifnotempty| is based on |\detokenize| and can manage with any argument.\seedesc{ifnotempty} +%\begin{macro}{helper macros} \FE % \begin{macrocode} -\newcommand\ifnotempty[1]{\csname @\expandafter\ifx - \expandafter\relax\detokenize{#1}\relax - second\else first\fi oftwo\endcsname} +\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} +%\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 % -%% \xifempty{ text }{ true }{ false } +%%% \ettl@onlypdfTeX for internal use % \fi -% \begin{macro}{\xifempty} \cmdlabel{impl:xifempty} -% |\xifempty| is based on pdf-TeX{} |\pdfstrcmp| and work with any argument.\seedesc{xifempty} +% +% \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} -\newcommand\xifempty[1]{\xifstrcmp{#1}{}} -\ettl@onlypdfTeX\pdfstrcmp\xifempty +\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} % % \iffalse % -%% \ifnotblank{ text }{ true }{ false } +%%% \ettl@nbk argument to be tested//{ true }{ false }// +%% `/` has a catcode of 3 all along this package % \fi % -% \begin{macro}{\ifnotblank} \cmdlabel{impl:ifnotblank} -% |\ifnotblank| reverses the test of |\ifblank|.\seedesc{ifnotblank} +% \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} -\begingroup\catcode`\&=3\catcode`\:=12 -\ifcsundef{ifnotblank}{% -\long\gdef\ifnotblank#1{\etb@ifblank@i#1&&\@firstoftwo\@secondoftwo:}} -\relax\endgroup +\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} +% \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 % -%% \xifblank{ string }{ true }{ false } +%% The following macros are not used (here just for memory, in case of...) % \fi % -% \begin{macro}{\xifblank}\cmdlabel{impl:xifblank} -% Just expands the parameter using |\protected@edef| before testing for |\ifblank|: \seedesc{xifblank} +%\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}: +% +% Usage: |\ettl@nbkcat |\prm{tokenA}\prm{string}|//|\prm{same catcodes}\prm{different catcodes}|//| % \begin{macrocode} -\newrobustcmd\xifblank[1]{\begingroup - \protected@edef\@xifblank{\endgroup - \noexpand\ifblank{#1}% - }\@xifblank} +\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} +%\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 +% +%%% \@gobblespace and The Space Token +% \fi +%\begin{Macro}{@gobblespace} +% \begin{macrocode} +\long\def\@gobblespace#1 {#1} +% \end{macrocode} +%\end{Macro} +% % \iffalse % -%% \iffirstchar{ string1 }{ string2 }{ true }{ false } +%%% \@gobblescape \cs-token % \fi % -% \begin{macro}{\iffirstchar}\cmdlabel{impl:iffirstchar} -% |\iffirstchar| test if |#1| and |#2| begins with the same character. \seedesc{iffirstchar} +% \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\iffirstchar[2]{\csname @% - \if \expandafter\@car\detokenize{#2}\relax\@nil\expandafter\@car\detokenize{#1}\string\\\@nil - \ifblank{#2}{second}{first}% - \else second% +\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} +% +% \iffalse +% +%% The swap macros +% \fi +% +%\begin{Macro}{@swap} +% \CS{@swap} reverses the order and does not add any curly braces: +% \begin{macrocode} +\newcommand\@swap[2]{#2#1} +\@swap{ }{\let\ettl@sptoken= }% This makes \ettl@sptoken a space token +% \end{macrocode} +%\end{Macro} +% +% \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}{@swaptwo} +% \CS{@swaptwo} reserves the order but keeps the curly braces: +% \begin{macrocode} +\newcommand\@swaptwo[2]{{#2}{#1}} +% \end{macrocode} +% {\rmk this macro is used in \cmdref{gettokslistindex}} +% \end{Macro} +% +% \Subsection{Expansion control} +% +% \iffalse +% +%%% \expandaftercmds : expansion control +%% level 1 : \expandaftercmds { code }{ cs-token } +%% 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\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} +% +% +% \begin{Macro}{expandnext} +% +% 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. +% +% \iffalse +% +%%% \expandnext : expansion control +%% level 1 : \expandnext { code }{ control sequences : the first is expanded before code } +%% level 2 : \expandnext\expandnext{ code }{ control sequences } +% \fi +% \begin{macrocode} +\newcommand\expandnext[2]{% + \ifsingletoken\expandnext{#1} + {\@expandnext{#2}{\expandafter\expandafter\expandafter}} + {\expandafter\@swaparg\expandafter{#2}{#1}}} +\long\def\@expandnext#1#2#3{% + \ifsingletoken\expandnext{#1} + {\@expandnext{#3}{\expandafter#2#2}} + {#2\@swaparg#2{#3}{#1}}} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \expandnexttwo{ code }{ control sequences }{ control sequences } +% \fi +% +%\begin{Macro}{expandnexttwo} +\newcommand\expandnexttwo[3]{\expandnext{\expandnext{#1}{#2}}{#3}} +%\end{Macro} +% +% \iffalse +% +%%% \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 +% +%%% \ExpandNext { code } { argument } +% \fi +% +% \begin{Macro}{ExpandNext} +% \cs{romannumeral} forces the expansion of the second \textbfsf{argument.} +% \begin{macrocode} + % 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} +% +% \iffalse +% +%%% \ExpandNextTwo { code } { arg1 }{ arg2 } +% \fi +% +%\begin{Macro}{ExpandNextTwo} +% \begin{macrocode} +\newcommand\ExpandNextTwo[3]{\ExpandNext{\ExpandNext{#1}{#2}}{#3}} +% \end{macrocode} +%\end{Macro} +% +% \iffalse +% +%% noexpandcs { csname } +% \fi +% +% \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*\noexpandcs[1]{\expandafter\noexpand\csname #1\endcsname} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%% noexpandafter +% \fi +% +% \begin{Macro}{noexpandafter} +% {\rmk \cmd{noexpandafter} only means \cmd{noexpand}\cmd{expandafter} and is shorter to type.} +% \begin{macrocode} +\newcommand*\noexpandafter{\noexpand\expandafter} +% \end{macrocode} +% +% \end{Macro} +% +% \Subsection{Meaning of control sequences} +% +% \iffalse +% +%%% \showcs { csname } +% \fi +% +% \begin{Macro}{showcs} +% \cs{showcs} shows the meaning of a named control sequence: +% \begin{macrocode} +\providecommand*\showcs[1]{\expandafter\show\csname#1\endcsname} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \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 +% +%%% \strip@meaning { cs-token } +%%% \strip@meaningcs { csname } +% \fi +% +% \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*\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 +% +%%% \parameters@meaning { cs-token } +%%% \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 +% +%%% \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 +% \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 +% +%%% \avoidvoid [ replacement code ]{ cs-token / string } +%%% \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 % -%% \ifsinglechar character{ string }{ true }{ false } +%%% \avoidvoidcs [ replacement code ]{ cs-name } +%%% \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 +% +%%% 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 % -%% \iflastchar{ string1 }{ string2 }{ true }{ false } +%%% \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 +% +%%% \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 +% +%%% \ifsinglechar character{ string }{ true }{ false } +% \fi +% +% \begin{Macro}{ifsinglechar} +% Test if \#2 is a single character equal to \#1: +% \begin{macrocode} +\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} +% +% \iffalse +% +%%% \ifOneChar{ string }{ true }{ false } +% \fi +% +% \begin{Macro}{ifOneChar} +% \cs{ifOneChar}\prm{string}\prm{true}\prm{false}¤ detokenizes \prm{string} first (see also \cmdref*{ifOneToken}): +% \begin{macrocode} +\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} +% +% \iffalse +% +%%% \ifOneCharWithBlanks{ string }{ true }{ false } +% \fi +% +%\begin{Macro}{ifOneCharWithBlanks} +% \begin{macrocode} +\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} +% +% \iffalse +% +%%% \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 % -%% \ifstrcmp{ string1 }{ string2 }{ true }{ false } +%%% \ifiscs { string }{ true }{ false } % \fi % -% \begin{macro}{\ifstrcmp}\cmdlabel{impl:ifstrcmp} -% The macro is base on the |\pdfstrcmp| primitive.\seedesc{ifstrcmp} +%\begin{Macro}{ifiscs} +% \cs{ifiscs}\prm{string} expands \prm{true} only if \prm{string} is a single control-word: % \begin{macrocode} -\newcommand\ifstrcmp[2]{\csname @% +\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} +% +% \iffalse +% +%%% \detokenizeChars { list of single tokens } +% \fi +% +%\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 +% +%%% \protectspace { string } +% \fi +% +%\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\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} +% +% \Subsection{Character and Strings} +% +% \iffalse +% +%%% \ifempty{ text }{ true }{ false } +% \fi +% +% \begin{Macro}{ifempty} +% |\ifempty| is based on |\detokenize| and can manage with any argument. +% \begin{macrocode} +\newcommand\ifempty[1]{\romannumeral\csname rmn@\if\relax\detokenize{#1}\relax + first\else second\fi oftwo\endcsname} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \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 +% +%%% \xifempty{ text }{ true }{ false } +% \fi +% \begin{Macro}{xifempty} +% |\xifempty| is based on pdf-TeX{} |\pdfstrcmp| and work with any argument. +% \begin{macrocode} +\newcommand\xifempty[1]{\xifstrcmp{#1}{}} +\ettl@onlypdfTeX\pdfstrcmp\xifempty[\xifstrempty] +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \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 +% +%%% \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 +% +%%% \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} +% +% +%\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*} +% +% +% \iffalse +% +%%% \ifstrcmp{ string1 }{ string2 }{ true }{ false } +% \fi +% +% \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 +\ettl@onlypdfTeX\pdfstrcmp\ifstrcmp[\ifstrequal] % \end{macrocode} -% \end{macro} +% \end{Macro} % % \iffalse % -%% \xifstrcmp{ string1 }{ string2 }{ true }{ false } +%%% \xifstrcmp{ string1 }{ string2 }{ true }{ false } % \fi % -% \begin{macro}{\xifstrcmp}\cmdlabel{impl:xifstrcmp} -% The macro is based on the |\pdfstrcmp| primitive.\seedesc{ifxstrcmp} +% \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\ifxstrcmp +\ettl@onlypdfTeX\pdfstrcmp\xifstrcmp[\xifstrequal] % \end{macrocode} -% \end{macro} +% \end{Macro} % -% \begin{macro}{\xifstrequal}\cmdlabel{impl:xifstrequal} -% The macro is based on \sty{etoolbox}-|\ifstrequal|.\seedesc{ifxstrequal} +% \begin{Macro}{xifstrequal} +% The macro is based on \xpackage{etoolbox}-|\ifstrequal|. % \begin{macrocode} -\newrobustcmd*\xifstrequal[2]{\begingroup +\newrobustcmd\xifstrequal[2]{\begingroup \protected@edef\@xifstrequal{\endgroup\noexpand\ifstrequal{#1}{#2}% }\@xifstrequal} % \end{macrocode} -% \end{macro} +% \end{Macro} +% +% \iffalse +% +%%% \ifcharupper{ string }{ true }{ false } +%%% \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} +\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} +% \end{Macro} +% \end{Macro*} +% +% \iffalse +% +%%% \ifuppercase{ string }{ true }{ false } +%%% \iflowercase{ string }{ true }{ false } +% \fi +% \begin{Macro}{ifuppercase} +% Compares the |\uppercase| transformation of a string with itself: +% \begin{macrocode} +\newrobustcmd\ifuppercase[1]{\uppercase{\ifstrcmp{#1}}{#1}} +% \end{macrocode} +% \end{Macro} +% +% \begin{Macro}{iflowercase} +% Compares the |\lowercase| transformation of a string with itself: +% \begin{macrocode} +\newrobustcmd\iflowercase[1]{\lowercase{\ifstrcmp{#1}}{#1}} +% \end{macrocode} +% \end{Macro} +% +% +% \iffalse +% +%%% \ifstrmatch{ pattern }{ string }{ true }{ false } +% \fi +% +% \begin{Macro}{ifstrmatch} +% The macro is base on the |\pdfmatch| primitive. +% \begin{macrocode} +\newcommand\ifstrmatch[2]{\romannumeral\csname rmn@% + \ifnum\pdfmatch{#1}{#2}=1 first\else second\fi oftwo\endcsname} +\ettl@onlypdfTeX\pdfmatch\ifstrmatch +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \ifstrdigit{ string }{ true }{ false } +% \fi +% +%\begin{Macro}{ifstrdigit} +% \cs{ifstrdigit} expands \prm{true} if \prm{string} is a single digit (without spaces): +% \begin{macrocode} +\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} +%\end{Macro} +% +% \iffalse +% +%%% \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} +%\end{Macro} % % % \iffalse % -%% \ifstrmatch{ pattern }{ true }{ false } +%%% \DeclareStringFilter[\global]{ \StringFilterMacro }{ string } % \fi % -% \begin{macro}{\ifstrmatch}\cmdlabel{impl:ifstrmatch} -% The macro is base on the |\pdfmatch| primitive.\seedesc{ifstrmatch} +%\begin{Macro}{DeclareStringFilter} +% \csbf{DeclareStringFilter} is the general contructor for purely expandable +% \textbfsf{string-filter} macros: +% \begin{macrocode} +\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} +%\end{Macro} +% +%\begin{macro}{\ettl@strfilt@dot} \FE +% Used by |\ettl@strfilt@mod| to test if a character is a dot. +% \begin{macrocode} +\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} +%\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} +\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} +%\end{macro} +% +%\begin{macro}{\ettl@strfilt} \FE +% \cs{ettl@strfilt} is the common start for the loop: +% \begin{macrocode} +\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} +%\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} +\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} +%\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\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} +%\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} +\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} -\newcommand\ifstrmatch[2]{\csname @% - \ifnum\pdfmatch{\detokenize{#1}}{\detokenize{#2}}=1 first\else second\fi - oftwo\endcsname} -\ettl@onlypdfTeX\pdfmatch\ifstrmatch +\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{macro} % -% -% \subsection{Purely expandable macros with options} +% \Subsection{Purely expandable macros with options} % % \iffalse %%---------------------------------------------------------------------------- %% Purely Expandable Macros With Options / Star Forms / Variants -%% \FE@testopt{ #1 }{ commands }{ default option } +%%% \FE@testopt{ #1 }{ commands }{ default option } % \fi -% \begin{macro}{\FE@testopt}\cmdlabel{impl:FE@testopt} -% Fully expandable |\@testopt|-like test:\seedesc{FE@testopt} +% +%\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} -\newcommand\FE@testopt[3]{\ifsinglechar [{#1}{#2#1}{#2[{#3}]{#1}}} +\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{Macro}{FE@testopt} +% Purely expandable |\@testopt|-like test: +% \begin{macrocode} +\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{Macro} % % \iffalse % -%% \FE@ifstar{ #1 } { \StarredMacro }{ \NotStarredMacro } +%%% \FE@ifstar{ #1 } { \StarredMacro }{ \NotStarredMacro } % \fi -% \begin{macro}{\FE@ifstar}\cmdlabel{impl:FE@ifstar} -% Fully expandable |\@ifstar|-like test:\seedesc{FE@ifstar} +% \begin{Macro}{FE@ifstar} +% Purely expandable |\@ifstar|-like test: % \begin{macrocode} -\newcommand\FE@ifstar[3]{\ifsinglechar *{#1}{#2}{#3{#1}}} +\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{Macro} % -% \end{macro} +% \iffalse +% +%%% \FE@charequal{ #1 } { \MacroWith= }{ \NormalMacro } % used by the string filters +% \fi +% +%\begin{macro}{\FE@ifcharequal} \FE +% This is the same as \cs{FE@ifstar} but for \CH{=} character (used in \cmdref*{DeclareStringFilter}): +% \begin{macrocode} +\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} % % \iffalse % -%% \FE@ifchar{#1}{#2}{ \SpecialFormMacro }{ \NormalMacro } +%%% \FE@ifchar{ }{ #1 }{ \SpecialFormMacro }{ \NormalMacro } % \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}{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} \newcommand\FE@ifchar[4]{\ifsinglechar{#1}{#2}{#3}{#4{#2}}} % \end{macrocode} -% \end{macro} +% \end{Macro} % +% \iffalse +% +%%% \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 % +%%% \ettl@supergobble{ p }{ q }{token_1}{token_2}...{token_p}{TOKEN_p+1}{token_p+2}...{token_p+q+1} % \fi +%\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} +\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} % -% \goodbreak % -% \begin{macro}{\DeclareCmdListParser}\cmdlabel{impl:DeclareCmdListParser} +% \Subsection{Define control sequence through groups} % -% |\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 +% +%%% \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 +%\iffalse % -%% \DeclareCmdListParser : general constructor for command-list parsers -%% \DeclareCmdListParser\ParserName{separator} -% \fi -% \begin{codecomment} -% The command-list-parser will be defined only if it is definable: +%%% \AfterAssignment{ code } +%\fi % +%\begin{Macro}{AfterAssignment} +% \cs{AfterAssignment} can be given arbitray code: % \begin{macrocode} -\newrobustcmd*\DeclareCmdListParser[2]{% - \@ifdefinable#1 - {\expandafter\etextools@defcmdparser\expandafter{#1}{#2}}} +\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} % -% 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 +% +%%% \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} -\begingroup\catcode`\&=3\catcode`\`=3 -\gdef\etextools@defcmdparser#1#2{% - \begingroup - \def\`##1`{\expandafter\noexpand\csname ##1\endcsname}% +\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} -% Now the parser definition is made inside an protected-|\edef| in order to expand control sequences names: +% \end{Macro} +% +% \Subsection{\textbackslash futuredef} +% +% \iffalse +%%---------------------------------------------------------------------------- +% +%%% \@ifchar{ single token }{ true }{ false } +% +% \fi +% +%\begin{Macro}{@ifchar} +% \cs{@ifchar} works just like \cs{@ifstar} but uses the \cmdref={character-test}. % \begin{macrocode} - \protected@edef\defineparser{\endgroup +\long\def\@ifchar#1#2{\ettl@ifnextchar #1{\@firstoftwo{#2}}} % \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} +% +% \iffalse +% +%%% \ettl@ifnextchar{ character token }{ true }{ false } +% +% \fi +% +%\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} - \long\def#1####1{\noexpand\FE@ifstar{####1} - {\`ettl@lst@opt\string#1`{}} - {\`ettl@lst@opt\string#1`\noexpandafter}}% +\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} -% 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} +% +% \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\csdef{ettl@lst@opt\string#1}####1####2{\noexpand\FE@testopt{####2} - {\`ettl@lst@@pt\string#1`{####1}}{\noexpand\do}}% +\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} -% 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}: +% \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\csdef{ettl@lst@@pt\string#1}####1[####2]####3{% - ####1\`ettl@lst\string#1`####1{####3}{####2}}% +\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} -% On the other hand, if the parser was not starred, the (mandatory) \prm{listmacro} is expanded once: +%\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} -% 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: +% \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} - \long\csdef{ettl@lst\string#1}####1####2{% - \`ettl@lst@\string#1`{####2}####1\unexpanded{#2}&}% +\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} -% In the following macro, we extract the first item from the list (before the \prm{separator} |#2|), for treatment: +%\end{macro} +%\end{macro} +% +%\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} - \long\csdef{ettl@lst@\string#1}####1####2\unexpanded{#2}####3&{% +\long\def\ettl@ifnspace#1#2/#3/#4 {#2\futurelet\@let@token#1} % \end{macrocode} -% Proceed with the first item, if not empty: +%\end{macro} +% +% \iffalse +% +%%% \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=*[...] ) +% \fi +% +% \begin{Macro}{futuredef} +% \begin{Macro*}{futuredef*} +% \begin{Macro*}{futuredef=} +% \begin{Macro*}{futuredef*=} +% This is the scanner. % \begin{macrocode} - \noexpand\ifblank{####2} - {} - {\noexpand\ettl@lst@doitem{####1}{####2}}% +\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} -% If the remainder of the list is empty then break loop, otherwise restart extracting the next, first item for treatment: +% \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} - \noexpand\ifblank{####3} - {\noexpand\ettl@listbreak} - {\`ettl@lst@\string#1`{####1}####3}&}% +\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} -% Now the definitions are ready, execute them: +% \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} - }\defineparser}% +\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} -% |\ettl@lst@doitem| apply the auxiliary command(s) (in |#1|) to the item (|#2|): -% |\ettl@listbreak| breaks the loop, removing the extra \sty{\&}: +% \cs{ettl@futuredef@space} gobbles the space token and append a space to the \textsfsl{result}. Then it loops: % \begin{macrocode} - \long\gdef\ettl@lst@doitem#1#2{#1{#2}}% - \long\gdef\ettl@listbreak#1&{}% +\long\def\ettl@futuredef@space#1#2/Ne¤t/#3#4 {\ettl@futur@def@collect#1#2/Ne¤t/{#3}{#4}{ }} % \end{macrocode} -% Leave ``catcode-group'': +% \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} -\endgroup +\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{codecomment} % \end{macro} -% \iffalse -% -% -%% \csvloop[\command]\csvListMacro -%% \csvloop*[\command]{item,item,item} -% \fi % -% \begin{macro}{\csvloop}\cmdlabel{impl:csvloop} -% Definition of |\csvloop|:\seedesc{csvloop} +%\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} -\DeclareCmdListParser\csvloop{,} +\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} +%\end{macro} % -% \begin{codecomment} -% Definition of |\listloop| (with a `\,\textbar\,' of catcode 3 -- cf.\sty{etoolbox}): +% \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} -\begingroup\catcode`\|=3 - \def\do{\DeclareCmdListParser\listloop{|}}% -\expandafter\endgroup\do +\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} -% \end{codecomment} -% -% \begin{codecomment} -% Definition of |\toksloop| (with no delimiter): +% \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} -\DeclareCmdListParser\toksloop{}% +\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} -% \end{codecomment} -% -% \iffalse -% -%% \csvtolist \ListMacro \csvListMacro -%% \csvtolist* \ListMacro {item,item,item} -% \fi -% \begin{macro}{\csvtolist}\cmdlabel{impl:csvtolist} -% This is the first application of |\csvloop|:\seedesc{csvtolist} +% \cs{ettl@futured@f@expand@nbk} is used when \cs{futuredef*} is called with a non empty optional argument: % \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}} +\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} +% \cs{ettl@futured@f@expand@bk} is used when \cs{futuredef*} is called with an empty optional argument: +% \begin{macrocode} +\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} +% \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} +\long\def\ettl@futured@f@exp@nd#1/Ne¤t/{% + #1\expandafter\futurelet\expandafter\ettl@x\expandafter\ettl@futured@f@loop} +% \end{macrocode} +% \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} +\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{macro} % % \iffalse % +%%---------------------------------------------------------------------------- % \fi % -% \begin{macro}{\tokstolist}\cmdlabel{impl:tokstolist} -% This is the first application of |\toksloop|:\seedesc{tokstolist} -% \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{}}} -% \end{macrocode} -% \end{macro} +% \Subsection{Loops and Lists Management} % +% \subsubsection{naturalloop} % % \iffalse % -%% \csvtolistadd \ListMacro \csvListMacro -%% \csvtolistadd* \ListMacro {item,item,item} +%%% \naturalloop [ auxiliary commands (default \do) ]{ n times }{ argument } % \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}{naturalloop} +% This macro uses the capability of \eTeX{} to build purely expandable loop using \cs{numexpr}: % \begin{macrocode} -\newrobustcmd*\csvtolistadd{\@ifstar - {\ettl@tolist\@ne{}\csvloop} - {\ettl@tolist\@ne\expandnext\csvloop}} +\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} -% \end{macro} +% +% \end{Macro} +% +% \subsubsection{Lists of single tokens} % % \iffalse % +%%% \ifinttokslist{ item }{ list of tokens }{ true }{ false } % \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*}{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} -\newrobustcmd*\tokstolistadd{\@ifstar{\ettl@tokstolist\@ne{}}{\ettl@tokstolist\@ne\expandnext}}% +\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}{\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} +\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} % % \iffalse % -%%\listdel\listMacro{item} -%%\listgdel\listMacro{item} -%%\listedel\listMacro{item} -%%\listxdel\listMacro{item} +%%% \gettokslistindex { item }{ list of tokens } +%%% \gettokslistcount { item }{ list of tokens } +%%% \gettokslisttoken { item }{ list of tokens } % \fi -% \begin{macro}{\listdel}\cmdlabel{impl:listdel} -% |\listdel| removes an item from a list:\seedesc{listdel} -% \begin{macrocode} -\newrobustcmd\listdel[2]{\@listdel\def{#1}{#2}}% -% \end{macrocode} -% \end{macro} % +% \begin{Macro*}{gettokslistindex} +% \begin{Macro*}{getcharlistindex} +% \begin{Macro*}{gettokslistcount} +% \begin{Macro*}{getcharlistcount} +% \begin{Macro*}{gettokslisttoken} +% \begin{Macro}{getcharlisttoken} % -% \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} -% \end{macrocode} +% \cs{gettokslistindex}\prm{item}\prm{tokenlist-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): +% \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} -\begingroup\catcode`\|=3\catcode`\&=3 +\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} -% Inside this ``catcode-group'' the definition of |\@listdel| ought to be global: +% \cs{ettl@getsinglelist} initiates the loop (we test if the list or the \prm{item} is empty first): % \begin{macrocode} -\long\gdef\@listdel#1#2#3{% +\long\def\ettl@getsinglelist#1#2{\ettl@singlelist@loop{#1}{-1}{-1}{}#2//% + \ettl@singlelist@loop\ettl@singlelist@result/End§List/} % \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: +% \cs{ettl@singlelist@loop} tests each token and update registers: % \begin{macrocode} -\begingroup - \long\def\@tempa##1|#3|##2&{##1|##2\@tempb}% +\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. % -% |\@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). +% \#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 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{macrocode} - \long\def\@tempb|##1|\@tempb##2|\@tempb{% - \ifblank{##2}{\unexpanded{##1}} -% \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): +% 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). +% +% \#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} - {\ifblank{##1}{}{\@tempx##1&}}}% +\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} -% 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}: +% Then \cs{ettl@setresult} finishes the job: % \begin{macrocode} - \long\def\@tempx##1&{\expandafter\@tempb\@tempa|##1|\@tempb|#3|&}% - \edef\@redef{\endgroup - \unexpanded{#1#2}{% ie: \def or \gdef \listmacro +\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} -% |\@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...): +% \end{Macro} +% \end{Macro*} +% \end{Macro*} +% \end{Macro*} +% \end{Macro*} +% \end{Macro*} +% +% \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 +% +%%% \DeclareCmdListParser : general constructor for command-list parsers +%%% \DeclareCmdListParser\ParserName{separator} +% \fi +% +% The command-list-parser will be defined only if it is definable: % \begin{macrocode} - \expandafter\@tempx\unexpanded\expandafter{#2}&}% +\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} -% Then just expand |\@redef| to proceed the redefinition of \prm{listmacro}: +% \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} - }\@redef}% end of \@listdel +\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} -% And ends the ``catcode-group'': +% \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} -\endgroup +\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{codecomment} -% -%\iffalse -% -% -%% \getlistindex[\indexmacro]{ \listmacro } -%% \getlistindex*[\indexmacro]{ expanded list } -% \fi -% +%\end{Macro} % -% \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: +% \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). % -% We first need to get into a group where delimiter `\,\textbar\,' and `\,\&\,' have catcode 3: +% 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} -\newcommand\getlistindex[1]{\FE@ifstar{#1} - {\ettl@getlistindex{}\unexpanded} - {\ettl@getlistindex\expandnext\unexpanded}} +\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{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}{breakloop} +% \cs{breakloop} gobbles anything until the \CH{/End§List/} delimiter: % \begin{macrocode} -\newcommand\xgetlistindex[1]{\FE@ifstar{#1} - {\ettl@getlistindex{}\@firstofone} - {\ettl@getlistindex\expandnext\@firstofone}} +\long\def\ettl@breakloop#1/End§List/{} +\let\breakloop\ettl@breakloop % \end{macrocode} -% \end{macro} +% \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} % -% Then the following macro does the job in a loop, which is fully expandable when we can use |\pdfstrcmp|: +% \iffalse +% +% +%%% \csvloop[\command]\csvListMacro +%%% \csvloop*[\command]{item,item,item} +% \fi % +% \begin{Macro*}{csvloop} +% Definition of |\csvloop|: \cs{forcsvloop} is also defined by \cmdref{DeclareCmdListParser} but is not purely expandable: +%\begin{Macro}{forcsvloop} % \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}]}} +\DeclareCmdListParser\csvloop{,} % \end{macrocode} +% \end{Macro} +%\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*}{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@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 +\begingroup\catcode`\|=3 +\DeclareCmdListParser\listloop{|}% global declaration +\endgroup % \end{macrocode} +% \end{Macro} +%\end{Macro*} +% \end{codecomment} % +% \begin{codecomment} +% \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} +\DeclareCmdListParser\toksloop{} +% \end{macrocode} +%\end{Macro} +% \end{Macro*} % \end{codecomment} % % \iffalse % -%%\getcsvlistindex{ item }{ csvlistmacro } -%%\getcsvlistindex*{ item }{ item,item,item } +%%% \forcsvloop\csvListMacro\do{...#1...} +%%% \forcsvloop*{item,item,item,...}\do{...#1...} +% \fi +% +% \iffalse +% +%%% \csvlistadd \csvListMacro { item } +%%% \csvlist(g|e|x)add \csvListMacro { item } % \fi -% \begin{macro}{\getcsvlistindex} \cmdlabel{impl:getcsvlistindex} -% \strut\seedesc{getcsvlistindex} +% +%\begin{Macro*}{csvlistadd} +%\begin{Macro*}{csvlistgadd} +%\begin{Macro*}{csvlisteadd} +%\begin{Macro}{csvlistxadd} % \begin{macrocode} -\long\gdef\getcsvlistindex#1{\FE@ifstar{#1} - {\ettl@getcsvlistindex{}\unexpanded} - {\ettl@getcsvlistindex\expandnext\unexpanded}} +\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*} +%\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). +% \iffalse +% +%%% \csvtolist [\ListMacro] \csvListMacro +%%% \csvtolist* [\ListMacro] {item,item,item} +%% Recommended use: \edef\ListMacro{\csvtolist{item,item,item}} +% \fi % +% \begin{Macro}{csvtolist} +% This is the first application of |\csvloop|: % \begin{macrocode} -\long\gdef\xgetcsvlistindex#1{\FE@ifstar{#1} - {\ettl@getcsvlistindex{}\@firstofone} - {\ettl@getcsvlistindex\expandnext\@firstofone}} +\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} % -% Then the following macro does the job in a loop, which is fully expandable when we can use |\pdfstrcmp|: +% \iffalse +% +%%% \listtocsv [\csvListMacro] \ListMacro +%%% \listtocsv* [\csvListMacro] { expanded List } +%% Recommended use: \edef\csvListMacro{\listtocsv\ListMacro} +% \fi % +%\begin{Macro}{listtocsv} +% This is the first application of |\listloop|: % \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}]}} +\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} % -% \begin{codecomment} -% The next two macros expand to the first item in a list or the remainder of the list respectively: +% \iffalse +%%% \tokstolist [\ListMacro] { \toksListMacro / token token token } +% \fi +% +% \begin{Macro}{tokstolist} +% This is the first application of |\toksloop|: % \begin{macrocode} -\long\gdef\ettl@csvlist@first@item#1,#2&{#1} -\long\gdef\ettl@csvlist@other@item#1,#2&{#2} +\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{codecomment} -% +% \end{Macro} % % \iffalse % -%%\gettokslistindex{ item }{ tokenslistmacro } -%%\gettokslistindex*{ item }{ list of tokens } +%%% \csvtolistadd \ListMacro \csvListMacro +%%% \csvtolistadd* \ListMacro {item,item,item} % \fi -% \begin{macro}{\gettokslistindex}\cmdlabel{impl:gettokslistindex} -% \strut\seedesc{gettokslistindex} +% \begin{Macro}{csvtolistadd} +% \cs{csvtolistadd} is not purely expandable: % \begin{macrocode} -\long\gdef\gettokslistindex#1{\FE@ifstar{#1} - {\ettl@gettokslistindex{}} - {\ettl@gettokslistindex\expandnext}} +\newrobustcmd*\csvtolistadd{\@ifstar{\ettl@csvtolistadd*}{\ettl@csvtolistadd{}}} +\long\def\ettl@csvtolistadd#1#2#3{\eappto#2{\csvtolist#1[]{#3}}} % \end{macrocode} -% \end{macro} +% \end{Macro} +% +% \iffalse +% +%%% \tokstolistadd \ListMacro { \toksListMacro / token token token } +% \fi % +% \begin{Macro}{tokstolistadd} +% \cs{tokstolistadd} 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}} +\newrobustcmd*\tokstolistadd{\@ifstar{\ettl@tokstolistadd*}{\ettl@tokstolistadd{}}} +\long\def\ettl@tokstolistadd#1#2#3{\eappto#2{\tokstolist#1[]{#3}}} % \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}{\ettl@RemoveInList} \cmdlabel{impl:ettl@RemoveInList} +% This is the general constructor for deletion into lists with any separator: % \begin{macrocode} -\long\gdef\ettl@tokslist@first@item#1#2&{#1} -\long\gdef\ettl@tokslist@other@item#1#2&{#2} -\endgroup% catcode group +\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{codecomment} -% -% +%\end{macro} % % \iffalse % -% -%%\getlistitem{ number }{ listmacro } -%%\getlistitem*{ number }{ listmacro } +%%% \listdel \listMacro { item } +%%% \listgdel \listMacro { item } +%%% \listedel \listMacro { item } +%%% \listxdel \listMacro { item } % \fi -% \begin{macro}{\getlistitem}\cmdlabel{impl:getlistitem} -% \strut\seedesc{getlistitem} +% +% \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} -\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 +\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*} +% \end{Macro*} % % \iffalse % -% -%% \getcsvlistitem{ number }{ csvlistmacro } -%% \getcsvlistitem*{ number }{ item,item,item,... } +%%% \csvdel \listMacro { item } +%%% \csvgdel \listMacro { item } +%%% \csvedel \listMacro { item } +%%% \csvxdel \listMacro { item } % \fi -% \begin{macro}{\getcsvlistitem}\cmdlabel{impl:getcsvlistitem} -% \strut\seedesc{getcsvlistitem} +% +% \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} -\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}} -\endgroup +\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*} +% \end{Macro*} % % \iffalse % -% -%% \gettokslistitem{ number }{ tokslistmacro } -%% \gettokslistitem*{ number }{ list of tokens } +%%% \toksdel \listMacro { item } +%%% \toksgdel \listMacro { item } +%%% \toksedel \listMacro { item } +%%% \toksxdel \listMacro { item } % \fi -% \begin{macro}{\gettokslistitem}\cmdlabel{impl:gettokslistitem} -% \strut\seedesc{gettokslistitem} +% +% \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} -\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\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*} +% \end{Macro*} % +%\iffalse +% +% +%%% \getlistindex[\indexmacro]{ \Listmacro } +%%% \getlistindex*[\indexmacro]{ expanded List } +% \fi % +% \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\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} % % \iffalse -%%---------------------------------------------------------------------------- -% -%% \collectoks{ cs-token }{ list of allowed tokens }{ commands to expand after } % +%%\getcsvlistindex [\result]{ item }{ csvlistmacro } +%%\getcsvlistindex*[\result]{ item }{ item,item,item } % \fi -% \begin{macro}{\collecttoks}\cmdlabel{impl:collecttoks} -% A simple token scanner, vectorized version of \cs{futurelet}.\seedesc{collecttoks} +% \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@ifinlist} +% \cs{ettl@ifinlist} will build a \cs{ifinlist} macro for list with a given separator. % \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} +\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 % +% +%%% \ifincsvlist{ item }{ csvlistmacro }{ true }{ false } +%%% \ifincsvlist*{ item }{ item,item,item,... }{ true }{ false } +%%% \xifincsvlist{ item }{ csvlistmacro }{ true }{ false } +%%% \xifincsvlist*{ item }{ item,item,item,... }{ true }{ false } % \fi % -% \begin{macro}{\ettl@collecttoks} +% \begin{Macro*}{ifincsvlist} +% A robust command with a star form. +% \begin{Macro}{xifincsvlist} +% The same with |\protected@edef|. % \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} +\ettl@if@inlist\ifincsvlist{,} +\ettl@xif@inlist\xifincsvlist{,} +\undef\ettl@if@inlist +\undef\ettl@xif@inlist % \end{macrocode} -% \end{macro} +% \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} % % \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: + +\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{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} + +\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} % % \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 -% Addition of \cmdref{ifnotempty}, \cmdref{iflastchar}, \cmdref{ifstrcmp}, \cmdref{ifstrmatch} +% 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{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{ }{ #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 -- cgit v1.2.3