From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/etextools/etextools.dtx | 5429 ++++++++++++++++++++++++++ 1 file changed, 5429 insertions(+) create mode 100644 macros/latex/contrib/etextools/etextools.dtx (limited to 'macros/latex/contrib/etextools/etextools.dtx') diff --git a/macros/latex/contrib/etextools/etextools.dtx b/macros/latex/contrib/etextools/etextools.dtx new file mode 100644 index 0000000000..bea51ebc63 --- /dev/null +++ b/macros/latex/contrib/etextools/etextools.dtx @@ -0,0 +1,5429 @@ +% \iffalse meta-comment +% etextools : e-TeX tools for LaTeX Users and package Writers (v.3.1415926 - 2010/12/07) +% +% 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.ins, etextools.drv +% etextools-examples.tex +% etextools.pdf and etextools-examples.pdf +% +% Unpacking: +% (a) If etextools.ins is present: +% etex etextools.ins +% (b) Without etextools.ins: +% etex etextools.dtx +% (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 +% (pdf)latex etextools-examples.tex +%<*ignore> +\begingroup + \def\x{LaTeX2e}% +\expandafter\endgroup +\ifcase 0\ifx\install y1\fi\expandafter + \ifx\csname processbatchFile\endcsname\relax\else1\fi + \ifx\fmtname\x\else 1\fi\relax +\else\csname fi\endcsname +% +%<*install> +\input docstrip.tex +\Msg{************************************************************************} +\Msg{* Installation *} +\Msg{* Package: etextools 2010/12/07 v.3.1415926 e-TeX tools for LaTeX Users and package Writers *} +\Msg{************************************************************************} + +\keepsilent +\askforoverwritefalse + +\let\MetaPrefix\relax +\preamble + +This is a generated file. + +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 + +\endpreamble +\let\MetaPrefix\DoubleperCent + +\generate{% + \file{etextools.ins}{\from{etextools.dtx}{install}}% + \file{etextools.sty}{\from{etextools.dtx}{package}}% +} +\askforoverwritefalse +\generate{% + \file{etextools.drv}{\from{etextools.dtx}{driver}}% + \file{etextools-examples.tex}{\from{etextools.dtx}{example}}% +} + +\obeyspaces +\Msg{************************************************************************} +\Msg{*} +\Msg{* To finish the installation you have to move the following *} +\Msg{* file into a directory searched by TeX: *} +\Msg{*} +\Msg{* etextools.sty *} +\Msg{*} +\Msg{* To produce the documentation run the file `etextools.dtx' *} +\Msg{* through LaTeX. *} +\Msg{*} +\Msg{* Happy TeXing! *} +\Msg{*} +\Msg{************************************************************************} + +\endbatchfile +% +%<*ignore> +\fi +% +%<*driver> +\edef\thisfile{\jobname} +\def\thisinfo{The \thispackage\ package -- an \eTeX{} package for \LaTeX{}} +\def\thisrevision{3.1415926} +\def\thisdate{20 December 2010} +\PassOptionsToPackage{hyperindex=false,pdfusetitle,colorlinks,pdfpagelabels,pdfencoding=auto}{hyperref} +\PassOptionsToPackage{svgnames}{xcolor} +%-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +\documentclass[a4paper,oneside]{ltxdockit} +\usepackage[latin1]{inputenc} +\usepackage[american]{babel} +\usepackage{bbding} +\usepackage{doc,tocloft,stmaryrd,amsmath,amssymb,xspace,graphicx,geometry} +\usepackage{fancyhdr,titlesec,relsize,framed,enumitem,embedfile,xcolor} +\let\Cross\relax +\usepackage{interfaces} +\usepackage{etoolbox,marvosym,wasysym,soul,makecell,colortbl,arydshln,numprint,bookmark} +\CodelineNumbered\CodelineIndex +\usepackage[expansion=all,protrusion=none]{microtype} +\usepackage{tabu}[2010/12/07]\tracingtabu +\csname endofdump\endcsname +\usepackage{fancyvrb} +\usepackage{umrand} +\newrobustcmd*\cmdLabel[1]{\csgdef{cmdlabel->#1}{}} +\embedfile{\thisfile.dtx} +\geometry{left=4.5cm,marginparwidth=14pt,right=1.1cm,top=3mm,headsep=3mm,bottom=3mm,footskip=8mm,includeheadfoot} +\csdef{ltd@email}#1{\href{mailto:#1}{\footnotesize\mdseries#1}} +\titlepage{% + title={The \thispackage\footnotemark 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={\FC}, + email={florent.chervet@free.fr}, + revision={\footnotesize\thisrevision}, + date={\footnotesize\thisdate}} +\hypersetup{% + 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} +% +% \fi +% +% \CheckSum{3781} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% \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} +% \DoNotIndex{\par,\providecommand,\relax,\renewcommand,\renewenvironment} +% \DoNotIndex{\stepcounter,\usecounter,\nocite,\fi} +% \DoNotIndex{\@fileswfalse,\@gobble,\@ifstar,\@unexpandable@protect} +% \DoNotIndex{\AtBeginDocument,\AtEndDocument,\begingroup,\endgroup} +% \DoNotIndex{\frenchspacing,\MessageBreak,\newif,\PackageWarningNoLine} +% \DoNotIndex{\protect,\string,\xdef,\ifx,\texttt,\@biblabel,\bibitem} +% \DoNotIndex{\z@,\wd,\wheremsg,\vrule,\voidb@x,\verb,\bibitem} +% \DoNotIndex{\FrameCommand,\MakeFramed,\FrameRestore,\hskip,\hfil,\hfill,\hsize,\hspace,\hss,\hbox,\hb@xt@,\endMakeFramed,\escapechar} +% \DoNotIndex{\do,\date,\if@tempswa,\@tempdima,\@tempboxa,\@tempswatrue,\@tempswafalse,\ifdefined,\ifhmode,\ifmmode,\cr} +% \DoNotIndex{\box,\author,\advance,\multiply,\Command,\outer,\next,\leavevmode,\kern,\title,\toks@,\trcg@where,\tt} +% \DoNotIndex{\the,\width,\star,\space,\section,\subsection,\textasteriskcentered,\textwidth} +% \DoNotIndex{\",\:,\@empty,\@for,\@gtempa,\@latex@error,\@namedef,\@nameuse,\@tempa,\@testopt,\@width,\\,\m@ne,\makeatletter,\makeatother} +% \DoNotIndex{\maketitle,\parindent,\setbox,\x,\kernel@ifnextchar} +% \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,\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,\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} +% +% \makeatletter +% \let\@begintochook \relax \let\@endtochook \relax +% \newrobustcmd*\Xspace{\ifnum\catcode`\ =10\relax\expandafter\xspace\fi} +% \newrobustcmd*\FC{{\color{copper}\usefont{T1}{fts}xn FC}} +% \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 +% \font\manual=manfnt +% \font\umranda=umranda \font\umrandasmall=umranda scaled800 +% \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} +% \newrobustcmd*\thisyear{2010} +% \renewrobustcmd\ltxsyntaxlabelfont{\spot\usefont{T1}{pcr}{b}{n}} +% \newrobustcmd\mycolorbox[1][{[rgb]{1.00,1.00,0.79}}]{\@testopt{\my@colorbox[{#1}]}{\red}} +% \def\M{\@ifstar{\M@i\@firstofone}{\M@i\meta}} +% \def\M@i#1{\@ifnextchar[^^A] +% {\M@square#1} +% {\@ifnextchar(^^A) +% {\M@paren#1} +% {\M@brace#1}}^^A +% } +% \def\M@square#1[#2]{\M@Bracket[{#1{#2}}]} +% \def\M@paren#1(#2){\M@Bracket({#1{#2}})} +% \def\M@brace#1#2{\M@Bracket\{{#1{#2}}\}} +% \def\M@Bracket#1#2#3{{\ttfamily#1#2#3}} +% \protected\long\def\my@colorbox[#1][#2]#3{\colorbox#1{#2#3}} +% \def\Underbrace#1_#2{$\underbrace{\vtop to2ex{}\hbox{#1}}_{\hbox{\footnotesize#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}}}} +% \footskip=0pt +% \pagesetup[corpus]{ +% head/rule/width=0pt, +% head/left=\@tempdima\dimexpr\hsize+\thesecwidth\relax\rmkcolor +% \hskip-\thesecwidth\rlap{\lower6pt\hbox to\@tempdima{\mydotleader\z@\hfill}}\hfill +% \small The \textcolor{black}\thispackage\ macros -- and \eTeX{} package for \LaTeX\hfill, +% foot/left/font=\color[gray]{.35}\footnotesize, +% foot/left=\vbox to\z@{\vss\rotatebox{90}{\thispackage\unskip\enspace\copyright\,\thisyear\enspace\scriptsize\lower.3ex\hbox{\NibRight}\enspace\FC}}, +% foot/left/offset=4cm, +% foot/right/offset=.5cm, +% foot/right=\pagenumberdisplay, +% } +% \pagesetup[toc]{ +% head/rule/width=0pt, +% foot/right=\pagenumberdisplay, +% } +% \pagesetup[empty]{norules, +% foot/left/font=\footnotesize, +% foot/left=\vbox to\z@{\vss\rotatebox{90}{\thispackage\unskip\enspace\copyright\,\thisyear\enspace\scriptsize\lower.3ex\hbox{\NibRight}\enspace\FC}}, +% foot/left/offset=2cm, +% } +% ^^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}}\let¤\textcurrency}{}{} +% \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} +% \def\reflink{\ifx\current@color\default@color \rmklink\else\let\current@color\reflink@color\set@color\fi}\let\reflink@color\current@color +% \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]{{\smaller[2]\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}} +% \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{\let\reflink@color\current@color +% \@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 +% ^^A \cmditem - => pas d'entrée dans la liste des commandes / laststarredcmditem et labelize +% ^^A \cmditem * => idem mais entrée dans la liste des commandes +% ^^A \cmditem => entrée dans la liste \cmditem + => idem mais couleur \spot dans la liste / lastcmditem et labelize +% ^^A \cmditem @ => pas d'impression (juste l'entrée dans la liste, avec couleur normale) +% ^^A \cmditem +[..]@ => pas d'impression (juste l'entrée dans la liste, avec couleur \spot) +% \renewrobustcmd\ltd@cmditem[1][]{\goodbreak +% \@ifchar-{\my@cmditem@starred{#1}\@gobble}%^^A \cmditem- => pas d'entrée dans la liste des fonctions +% {\@ifstar{\my@cmditem@starred{#1}\@firstofone}{\my@cmditem{#1}}}}%^^A \cmditem* => entrée dans la liste des fonctions +% \newrobustcmd*\my@cmditem@starred[3]{%^^A starred = \cmditem- ou \cmditem* +% \edef\laststarredcmditem{\ifblank{#1}{#3}{#1}}%^^A +% \edef\cmditem@end@hook{\cmditem@labelize{\ifblank{#1}{#3}{#1}}}%^^A +% #2{\expandafter\addcommand\expandafter{\laststarredcmditem}{}{#3}}%^^A +% \Org@ltd@cmditem{#3}}^^A Make bookmark anyway (no star form) +% \newrobustcmd*\my@cmditem[1]{\@ifchar+%^^A \cmditem+ => couleur \spot dans la liste des commandes +% {\bookmarksetup{color*=spot}^^A +% \@ifchar @{\my@cmd@item{#1}\spot\@gobble}{\my@cmd@item{#1}\spot\@firstofone}}%^^A \cmditem+@ => couleur \spot (dans la liste) mais pas d'impression dans le texte +% {\@ifchar @{\my@cmd@item{#1}{}\@gobble}{\my@cmd@item{#1}{}\@firstofone}}} +% \newrobustcmd*\my@cmd@item[4]{% +% \let\lastcmditem\@empty\let\laststarredcmditem\@empty +% \edef\lastcmditem{\ifblank{#1}{#4}{#1}}% +% \def\cmditem@end@hook{\cmditem@labelize{\avoidvoid[\laststarredcmditem]\lastcmditem}} +% \expandafter\addcommand\expandafter{\lastcmditem}{#2}{#4}% +% #3{\Org@ltd@cmditem{#4}}} +% \newrobustcmd\addcommand[3]{% +% \refstepcounter{command}% +% \addcontentsline{cmds}{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[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}\cmdlabel{impl:#2}}% +% {\Check@FEList{#1}\cmdlabel{impl:#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*}[2][]{% +% \expandafter\@Macro\expandafter{\@backslashchar#2}% +% \ifblank{#1}{\cmdlabel{impl:#2}}{\cmdlabel{impl:#1}}} +% {\end{macro}} +% +% \DefineVerbatimEnvironment{VerbLines}{Verbatim}{gobble=1,frame=lines,framesep=6pt,fontfamily=txtt,fontseries=b} +% \DefineVerbatimEnvironment{Verb}{Verbatim}{gobble=1} +% \DefineVerbatimEnvironment{VerbZ}{Verbatim}{gobble=1} +% \tocsetup{ +% part/skip=6pt, +% subsection/number/width=1.5em, +% subsection/number/before=\hbox to.5em\bgroup\hss, +% subsection/number/after=\egroup\hbox to1em{\hss\tinybullet\hss}, +% subsection/pagenumbers/font=\scriptsize, +% subsection/leader=\kern.4em\mydotleader[1pt]\z@\hfill, +% subsection/skip=-.7pt, +% section/skip=3pt, +% section/number/width=1.5em, +% section/font=\usekomafont{section}\large\bfseries\red, +% part/font=\usekomafont{section}\large\bfseries, +% section/number/before=\cftsecfont\hbox to.5em\bgroup\hss, +% section/number/after=\egroup\raise.2ex\hbox to1em{\hss\scriptsize\Forward\hss}, +% } +% \newlistof{command}{cmds}{} +% \renewcommand\thecommand{\arabic{command}} +% \def\Hy@currentbookmarklevel{\BKM@currentlevel} +% \newlength\thesecwidth\thesecwidth=2.2cm +% +% \sectionformat\section[hang]{ +% font=\LARGE\bfseries, +% label=\llap{\hbox to\thesecwidth{\hfil\arabic{section}\hfil\kern.4em{\spot\Forward}\kern.4em\hfil}}, +% labelsep=0pt, +% left=0pt, +% top=6pt plus4pt minus2pt, +% bottom=3pt plus2pt minus1pt, +% break=\penalty-3000, +% bookmark={color=spot}, +% } +% \newrobustcmd*\normalsubsecformat{\sectionformat\subsection[hang]{ +% font=\Large\bfseries, +% label=\llap{\hbox to\thesecwidth{\arabic{section}\textbullet\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}, +% labelsep=0pt, +% left=0pt, +% top=6pt plus4pt minus2pt, +% bottom=3pt plus2pt minus1pt, +% bookmark={color=ForestGreen,italic}, +% } +% } +% \newrobustcmd*\implementationsubsecformat{\sectionformat\subsection[hang]{ +% font=\Large\bfseries, +% label=\llap{\hbox to\thesecwidth{I\textbullet\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}, +% labelsep=0pt, +% left=0pt, +% top=6pt plus4pt minus2pt, +% bottom=3pt plus2pt minus1pt, +% } +% \sectionformat\subsubsection[hang]{ +% font=\large\bfseries, +% label=\llap{\hbox to\thesecwidth{I\textbullet\arabic{subsection}\textbullet\arabic{subsubsection}\hfil{\fecc--}\hfil}}, +% labelsep=0pt +% } +% } +% \newrobustcmd*\firstsubsecformat{\sectionformat\subsection[hang]{ +% font=\large\bfseries, +% label=\llap{\hbox to\thesecwidth{\hss\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}, +% labelsep=0pt, +% left=0pt, +% top=5pt plus2pt minus2pt, +% bottom=2pt plus1pt minus1pt, +% break=\penalty-500, +% } +% \sectionformat\section{mark=} +% } +% \firstsubsecformat +% \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}}% +% ^^A\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}}% +% ^^A\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{\|} +% \makeatother +% +% \begingroup \movepage{2cm}\vspace*{-1.2cm}\let\footnoterule\relax\skip\footins=-.3cm\footskip=0pt\enlargethispage\baselineskip +% \definecolor{reflink}{gray}{0}\makeatletter +% \newrobustcmd\corner[2][\spot\umranda]{\hbox{#1\rlap{\char'115}\char'#2}} +% \setbox\helpbox\vbox to\z@{\lineskip-1.3pt\baselineskip\lineskip +% \parshape 9 -1.5ex \z@ -3ex \z@ -4.3ex \z@ -5ex \z@ -5.6ex \z@ -5ex \z@ -4.3ex \z@ -3ex \z@ -1.5ex \z@\relax +% \noindent\rlap{\Large\leftmoon\corner[\spot\umrandasmall]{17}}\strut\linebreak +% \rlap{\Large\leftmoon}\strut\linebreak +% \rlap{\Large\leftmoon}\strut\linebreak +% \rlap{\Large\leftmoon}\strut\linebreak +% \rlap{\Large\leftmoon}\strut\linebreak +% \rlap{\Large\leftmoon}\strut\linebreak +% \rlap{\Large\leftmoon}\strut\linebreak +% \rlap{\Large\leftmoon}\strut\linebreak +% \rlap{\Large\leftmoon\corner[\spot\umrandasmall]{21}}\vss} +% \newsavebox\myb \setbox\myb\vtop to\z@{\hbox{\rlap{\lower1.9ex\hbox{\spot\umranda\char'111}}\lower17.2ex\hbox{\lower1.9ex\hbox{\spot\umranda\char'111}}}\vss} +% \setbox\helpboxx\vbox{\hbox to\z@{\hbox to\hsize{\hfil\copy\helpbox\cleaders\copy\myb\hskip14cm\reflectbox{\copy\helpbox}\hfil}\hss}\printtitlepage} +% \box\helpboxx \footnotetext {\noindent \thispackage: \CTAN{macros/latex/contrib/\thisfile}} +% +% \begingroup\makeatletter\parfillskip\z@ +% \tocsetup{ +% pagestyle=toc, +% title=\mydotleader{.5ex}\hfill\kern.5em\Large\bfseries Contents\kern.5em\mydotleader{.5ex}\hfill\kern\z@, +% title/bottom=-12pt, +% title/top=12pt, +% part/leader=\kern.4em\mydotleader{.4ex}\hfill\hbox to\z@{\mydotleader{.4ex}\hskip\@pnumwidth\kern\z@\hss}, +% subsection/skip=-.7ptplus.01fil, +% section/skip=2ptplus.01fil, +% after=\vspace*{-6pt}\leavevmode\mydotleader{0pt}\hfill\kern\z@, +% columns=2, +% multicolsep=0pt, +% bookmark={bold,text=etextools,color=black}, +% } +% \colorlet{reflink}{DarkSlateBlue}^^A\definecolor{reflink}{rgb}{0.37,0.00,0.37} +% \tableofcontents +% \endgroup +% \OnlyDescription +% +% \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 \xpackage{etoolbox} package. +% +% 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{\bfseries The main contributions of \thispackage are :}\hfill\smex\hyperref{}{Part}{ListOfCommands}{\blue see the complete list} +% \begin{itemize} +% \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 \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 \xpackage{embedfile} by H. Oberdiek.\vskip0ptplus1filll} +% +% ^^A END OF FIRST PAGE ---------------------------------------------------------------------------------------------- +% \vfil\break +% \endgroup +% +% ^^A\stop +% \begingroup \movepage{1cm}\footskip=0pt\enlargethispage{\baselineskip} +% \Section*{Introduction} +% \addcontentsline{toc}{section}{\hskip\cftsecnumwidth\texorpdfstring\dr{} Introduction} +% \renewcommand\thesubsection{\arabic{subsection}}^^A for toc +% +% \Subsection{Motivation} +% +% 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... +% +% 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} +% +% 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. +% +% 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}. +% +% {\centering +% \begin{tabu}{|>{\rred}X[-1c]|X|} \hline +% \thead{levels} & \thead{sequence to get the result} \\ \tabucline- +% $\mathbf1$ & \cs[\red]{expandnext}\M*{\cs{def}\cs{result}}\M*{\cs[\copper]{FEmacro}\mprm{arguments}} \\ \tabucline[on 1pt off1pt]- +% $\mathbf2$ & \cs[\red]{expandnext}\cs[\red]{expandnext}\M*{\cs{def}\cs{result}}\M*{\cs[\copper]{FEmacro}\mprm{arguments}} \\ \tabucline[on 1pt off1pt]- +% more & \cs[\red]{ExpandNext}\M*{\cs{def}\cs{result}}\M*{\cs[\copper]{FEmacro}\mprm{arguments}} \footnotemark \\ \tabucline- +% \end{tabu}\par} +% \footnotetext{\cs{ExpandNext} is not always enough: \cs{csvloop} for exemple requires \cs{edef} (or \cs{csname}...) to be completely expanded.} +% +% 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} +% +% The \hyperref{file:etextools-examples}{ettlex}{toc}{example file} provided with \thispackage\ illustrates the macros defined here. +% +% \Subsection{Requirements} +% +% 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 !} +% +% 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}\enlargethispage{2\baselineskip} +% \colorlet{reflink}{MidnightBlue} +% \listofsetup{cmds}{ +% command/number/width=1.5em, +% command/leader=\cftsubsecleader, +% command/font=\large\sfbf\db, +% before=, +% title/font=\vspace*{-4mm}\LARGE\bfseries, +% title=\mydotleader{.4ex}\hfill\kern.5em +% \hyperdef{Part}{ListOfCommands}{\begin{tabu}[b]{c} \thispackage\\[-1ex] List of Commands Provided\end{tabu}}^^A +% \kern.5em\mydotleader{.4ex}\hfill, +% title/bottom=12pt, +% command/skip=4pt plus.1fil, +% pagestyle=empty, +% bookmark={bold,color=blue,text=List of commands,level=0}, +% multicols/after=\aftergroup\theleader, +% twocolumns, +% } +% \def\theleader{\vspace*{-3mm}\mydotleader{-.4ex}\hfill\kern0pt} +% \listofcommand +% \clearpage +% \endgroup +% +% \part*{{\spot\blacksmiley}\hfill All User Commands\hfill{\spot\blacksmiley}} +% +% \bookmarksetup{openlevel=1} +% +% \Section{General Helper Macros} +% +% \begin{ltxsyntax} +% +% \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\FEII 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}}. +% +% \cmditem-{@swaplast}{ token1 }{ token2 }{ token3 } +% +% \CSbf{@swaplast}\FEI swaps \prm{token2} and \prm{token3} but \prm{token1} remains in first position:§ +% \hfill \cs[\red]{@swaplast}\#1\#2\#3| |\smex| |\#1\#3\#2 +% +% {\rmk \cs{@swaplast} is used in the definition of the command-list-parser defined with \cmdref{DeclareCmdListParser}.} +% +% \cmditem{@swaptwo}{ token1 }{ token2 } +% +% Just\FEI reverse the order of the \textbfsf{arguments:}\hfill \cs[\red]{@swaptwo}\#1\#2| |\smex|{|\#2|}{|\#1|}|. +% +% \CSbf{@swaptwo} keeps the curly braces around its arguments (be aware that it does not add them, however). +% +% {\rmk \cmd{@swaptwo} is used in the definition of \cmdref{gettokslistindex} and \cmdref{getcharlistindex}.} +% +% \end{ltxsyntax} +% +% \Section{Expansion control} +% +% We often want a control sequence to be expanded after its first argument. It is normally the job +% of \cs{expandafter}. With many \cs{expandafter}s it is always possible to expand once, twice, thrice +% or more, the \textbfsf{very first token that occurs after the begin-group character} delimiting the argument. +% +% \cmdref{expandnext} simplifies the syntax (without making the execution process too heavy). +% +% Now it is also possible to expand the \textsfsl{very first} token \textsfbf{infinitely}: +% this is the aim of \cmdref{ExpandNext}. +% +% \begin{ltxsyntax} +% \ClearPage* +% \cmditem+{expandaftercmds}{ code }{ control sequences } +% +% \csbf{expandafter}\FE is sometimes limited because it affects only the very next token. +% \csbf{expandaftercmds} works just like the \csbf{expandafter} primitive but may be followed by +% arbitrary \prm{code}, not only a single token. +% +% A typical example is the following code, which detokenizes the character \CH{\#{}}:§ +% \begin{VerbLines}[commandchars=!()] +% (!red\expandaftercmds{)\expandafter\@gobble\string(!red}){\csname !#\endcsname} +% \end{VerbLines} +% without duplication (|\detokenize{|\#{}|}| leads to \CH{\#{}\#{}} if catcode of \#{} is $6$) +% +% {\rmk \cs{expandaftercmds} is used in the definition of \cs{ettl@Remove} and then in +% \cmdref{listdel}, and the string-comparators declared with \cmdref{DeclareStringFilter}}. +% +% \cmditem+{expandnext}{ code }{ control sequences } +% +% \CSbf{expandnext}\FE is quite the same as \CSbf{expandaftercmds} except that the \prm{control sequences} +% are the \textbfsf{argument of} \prmb{code}, \ie they are enclosed with curly braces after expansion. +% +% Suppose you want to test if the replacement text of a macro is blank (only spaces). You will say:§§ +% \begin{VerbLines}[commandchars=!()] +% (!blue\expandafter)(!copper\ifblank)(!blue\expandafter) {\foo}{!prm(true part)}{!prm(false part)} +% !normalfont(With !cs(expandnext) you'll just have to say:) +% (!red\expandnext)(!copper\ifblank){\foo}{!prm(true part)}{!prm(false part)} +% \end{VerbLines} +% +% +% \textbfsf{\prmb{code} may be arbitrarily \TeX{} code, unlike \CSbf{expandafter},} you may say:§§ +% \begin{VerbLines}[commandchars=!()] +% (!red\expandnext{)(!copper\def\test)(!red}){\csname name\endcsname} !hfil!nsl and it is exactly: +% !mdseries\edef\test{\expandafter\noexpand\csname name\endcsname} +% !nsl and also exactly: +% !mdseries!small \expandafter\def\expandafter\test\expandafter{\csname name\endcsname} +% (!mdseries!normalfont!itshape Genauer gesagt:) \meaning\test = macro:->\name +% \end{VerbLines} +% +% \csbf{expandnext} can be used for macros with optional arguments:§§ +% \begin{VerbLines}[commandchars=$()] +% ($red expandnext{)($copper\Macro[option])($red}){$prm(argument)} +%\end{VerbLines} +% +% \csbf{expandnext} can be used to test if a purely expandable macro is expandable at once. +% (If it is not, the \cmdref{ExpandNext} macro can be used intead.) +% +% Now \csbf{expandnext} behaves like \cs{expandafter} and is cumulative: if you need two levels +% of expansions you may say:§§ +% \begin{VerbLines}[commandchars=!()] +% (!red\expandnext\expandnext)(!copper{\def\test}){\csname name\endcsname} +% !normalfont and it is exactly: +% !mdseries!small\edef\test{\expandafter\expandafter\expandafter\noexpand\csname name\endcsname} +% !normalfont and also exactly: +% !mdfs\expandafter\expandafter\expandafter\def\expandafter\expandafter\expandafter\test +% !mdfs \expandafter\expandafter\expandafter{\csname name\endcsname} +% (!mdseries!normalfont!emph(Genauer gesagt:)) \meaning\test = macro:-> !prmb(the meaning of !csbf(name)) +% \end{VerbLines} +% \cs{expandnext} is an \cs{expandafter} saver ! +% +% {\rmk +% Now observe the following game : +% \begin{tabbing} +% \qquad\= |\def\foo{foo}| \qquad \= \smex \qquad \= |\def\Foo{\foo}| \quad \= \eol \\ +% \> |\def\\FOo{\Foo}| \> \smex \> |\def\FOO{\FOo}| \> \eol \\ +% \> |\def\fool{\FOO}| +% \end{tabbing} +% 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:§ +% \qquad |\expandnext\expandnext\expandnext\expandnext\expandnext\ifblank{\fool}|} +% +% \cmditem{expandnexttwo}{ code }{ control sequences }{ control sequences } +% +% \csbf{expandnexttwo}\FE will act as \cs{expandnext} on two arguments: +% +% \qquad\cs{expandnexttwo}:\enspace\#1\#2\#3$\longrightarrow$ +% \cs{expandnext} {\textbf\{}\cs{expandnext}\{\#1\}\Underbrace{\{\#2\}}_{\scriptsize\makecellbox[c]{expanded\\\bfseries once after}}\textbf\}\Underbrace{\{\#3\}}_{\scriptsize\makecellbox[c]{expanded\\\bfseries once first}} +% +% You may easily define \cs{expandnextthree} the same way, if you need it... +% +% {\rmk \cs{expandnexttwo} is used in \cmdref{iffirstchar}.} +% +% \cmditem{ExpandAftercmds}{ code }{ control sequences } +% +% \csbf{ExpandAftercmds}\FE acts like the primitive \cs{expandafter} but:\enlargethispage{\baselineskip} +% \begin{enumerate}[label=--~] +% \item the \textslsf{very first} token in \prmb{control sequences} is \textbfsf{totally expanded} +% \item \prmb{code} may be arbitrarily code (not necessarily a single token) +% \end{enumerate} +% +% \ClearPage +% \cmditem+{ExpandNext}{ code }{ control sequences } +% +% More\FE on expansion! Suppose you have a string say "12345"\ and you wish to reverse the order of +% the letters (here, the \textit{figures}). To do that we need a macro that swaps two elements, and then +% group them in order to swap with the next in a loop: the idea is to do: +% \quad |12345|\smex swap |{21}345| \smex swap |{321}45| \smex swap |{4321}5|. +% +% \thispackage provides a tool to loop against natural integers from $1$ to $n$. \cmdref{naturalloop} +% is purely expandable and we get the result with:§ +% \begin{VerbLines}[commandchars=!(),fontseries=m] +% \def\swap!#1!#2{{!#2!#1}} +% \def\do[!#1]!#2!#3{\swap !#3} +% (!bfseries\edef\result{\naturalloop[\do]{4}{12345}} !smex macro:->54321) +% (!bfseries(!red\ExpandNext{)(!copper\def\RESULT)(!red }){\naturalloop{4}{12345}}!smex:->54321) +% \end{VerbLines} +% +% \textbfsf{\CSbf{ExpandNext} has expanded the second argument totally without the use of \CSbf{edef}!} +% +% 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{}}|§ +% will expand to: |\"cs-name"| but this (new) control sequence itself will not be expanded. +% A typical use is shown in the following code:§ +% \smex |\edef\abc{\noexpandcs{abc@\@gobblescape\controlword}}|§ +% \smex if equivalent to:\quad|\def\abc{\abc@controlword}|. +% +% {\hint|\noexpandcs| may be abbreviated f.ex. in |\"#1"| in |\edef| that take place in a group. } +% +% \cmditem{noexpandafter} +% +% |\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[Meaning of control sequences]{Meaning of control sequences -- determining their type.} +% +% \begin{ltxsyntax} +% +% \cmditem+{thefontname} +% +% \csbf{thefontname}\notFE will display (in Computer Modern font at 10 points) the name of the current font selected. +% Something like:§ +% \qquad|select font musix11 at 10.0pt| +% +% \cmditem[showcs]@{showcs \tsptb showthecs} +% \cmditem-{showcs}{ csname } +% +% \cs{showcs}\notFE does \cs{show} on the named control sequence. +% +% \cmditem-{showthecs}{ csname } +% +% \cs{showthecs}\notFE does \cs{showthe} on the named control sequence. +% +% \cmditem{meaningcs}{ csname } +% +% \cs{meaningcs}\FEII gives the \cs{meaning} of the named control sequence. However, if the control sequence is +% not defined, \cs{meaningcs} expands to |\meaning\@undefined| (\ie the word \CH{undefined}) rather than the expected |\relax|. +% +% \cmditem{strip@meaning}{ cs-token } +% \cmditem*{strip@meaningcs}{ csname } \FEII* +% +% \csbf{strip@meaning}\FEII gives the \cs{meaning} of the \prm{cs-token}: +% \begin{enumerate}[label=\roman*)~] +% \item without the prefix `\,|macro:|\#1\#2...|->|)\,` ¤ if \prm{cs-token} is a macro +% \item integrally if \prm{cs-token} is defined and is not a macro +% \item expands to an empty string if \prm{cs-token} is undefined. +% \end{enumerate} +% +% \cs{strip@meaningcs} does the same for named control sequences. +% +% \cmditem{parameters@meaning}{ cs-token } +% \cmditem*{parameters@meaningcs}{ csname } \FEII* +% +% \csbf{parameters@meaning}\FEII expands to the part of the \cs{meaning} which corresponds +% to the \textitbf{parameter string}. If a macro has no parameter, then it expands to an empty string. +% If the \prm{cs-token} or the \prm{csname} given is not a macro, it also expands to an empty string. +% +% \newcommand*\mycell{\small\makecell[c]} \newcommand*\macpf{\vb macro:} \let\theadfont=\nbf +% \hskip-1.5em\begin{tabular}{|>{\vb\cs{}}l|c|c|c|}\hline +% \multicolumn{4}{c}{\textbfbf{to summarize}} \\ \hline +% \omit & \omit & \omit & \omit \\ [.3ex] \cline{2-4} +% \multicolumn{1}{l|}{} & \thead{macro} & \thead{not macro} & \thead{undefined} \\ \hline +% meaning & \mycell{the meaning \\ \eg \macpf[\#1]\#2->\#1\#2} & \mycell{the meaning \\ \eg \cs{count21}} & \vb undefined \\ +% meaningcs & \mycell{the meaning \\ \eg \macpf[\#1]\#2->\#1\#2} & \mycell{the meaning \\ \eg \cs{count21}} & \vb undefined \\ \hdashline[1pt/1pt] +% strip@meaning & \mycell{the replacement text \\ \eg \#1\#2} & \mycell{the meaning \\ \eg\cs{count21}} & an empty string \\ +% strip@meaningcs & \mycell{the replacement text \\ \eg \#1\#2} & \mycell{the meaning \\ \eg\cs{count21}} & an empty string \\ \hdashline[1pt/1pt] +% parameters@meaning & \mycell{the parameter string \\ \eg[\#1]\#2} & an empty string & an empty string \\ +% parameters@meaningcs & \mycell{the parameter string \\ \eg[\#1]\#2} & an empty string & an empty string \\ \hline +% \end{tabular} +% \ClearPage* +% +% \cmditem{ifdefcount}{ single token }{ true }{ false } +% \cmditem*{ifdeftoks}{ single token }{ true }{ false } \FEII* +% \cmditem[ifdefskip]@{ifdefdimen\tsptb ifdefskip\tsptb ifdefmuskip} +% \cmditem-{ifdefdimen} {cs-token }{ true }{ false } \FEII* +% \cmditem-{ifdefskip}{ single token }{ true }{ false } \FEII* +% \cmditem-{ifdefmuskip}{ single token }{ true }{ false } \FEII* +% \cmditem[ifdefchar]@{ifdefchar\tsptb ifdefmathchar} +% \cmditem-{ifdefchar}{ single token }{ true }{ false } \FEII* +% \cmditem-{ifdefmathchar}{ single token }{ true }{ false } \FEII* +% +% \xpackage{etoolbox}\FEII provides \cs{ifdefmaco} to test if a given control sequence is defined as a macro. +% \thispackage provides tests for other types of tokens. +% +% Test is made by a filter on the meaning of the \prm{single token} given as argument. The test is always false +% if this \prm{single token} is an undefined control sequence. +% \iffalse +% \cs{ifdefblankspace} will expand \prm{true} if the \prm{single token} is a blank space.§ +% \cs{ifdefthechar} will expand \prm{true} is the \prm{single token} has a meaning of the form: |the character|\stform[\blue]\textellipsis§ +% \cs{ifdeftheletter} will expand \prm{true} is the \prm{single token} has a meaning of the form: |the letter|\stform[\blue]\textellipsis§ +% +% {\rmk \cs{ifdefcount} is used -- indirectly -- in the definition of \cmdref{getlistindex} and the other macros +% for getting indexes: \cmdref{getcsvlistindex} etc.} +% \fi +% \ClearPage +% +% \cmditem[avoidvoid]+@{avoidvoid \tsptb avoidvoidcs} +% \cmditem-{avoidvoid} [ replacement code ]{ cs-token / string } \FEII* +% \cmditem-{avoidvoid\stform*}[ replacement code ]{ cs-token / string } \FEII* +% +% \csbf{avoidvoid}\FEII will test the \prm{cs-token} with \cs{ifdefvoid} (from \xpackage{etoolbox}). In case +% \prm{cs-token} is void (that means: it is either undefined or has been |\let| to |\relax| or it is a parameterless macro +% with blank -- \ie empty or space -- replacement string), then \cs{avoidvoid} expands \prm{replacement code} +% (optional parameter whose default is an empty string). +% +% Otherwise, \prm{cs-token} is not void (that means: it is defined, its meaning is not |\relax| AND it is either +% a macro with parameters or a parameterless macro with a replacement string which is NOT blank) +% then \cs{avoidvoid} expands \prm{cs-token}:§§ +% \begin{VerbLines}[commandchars=$()] +% ($red\avoidvoid) {\@undefined} ($nnn will expand to an empty string) +% ($red\avoidvoid) [($copper\macro)]\relax ($nnn will expand) ($md$copper\macro) +% ($red\avoidvoid) [($copper$!$!$! string is blank)]{$spview} ($nnn will expand$vb$copper string is blank) +% ($red\avoidvoid$stform*)[($copper$!$!$! string is empty)]{$spview} ($nnn will expand $spview) +% ($red\avoidvoid) [($copper\errmessage{string must not be empty})]{some text} +% ($nnn will expand$vb some text) +% ($red\avoidvoid) [($copper\errmessage{macro is void$})]\macro +% ($nnn will expand ($vb$copper\errmessage{...}) if ($vb\macro) is void) +% \protected\def($dg\test){$spview} +% \edef($copper\result){($red\avoidvoid$stform*)($dg\test)} +% \meaning($copper\result) macro:->($dg\test) ($nnn1-expansion of ($dg\test) not empty) +% \edef($copper\result){($red\avoidvoid)[other]($dg\test)} +% \meaning($copper\result) macro:->other ($nnn1-expansion of ($dg\test) is blank) +% \end{VerbLines} +% +% \cs{avoidvoid} is based on \cs{ifblank} test, either onto \prm{string} or, if \prm{string} is in fact a +% control word (tested with \cmdref{ifiscs}) on the replacement text of this control word\footnote{if it is defined +% as a macro. Well: the test occurs on the result of \cmdref{strip@meaning} onto the control-sequence!}. If for your +% special purpose, you prefer to test if the \prm{string} (or the replacement text of \prm{cs-token}) is \textbfsf{really empty +% and not only blank}, the \stform* star-form of \cs{avoidvoid} is made for you! +% +% \cs{avoidvoid} is purely expandable and uses \cmdref{FE@ifstar} and \cmdref{FE@testopt}: +% if the mandatory argument is a \prm{string} equal to \CH{\stform[\blue]*$__{12}$} or \CH{\stform[\blue][$__{12}$}^^A] +% there will be a problem (and most probably an error). Therefore, \textbfsf{when using \csbf{avoidvoid} you are encourage to +% specify always an option, even if it is empty.} +% \ClearPage* +% \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. \enlargethispage\baselineskip +% Therefore, \textbfsf{you cannot test a \textvbbf{string} with \csbf{avoidvoidcs}!}§§ +% \begin{VerbLines}[commandchars=$()] +% ($red\avoidvoidcs){@undefined} ($nnn will expand to an empty string) +% ($red\avoidvoidcs)[\deblank]{zap@space} ($nnn will expand to $cs(zap@space)) +% \def($dg\test){This is a test} +% ($red\avoidvoidcs)[($copper\errmessage{void macro})]{test} +% ($nnn will expand) $dg\test +% ($red\avoidvoidcs)[($copper\errmessage{void macro})]{($dg\test)} +% ($nnn will expand) ($md$copper\errmessage{void macro}) +% ($nnn this is because) \csname This is a test\endcsname($nnn is not defined !) +% ($nbf Finally, clever !) +% \protected\def($dg\test){$spview} +% ($red\avoidvoidcs) [other]{test} ($nnn will expand) other ($nnn: $cs(test) is void) +% ($red\avoidvoidcs*)[other]{test} ($nnn will expand) ($dg\test) ($nnn: $cs(test) is not $cs(@empty)) +% ($red\avoidvoidcs) [other]($dg\test) ($nnn will expand) \ ($nnn: control space, which is not void) +% ($red\avoidvoidcs*)[other]($dg\test) ($nnn will expand) \ ($nnn: control space, which is not void) +%\end{VerbLines} +% +% \end{ltxsyntax} +% \ClearPage* +% +% \Section{Single tokens/single characters} +% +% A single token is either a control word (that means a caracter of category $0$ followed by caracters of category $11$) +% or a single character with a valid category code (\ie $\ne 15$ and $\ne 9$). +% +% +% \Subsection{The \cs{ifx} test and the character test} +% \cmdlabel{character-test} +% +% When dealing with single tokens, we need an \emph{equality-test} macro that expands to |\@firstoftwo| in case of +% equality and |\@secondoftwo| in case of inequality. +% +% \thispackage implements two such \textbfsf{\slshape equality-test macros}: +% +% \begin{enumerate}[label={\blue\arabic*)~}] +% \item The \csbf[\blue]{ifx} test: is the standard test for tokens:\\ +% \null¤¤\prm{tokenA} is equal to \prm{tokenB} if:¤¤ {\rred\cs{ifx}\PRM[\black]{tokenA}\PRM[\black]{tokenB}}¤ returns \textbf{true}\\ +% {\rmk* The \csbf{ifx} test is implemented in \cmdref*{ettl@ifx}.} +% \item The \textbfsf{\blue character test} is a bit more sophisticated and works as follow:§ +% \begin{enumerate}[label=\roman*)~,labelwidth=1em] +% \item if \prm{tokenA} and \prm{tokenB} have the same category code (tested with an unexpandable |\ifcat|):\\ +% \prm{tokenA} is equal to \prm{tokenB} if:¤¤ {\rred\cs{ifx}\PRM[\black]{tokenA}\PRM[\black]{tokenB}}¤ returns \textbf{true} +% \item otherwise:\\ +% \prm{tokenA} is equal to \prm{tokenB} if:¤{\rred\cs{if}\cs{noexpand}\PRM[\black]{tokenB}\cs{string}\PRM[\black]{tokenA}}\\ +% \null\hphantom{\prm{tokenA} is equal to \prm{tokenB} if:¤¤ {\rred\cs{ifx}\PRM[\black]{tokenA}\PRM[\black]{tokenB}}¤} returns \textbf{true} +% \end{enumerate}\vskip-\parskip +% {\rmk* The \textbfsf{character test} is implemented in \cmdref*{ettl@ifchar} and its behaviour may be tested with \cmdref{ifsinglechar}.} +% \end{enumerate} +% +% \Subsection.{Basic test macros} +% +% \begin{ltxsyntax} +% +% \cmditem[ifsingletoken]+@{ifsingletoken~\db\tsptb ifOneToken} +% \cmditem-{ifsingletoken}{ single token }{ code }{ true }{ false } +% +% \csbf{ifsingletoken}\FEII 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[iffirsttoken]@{iffirsttoken~\spot\tsptb iffirstchar} +% \cmditem-{iffirsttoken}{ string1 }{ string2 }{ true }{ false } +% +% \csbf{iffirsttoken}\FEII compares the very first tokens of each \prm{string}. The +% comparison is done using \csbf{ifx} and the macro is fully expandable. Neither \prm{string1} nor \prm{string2} +% is expanded before comparison. Example:§ +% \qquad|\iffirsttoken \relax{\relax\textbf{hello world}}{begins with \relax}{begins with something else}| +% +% \qquad|\iffirsttoken|\mprm{}\mprm{whatever}¤expands\prmb{true} only if \prmb{whatever} is empty. +% +% \cmditem-{iffirstchar}{ string1 }{ string2 }{ true }{ false } +% +% \csbf{iffirstchar}\FEII compares the character codes of the \textbf{first} characters of each \prm{string}. The +% comparison is \emph{catcode agnostic} and the macro is fully expandable. Neither \prm{string1} nor \prm{string2} +% is expanded before comparison. Example:§ +% \qquad|\iffirstchar *{*hello*}{begins with a star}{begins with something else}| +% +% Alternatively, you may use the \cmdref{ifstrmatch} test. +% +% \qquad|\iffirstchar|\mprm{}\mprm{whatever}¤expands\prmb{true} only if \prmb{whatever} is empty. +% +% \ClearPage +% \cmditem+{ifiscs}{ string }{ true }{ false } +% +% \csbf{ifiscs}\FEII will expand \prmb{true} only \textbfsf{if \prmb{string} is a single control word.} \prm{string} +% may be anything, including \cs{if}-conditional, even not properly closed:§§ +% \begin{VerbLines}[commandchars=!()] +% (!red\ifiscs){\MyMacro} !nnn will expand !prmb(true) +% (!red\ifiscs){x} !nnn will expand !prmb(false) !textemdash even if x is active +% (!red\ifiscs){\ifx AB C\else D\fi} !nnn will expand !prmb(false) +% (!red\ifiscs){(!blue!textvisiblespace)\else} !nnn will expand !prmb(false) +% (!red\ifiscs){\else(!blue!textvisiblespace)} !nnn will expand !prmb(true) +% (!red\ifiscs){(!blue!textvisiblespace)} !nnn will expand !prmb(false) +% (!red\ifiscs){\@sptoken} !nnn will expand !prmb(true) +% (!red\ifiscs){} !nnn will expand !prmb(false) +% (!dg!md\let\ALPHA=A) +% (!red\ifiscs){\ALPHA} !nnn will expand !prmb(true) +% \end{VerbLines} +% +% \cs{ifiscs} is an optimized form of: ``\cs{ifOneToken} AND NOT \cs{ifOneChar}''. +% +% {\rmk \cs{ifiscs} is used in the definition of the \cmdref=[DeclareCmdListParser]{command-list parsers}.} +% +% \cmditem{detokenizeChars}{ list of single tokens } +% +% \csbf{detokenizeChars}\FE will selectively detokenize the tokens in \prm{list of single tokens}. That means: single +% characters (tested with \cmdref{ifOneChar}) are detokenized while control sequences are not detokenized:§§ +% \begin{VerbLines}[commandchars=!()] +% \edef(!copper\result){(!red\detokenizeChars){!blue*+=!spview[!black]$@(!dg\relax\else);}} +% (!copper\result): !chcat*(12)!chcat+(12)!chcat=(12)!chcat(!spview)(10)!chcat$(12)!chcat@(12)(!dg\relax\else)!chcat;(12) +% \end{VerbLines} +% +% {\rmk \cs{detokenizeChars} is used in the normal form of \cmdref{futuredef}.} +% +% \cmditem{protectspace}{ code } +% +% \csbf{protectspace}\FEII will protect the spaces in \prm{code}, replacing spaces by a space surrounded by braces:§§ +% \setbox\helpbox\hbox{\texthl{\spview[\red]}} \setbox\helpboxx\hbox{\hl{\hbox{\{\spview[\red]\}}}} +% \begin{VerbLines}[commandchars=$()] +% \def($copper\test){abc$hpbox$hpbox$!$!$! def\else\relax\fi ghi$hpbox$hpbox$!$!$! j$hpbox} +% \edef($dg\result){\unexpanded\expandafter\expandafter\expandafter{% +% ($red\protectspace){($copper\test)}}} +% \meaning($dg\result): macro:->abc$hpboxx$!$!$! def\else \relax \fi ghi$hpboxx$!$!$! j$hpboxx +% \end{VerbLines} +% +% N.B.: there is no space after |\fi| in the definition of \cs[\copper]{test}... +% +% {\rmk \cs{protectspace} is used in \cmdref{detokenizeChars}.§ +% \cs{protectspace} is an example of a \textbf{recursive macro which is 2-purely expandable. }} +% +% \end{ltxsyntax} +% +% \Section{Characters and Strings} +% +% \begin{ltxsyntax} +% +% \cmditem+{ifempty}{ string }{ true }{ false } +% +% \csbf{ifempty}\FEII is similar to |\ifblank| but it test if a string is really empty +% (it shall not contain any character nor spaces). To test if the replacement +% text of a macro is empty, one may use |\ifempty| in conjunction with \cmdref{expandnext}: +% +% \begin{tabbing} +% \quad\=|\expandnext\ifempty{\macro}| \prm{true}\prm{false} +% \end{tabbing} +% +% |\ifempty| is based on |\detokenize| and accept anything in its argument. +% +% {\rmk This is NOT: |\expandafter\ifx\expandafter\relax\detokenize{\#1}\relax| !} +% +% \cmditem{xifempty}{ string or cs-token }{ true }{ false } +% +% |\xifempty|\pdfFE is similar to |\ifempty| but the argument is expanded during comparison. +% +% \begin{tabbing} +% \quad\=|\def\x{\@empty}\def\y{}| \\ +% \>|\xifempty{\x\y}| \prm{true}\prm{false}¤¤ will expand \prm{true} +% \end{tabbing} +% +% {\rmk If pdf\TeX{} is in use, the macro is based on the \cs{pdfstrcmp} primitive.} +% +% \cmditem{ifnotempty}{ string }{ true }{ false } +% +% \csbf{ifnotempty}\FEII reverses the test of |\ifempty|. +% +% +% \cmditem{xifblank}{ string }{ true }{ false } +% +% |\xifblank|\notFE\\ is similar to |\ifblank| except that the \prm{string} is first expanded +% with \cs{protected@edef}. +% +% \cmditem{ifnotblank}{ string }{ true }{ false } +% +% \csbf{ifnotblank} \FEII reverses the test of |\ifblank|. +% +% {\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+{deblank}{ string } +% +% |\deblank|\FEII removes all leading and trailing blank spaces from its argument.\medbreak +% +% 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} +% +% 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}. +% +% For more on normalisation, refer to the \Xpackage{kvsetkeys}\footnote{\xpackage{kvsetkeys}-normalisation also +% include a replacement of \CH{,} and \CH{=} to ensure that their category code are 12.} package. +% +% +% \cmditem{ifstrcmp}{ string1 }{ string2 }{ true }{ false } +% +% \csbf{ifstrcmp}\pdfFE is based on the |\pdfstrcmp| primitive (or the XeTeX-|\strcmp|) if available. Otherwise, +% |\ifstrcmp| is |\let| to \xpackage{etoolbox}-\cs{ifstrequal}. +% +% Neither \prm{string1} nor \prm{string2} is expanded during comparison. The comparison is +% \emph{catcode agnostic} (use of |\detokenize |). +% +% \cmditem{xifstrequal}{ string1 }{ string2 }{ true }{ false } +% +% |\xifstrequal|\notFE\ is the same as \xpackage{etoolbox}-|\ifstrequal| apart that each parameter string is expanded +% (with |\protected@edef|) before comparison. +% +% \cmditem{xifstrcmp}{ string1 }{ string2 }{ true }{ false } +% +% |\xifstrcmp|\pdfFE is the \LaTeX{} form of |\pdfstrcmp| primitive. If this primitive is not available, +% |\xifstrcmp| is |\let| to |\xifstrequal|. +% +% \prm{string1} and \prm{string2} are expanded during comparison. +% +% \cmditem[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|. +% +% \cmditem{ifuppercase}{ string }{ true }{ false } +% \cmditem-{iflowercase} {string }{ true }{ false } +% +% \csbf{ifuppercase}\notFE\ compares the \prm{string} with |\uppercase{|\prm{string}|}|. +% +% \csbf{iflowercase} compares the \prm{string} with |\lowercase{|\prm{string}|}|. +% +% 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} +% \quad\=\cs{ifstrmatch}\{[\textasteriskcentered]\$\}\{\prm{string}\} +% \end{tabbing} +% for example to test \CH{\textasteriskcentered} at the end of a string. +% +% \ClearPage +% \cmditem[ifstrdigit]@{ifstrmatch~\spot\tsptb ifstrnum} +% \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 is(!nbf true) if !mprm(string) is a positive integer +% \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...) +% {\sfbf\csbf{ifstrnum} is a purely expandable test to check if it is possible to expand +% \csbf{number} {\md(or \cs{romannumeral})} onto \prmb{string}} (but \cs{ifstrnum} does not expand \prm{string}.) +% +% \bigbreak +% +% \ClearPage +% \cmditem+{DeclareStringFilter}[\cs{global}]{ command-name }{ stringA } +% \newcommand\myitem[1]{\item[\hss{\stform[\rred\large]{#1}}\hss]} ^^A\newcommand*\interitem{\item[]\hskip-\leftmargin} +% +% With \csbf{DeclareStringFilter}\notFE, you will define \textbf{a purely expandable command} designed to test +% if a string: +% \begin{itemize}[labelsep=2em,leftmargin=5em] +% \myitem= is is \textbfsf{equal} to a \textsl{given} string \prm{stringA} (with possibly spaces before and after) +% \myitem{==} is \textbfsf{strictly equal} to a \textsl{given} string \prm{stringA} (no spaces allowed) +% \myitem< \textbfsf{begins with} \prm{stringA} (possibly with leading spaces) +% \myitem{<=} \textbfsf{strictly begins with} \prm{stringA} (no leading spaces allowed) +% \myitem> \textbfsf{ends with} \prm{stringA} (possibly with trailing spaces) +% \myitem{>=} \textbfsf{strictly ends with} \prm{stringA} (no trailing spaces allowed) +% \myitem? \textbfsf{contains} \prm{stringA}, and optionally how many times +% \interitem and also your \textitbf{\sffamily string-filter} will be able to +% \myitem\textendash \textbfsf{remove} \prm{stringA} from any string $0$, $1$ or more times\\ +% ¤¤(maximum = |\ettl@intmax|$ = 2^{13}-1 = $\numprint{2147483647}) +% \myitem+ \textbfsf{replace} \prm{stringA} by any other string $0$, $1$ or more times +% \myitem! \textbfsf{count} the number of occurences of \prm{stringA} in any string +% \end{itemize} +% +% {\hfill\mycolorbox{\bf Equality is \CSbf{catcode} dependent.}\hfill} +% +% You may also check that \prm{stringA} may be a blank space (but as for now, you cannot +% replace blank spaces at the end of the string...). +% \ClearPage +% \newcommand\¤[1][]{\textcolor{blue}{\bfseries{\vbbf\textvisiblespace}#1}} +% +% Let's see how this works (\¤\ is zero or more spaces):§§\enlargethispage{5\baselineskip} +% \def\YES{\textcolor{blue}{\bfseries YES}} \newcommand\bigskipneg{\vskip-8pt} +% \def\YYESS{\¤[YES]\¤} +% \def\YYES{\¤[YES]} +% \def\YESS{\textcolor{blue}{\bfseries YES}\¤} +% \let\verbatimfont\tt +% \begin{VerbLines}[commandchars=$(),fontseries=b] +% ($red\DeclareStringFilter)($copper\CompareYES){$YES} ($nnn defines $CSbf(CompareYES)) +% ($nnn$csbf(CompareYES) is the ($itbf$sffamily string-filter) for the string "$YES" $quad$smex $prm(stringA)) +% +% ($copper\CompareYES) $mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string) $nbf is "$YYESS") +% ($copper\CompareYES)($rred$large=) $mprm(string)$mprm(true)$mprm(false)($nnn is the same) +% ($copper\CompareYES)($rred$large=.)$mprm(string)$mprm(true)$mprm(false)($nnn is also the same) +% ($copper\CompareYES)($rred$large==)$mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf is "$YES") +% +% ($copper\CompareYES)($rred$large<) $mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf begins with "$YYES") +% ($copper\CompareYES)($rred$large<=)$mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf begins with "$YES") +% +% ($copper\CompareYES)($rred$large>) $mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf ends with "$YESS") +% ($copper\CompareYES)($rred$large>=)$mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf ends with "$YES") +% +% ($copper\CompareYES)($rred$large?) $mprm(string)$mprm(true)$mprm(false)($nnn expands $prm(true) if $prm(string)$nbf contains "$YES") +% ($copper\CompareYES)($rred$large?[($itbf$!$!$! n)])$mprm(string)$mprm(true)$mprm(false)$nnn expands $prm(true) if $prm(string) +% $hfill$nbf contains "$YES" more than($itbf n) times +% +% ($copper\CompareYES)($rred$large-) $mprm(string) $nbf removes all occurences $nnn of "$YES" in $prm(string) +% ($copper\CompareYES)($rred$large-[($itbf$!$!$! n)])$mprm(string) $nbf removes at most($itbf n) occurences $nnn of "$YES" +% +% ($copper\CompareYES)($rred$large+) $mprm(string)$mprm(stringB) $nbf replaces all occurences +% $hfill$nbf of "$YES" by $prm(stringB) in $prm(string) +% ($copper\CompareYES)($rred$large+[($itbf$!$!$! n)])$mprm(string)$mprm(stringB) $nbf replaces at most($it n) occurences +% $hfill$nbf of "$YES" by $prm(stringB) in $prm(string) +% ($nnn And finally:) +% ($copper\CompareYES)($rred$large!){$prm(string)} $nnn expands to($nbf the number of times "$YES") can be found in $prm(string) +% \end{VerbLines} +% +% \let\verbatimfont\verbfont +% A problem may arise if the \prm{string} to compare is the string \CH{\vbbf\blue=}, because purely expandable +% tests for modifiers don't make difference between \CH{=} and \CH{\{=\}}. To avoid this problem, +% you may say {\vbbf\red=.} or {\vbbf\red>.} or {\vbbf\red>.} instead of {\vbbf\red=}, {\vbbf\red>} and {\vbbf\red<}. +% +% All the same, you may say {\vbbf\red?.}, {\vbbf\red+.} and {\vbbf\red-.} to avoid problems if the \prm{string} is \CH{\stform[\blue][}.^^A] +% +% {\rmk \cs{CompareYES} and each of its form are purely expandable thank to \cmdref{FE@modifiers}.} +% +% You should not test a \prm{string} which contains the following sequence:§ +% \hfill\colorbox{ly}{$/__8$E$__{11}$n$__{11}$d$__{11}\S__7$S$__{11}$t$__{11}$r$__{11}$i$__{11}$n$__{11}$g$__{11}/__8$}\hfill\kern0pt\par +% +% {\rmk nor a string which contains \CH{\chcat/8} because \chcat/8 has a special meaning for \thispackage-\cmdref*{ettl@nbk}.} +% +% \end{ltxsyntax} +% +% \ClearPage* +% +% \Section{Fully expandable macros with options and modifiers} +% +% With \cs{ifblank} and \cs{ifempty} which are purely expandable macros, it becomes possible to write fully expandable +% macros with an option, \textbf{provided that this macro has at least one non-optional argument}, +% as far as we don't use |\futurelet| nor any assignment. +% +% \begin{ltxsyntax} +% +% \cmditem{FE@testopt}{\#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} +% +% \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}). +% +% Just like \cs{@testopt}, \cs{FE@testopt} is sensitive to the category code of \CH{\chcat\textasteriskcentered{12}} which must be \textvb{other}. +% +% {\rmk |\FE@testopt| is used in the definition of \cmdref{DeclareStringFilter}, \cmdref{avoidvoid}, \cmdref{ettl@supergobble} +% and \cmdref{csvtolist}.} +% +% \cmditem{FE@ifstar}{\#1}{ star-commands }{ non-star commands } +% +% 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} +% +% Just like \cs{@ifstar}, \cs{FE@ifstar} is sensitive to the category code of \stform* which must be \textvb{other}. +% +% {\rmk |\FE@ifstar| is used in the definitions of \cmdref{csvtolist}, \cmdref{listtocsv} and \cmdref{tokstolist}.} +% +% \cmditem{FE@ifchar}{ Variant Character }{\#1}{ special-commands }{ normal-commands } +% +% As a\FE generalisation of \cs{FE@ifstar} \thispackage provides \csbf{FE@ifchar} for use with other variants than the \stform*-form. +% +% 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} +% +% 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). +% +% \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... +% +% +% \ClearPage* +% \cmditem+{FE@modifiers}{ Allowed Modifiers }{\#1}{ 1st case }{ 2nd case }{...}{ Normal case } +% +% \csbf{FE@modifiers}\FE is a generalization of \cmdref{FE@ifchar} to allow different modifiers for a single macro. +% The first argument is the \prm{Allowed Modifiers} for this macro. +% +% For example, if you want to define a \textbf{purely expandable} macro with a \stform[\blue]* \textbfsf{star} form, a +% \stform[\blue]+ \textbfsf{plus} form and a \stform[\blue]{--} \textbfsf{minus} form you may say:§§ +% \begin{VerbLines}[commandchars=&()] +% \def(&copper\MySuperMacro) {(&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} +% +% \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. +% +% {\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}.} +% +% \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}$} +% +% \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} +% +% 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. +% +% Now if \PRM[\blue]{$\mathbf{n}$}$=$\PRM[\blue]{$\mathbf{N}$}, \csbf{ettl@supergobble} +% gobbles the \PRM[\blue]{$\mathbf{N}$} tokens (including the last). +% +% 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). +% +% 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$...). +% +% {\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!} +% +% \end{ltxsyntax} +% +% \ClearPage* +% +% \Section[{More options with \texorpdfstring{\cs[\sfbf]{futuredef}}{\cs{futuredef}}}]{More options with \csbf{future{\spot def}} : vectorized \csbf{future{\blue let}}: } +% +% \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} +% +% {\rmk Unless \cs{@ifstar}, \cs{@ifchar} is a |\long| macro...} +% +% \cmditem+{@char@testopt}{ code }{ single token }{ default option }{ single token } +% +% \csbf{@char@testopt}\notFE is a generalization of \LaTeX's\cs{@testopt} that may be used as follow:§§ +% \begin{VerbLines}[commandchars=!$£] +% \newcommand$!copper\SpecialMacro£{$!red\@char@testopt£\GeneralMacro({default})} +% $!nnn with£\GeneralMacro$!nnn a macro accepting optional parenthesis:£ +% \def\GeneralMacro(#1){...} +% $!nbf or:£ +% \newcommand$!copper\SpecialMacro£{$!red\@char@testopt£\GeneralMacro<{default}>} +% $!nnn with£\GeneralMacro$!nnn a macro accepting optional brackets:£ +% \def\GeneralMacro<#1>{...} +% \end{VerbLines} +% +% {\rmk NB: \cs{@char@testopt} uses \cmdref{ettl@ifnextchar} and therefore, the category code of single +% \textbf{characters} is not taken into account.} +% +% ^^A \cmditem+{@ifnextchardigit}{ true }{ false } +% ^^A +% ^^A \cs{@ifnextchardigit}\notFE\ expands \meta{true} only if the next character is a digit (\ie 0, 1, 2, 3, 4, 5, 6, 7, 8 or 9). +% +% \cmditem{ettl@ifnextchar}{ single token }{ true }{ false } +% +% \csbf{ettl@ifnextchar}\notFE\ is the engine for \csbf{@ifchar}. It is based on \cs{futurelet} and on the \cmdref={character-test}:§§ +% \begin{VerbLines}[commandchars=$()] +% $dg\begingroup \catcode`\$stform[$blue]! \active \let$stform[$blue]!=\else +% $dg\gdef ($copper\test) {($red\ettl@ifnextchar) $stform[$blue]!{true}{false\@gobble}} +% $dg\endgroup +% \catcode`\$stform[$dc]!\active \let$stform[$dc]!=\ifodd +% ($copper\test)$stform[$dc]! $nnn will expand $prmb(true) +% ($copper\test)\ifodd $nnn will expand $prmb(false) +% ($copper\test)\else $nnn will expand $prmb(false) +% \end{VerbLines} +% \bigbreak +% +% \thispackage defines a vectorized version of \cs{futurelet}. The idea is to say: +% +% \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. +% +% +% \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 } +% +% \csbf{future\spot def}\notFE\ will read the following token with \csbf{future\blue let}. 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. +% \end{ltxsyntax} +% +% 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 executes 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 \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:§ +% \csbf{futuredef}\textvbbf{[.-=]}\csbf{nexttokens}\{\prm{commands next}\} \quad it is possible to +% test the pattern given using \cs{pdfstrcmp} or \cs{ifstrequal} (or even a \cmdref[DeclareStringFilter]{string-filter}) +% and, for example, the \CSbf{switch} construction of the \xpackage{boolexpr} package: +% \begin{VerbLines}[fontseries=m] +% \switch[\pdfstrcmp{\nexttokens}]% +% \case{{..}}\hdashline[parameters]% +% \case{{--}}\hdashline[parameters]% +% \case{{==}}\hdashline[parameters]% +% \case{{.-.}}\hdashline[parameters]% +% \otherwise \original@hline% +% \endswitch +% \end{VerbLines} +% +% \CSbf{switch} is purely expandable. See \Xpackage{boolexpr} for more information on \cs{switch}. +% +% \begin{ltxsyntax} +% \cmditem[starredfuturedef]{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 } +% +% 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 executes the \prm{commands to expand after}. +% \end{ltxsyntax} +% +% 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*}.} +% +% \ClearPage* +% \Section{Define control sequences through groups} +% +% \begin{ltxsyntax} +% +% \cmditem[AfterGroup]@{AfterGroup\tsptb AfterGroup\stform*} +% \cmditem-{AfterGroup}{ code } +% \cmditem-{AfterGroup\stform*}{ code } +% +% The \cs[\red]{aftergroup}\notFE\ primitive does not allow arbitrary code: only a single token may be placed after \cs{aftergroup}. +% \csbf{AfterGroup} allows arbitrary \prm{code} to be expanded after \cs{endgroup} or an end-group character. +% +% The \stform* star form of \cs{AfterGroup} does the same, but expands its argument with |\edef|:§§ +% \begin{VerbLines}[commandchars=!()] +%!md \newcommand(!copper\macro)[1]{\textbf{Just to see...!#1}} +% (!dg\begingroup) +%!md \newcommand(!copper\othermacro)[1]{\textbf{will we see...!#1}} +% (!red\AfterGroup)!md{(!copper\macro){if it works}} +% (!red\AfterGroup*)!md{\expandonce{(!copper\othermacro){if it works}}} +% (!dg\endgroup) +% (!nnn and here) (!md(!copper\macro){if it works}) (!nnn will be executed) +% (!nnn and here) (!md\textbf{will we see...if it works}) (!nnn will be executed) +% \end{VerbLines} +% +% \cmditem{AfterAssignment}{ code } +% +% In the same order of idea,\notFE\ \csbf{AfterAssignment} allows arbitrary \prm{code} to be expanded \cs{afterassignment}. +% +% \cmditem+{aftergroup@def}{ command } +% +% When leaving\notFE\ a group with the end-group character \CH{\stform[\dg]\}} or the execution of \csbf[\dg]{endgroup} +% the meaning of the control sequences that where locally defined inside the group are restored to +% what they were before. +% +% The idea of \cs{aftergroup@def} is to keep a control sequence though \csbf[\dg]{endgroup} or \CH{\stform[\dg]\}}. +% This is done by redefining it after the group. \cs{aftergroup@def} is based on \Xpackage[oberdiek/letltxmacro]{letltxmacro} and +% on \cmdref{AfterGroup} just defined. Therefore, \cs{aftergroup@def} works with commands with optional arguments declared +% with \LaTeX's \cs{newcommand}, with robust commands from \xpackage{etoolbox}-\cs{newrobustcmd} and +% with \LaTeX's robust commands (\cs{DeclareRobustCommand}). +% +% \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} +% +% +% \end{ltxsyntax} +% +% \ClearPage* +% \Section{Lists management} +% +% \Subsection{The natural loop} +% +% \begin{ltxsyntax} +% \cmditem{naturalloop}[auxiliary commands]{ number of times }{ argument } +% +% {\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. +% +% \end{ltxsyntax} +% +% +% \Subsection{Lists of single tokens / characters} \cmdlabel{list of single tokens} +% +% Lists of single tokens are a special case of lists: they have no separator. The test for equalty of tokens +% is made by \csbf[\red]{ifx} and therefore, finding a token in a list of single tokens is always a purely expandable operation. +% +% A \textsfbf{\slshape list of single tokens} is a list of \textitbf{single} tokens: that means you can't group them with braces +% (the list may contain the |\bgroup| and |\egroup| tokens however). +% +% Lists of single tokens may also be tested with a special test which is |\ifx| in case of control sequences and +% a detokenized-|\if| in case of single characters. +% +% Lists of single characters are used for testing \textsl{modifiers} in a purely expandable way. \textsfbf{\slshape modifiers} are +% a vectorialisation of \cs{FE@ifstar} (and \cs{FE@ifchar}). +% +% \begin{ltxsyntax} +% +% \ClearPage +% \cmditem[ifintokslist]+@{ifintokslist\tsptb ifincharlist} +% \cmditem-{ifintokslist}{ single token }{ list of single tokens }{ true }{ false } \FEII* +% \cmditem-{ifincharlist}{ single token }{ list of single tokens }{ true }{ false } \FEII* +% +% \csbf{ifintokslist} will switch\FEII to \prm{true} if the \prm{single token} is found +% in the \prm{list of single tokens} while testing against each token of the list using \csbf{ifx}. +% +% {\rmk\cs{ifintokslist} could be tested with |\ifnum\getokslistindex{|\prm{token}|}{|\prm{list of tokens}|}| +% but \cs{ifintokslist} optimises the loop in case the token is in the list.} +% +% \csbf{ifincharlist} will expands \prm{true} if the \prm{single token} is found in the \prm{list of single tokens} +% but the test for equality of tokens is the \cmdref={character-test}. +% +% \end{ltxsyntax} +% \ClearPage* +% +% Therefore, \cs{ifincharlist} behaves as follow:§§ +% \begin{VerbLines}[commandchars=$()] +% \begingroup \catcode`\!=13 \catcode`\.=8 \catcode`\: 3 +% \global\def($copper\mylist){($blue:!\relax=.0)} ($nbf|) ($red\ifintokslist) +% \endgroup $nbf| +% $cs(expandnext){($red\ifincharlist)($blue!)}($copper\mylist){true}{false} $nbf true | false +% \expandnext{($red\ifincharlist)($blue0)}($copper\mylist){true}{false} $nbf true | true +% \expandnext{($red\ifincharlist)($blue:)}($copper\mylist){true}{false} $nbf true | false +% \expandnext{($red\ifincharlist)($blue\relax)}($copper\mylist){true}{false} $nbf true | true +% \end{VerbLines} +% +% {\rmk \cs{ifincharlist} is used in the definition of \cmdref{futuredef}.} +% +% \begin{ltxsyntax} +% \cmditem+{gettokslistindex}{item}{list of single tokens} +% +% \csbf{gettokslistindex}\FEII expands to the index of \prmb{item} in the list of single tokens given as a second argument. +% +% +% \textbf{Note that the \opt{index} is $\mathbf0-$based} for consistency with |\ifcase| ({\mdfs and also with +% \cmdref{ettl@supergobble}}). +% \ClearPage +% +% It is possible to say:§§\makeatletter\setbox\helpbox\hbox{\colorbox{yellow}{\vbbf 3}}\setbox\helpboxx\hbox{\colorbox{yellow}{\vbbf -1}} +% \begin{VerbLines}[commandchars=!\[\]] +% \newcount[!copper\result] +% [!copper\result] = [!red\gettokslistindex]{d}{abcdef} !smex \result=!box!helpbox +% \ifcase [!red\gettokslistindex]{d}{abcef} +% [!nnn what to do if ] a +% \or [!nnn what to do if ] b +% \or [!nnn what to do if ] c +% \or [!nnn etc. etc. etc.] +% \else [!nnn what to do if] d [!nnn is not in the list:] !smex result=!box!helpboxx +% \fi +% \end{VerbLines} +% \makeatother +% +% Please, refer to the examples... +% +% This feature is extensively used in \cmdref{FE@modifiers}. +% +% {\rmk \cmdref*{gettokslistindex} is kind of masterpiece of purely expandable programming with \eTeX} +% +% \cmditem+{getcharlistindex}{item}{list of single tokens} +% +% \csbf{getcharlistindex}\FEII expands to the index of \prmb{item} in the list of single tokens +% (the index is $\mathbf0$ for the first item, $\mathbf{-1}$ if \prm{item} is not in the list). +% The character-test is used instead of |\ifx| (see \cmdref{ifincharlist}). +% +% {\rmk \cmdref{getcharlistindex} is used - indirectly - in the definition of \cmdref{FE@modifiers}.} +% +% \ClearPage +% \cmditem[gettokslistcount] @{gettokslistcount/token} +% \cmditem-{gettokslistcount}{list of single tokens} \FEII* +% \cmditem-{gettokslisttoken}{item}{list of single tokens} \FEII* +% +% \csbf{gettokslistcount},\FEII \csbf{gettokslisttoken} and \csbf{gettokslistindex} work all three with +% the same engine, and this is also the case for \cmdref{getcharlistcount}, \cmdref{getcharlisttoken} and \cmdref{getcharlistindex}. +% All are fully expandable. +% \ClearPage +% +% \cs{gettokslistcount} gives the number of tokens in the list, while \cs{gettokslisttoken} should be seldom used (but +% it was natural to define it as well).§§ +% \begin{VerbLines}[commandchars=!(),fontseries=m] +% (!nnn if you say:) \let(!dg\plus) = !stform[!blue]+ +% (!red\gettokslisttokens){(!dg\plus)}{ABCD!stform[!blue]+EFG} (!nnn will expand to: )!stform[!blue]+ +% (!nnn and:) +% (!red\gettokslisttokens){!stform[!blue]+}{ABCD(!dg\plus) EFG} (!nnn will expand to: )!dg\plus +% \end{VerbLines} +% +% The idea is to loop into the list, testing each token of the list against \prm{item} with |\ifx|. +% The \textsl{test-macro} (together with its own parameters) is a parameter of the \textsl{loop-macro}, +% and therefore, it can be changed without redefining it. As a result, the loop is purely expandable. +% +% Finally, when the loop is finished, the test macro becomes the \textsl{give-result-macro} (without |\let|) +% and its own parameters are \textsl{extracted using projections} (like |\@firstoftwo|). +% +% The parameters of the \textsl{test-macro} include: +% \begin{enumerate}[label=--~] +% \item the current index in the list +% \item the index of the \prm{item} found if |\ifx| returned \textvb{true} +% \item the name of the \textsl{test-macro} to use at the next iteration. Usually it is the \textsl{test-macro} +% itself, but for the last token in the list, this parameter is the \textsl{give-result-macro}. +% \end{enumerate} +% +% Definition of \cmdref*{ettl@getsinglelist} 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}{ code } \FE* +% +% |\DeclareCmdListParser| acts\notFE\ 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}. \csbf{breakloop} will +% gobble anything until the end-of-list delimiter +% (\footnotesize\colorbox{ly}{$/__8$E$__{11}$n$__{11}$d$__{11}\S__7$L$__{11}$i$__{11}$s$__{11}$t$__{11}$/$__8$}) +% and will append the \textbf{mandatory} parameter \prmb{code} after. +% +% \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]*) ($nitbf may be) used when ($vbbf$copper\mylist) is already expanded.) +% ($nnn The plus form ($red$vbbf\csvloop$stform[$rred]+) ($nitbf 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($nitbf 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. +% It behaves exactly as \cmdref{csvloop} does. +% +% \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}). +% +% With \cs{toksloop} you are able to count the number of characters in a string:§§ +% \begin{VerbLines}[commandchars=$()] +% ($red\toksloop$stform[$rred]!){abcdef} $smex 6 +% \end{VerbLines} +% Spaces are not counted, however... +% \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. There is no \stform! form. +% +% \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 makes 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 conversions could be used very often and \thispackage provides a few macros to convert +% lists easily: +% +% \begin{ltxsyntax} +% \ClearPage +% +% \cmditem[csvtolist]@{csvtolist\tsptb tokstolist\tsptb listtocsv} +% \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: \itemitemitem*[{\stform[\blue],}]}. +% But expansion occurs only if this parameter is a single control word... +% \ClearPage +% +% \cmditem[tokstolist]-{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:§§ +% \newcommand\etbsep{\stform[\blue]\textbar$__3$\!\!\!} +% \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[listtocsv]-{listtocsv}[ target: csvlistmacro ]{ source: Listmacro \textsfsl{or} expanded List } +% \cmditem-{listtocsv\stform*}[ target: csvlistmacro ]{ source: Listmacro \textsfsl{or} expanded List } \FE* +% +% \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} +% +% \cmditem[csvtolistadd]@{csvtolistadd\tsptb tokstolistadd} +% \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:§§ +% \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[tokstolistadd]-{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). +% +% \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 \csbf{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. +% +% \csbf{listedel} expands the \prm{item} (with |\protected@edef|) \textsfbf{before} deletion, whilst with \csbf{listgdel} +% the final assignment to (the \emph{shortened}) \prm{Listmacro} is global. Finally, \csbf{listxdel} both expands the \prm{item} +% and makes 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)} +% ($red\listdel)[($dg\mycounter)]($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} +% ^^A\cmditem-{xgetlistindex}[result-index(counter or macro)]{item}{Listmacro} +% \cmditem-{getlistindex*}[result-index(counter or macro)]{item}{list} +% ^^A\cmditem-{xgetlistindex*}[result-index(counter or macro)]{item}{list} +% +% \end{ltxsyntax} +% +% Sometimes\notFE\ 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} +% ^^A\cmditem-{xgetcsvlistindex}[result-index(counter or macro)]{item}{csvlistmacro} +% \cmditem-{getcsvlistindex*}[result-index(counter or macro)]{item}{item,item,item,...} +% ^^A\cmditem-{xgetcsvlistindex*}[result-index(counter or macro)]{item}{item,item,item,...} +% \end{ltxsyntax} +% +% This\notFE\ 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. +% +% \subsection[\texorpdfstring\blue{}Arithmetic: lists of numbers]{Arithmetic: lists of numbers} +% +% \begin{ltxsyntax} +% \cmditem+{interval}{ number }{ sorted comma separated list of numbers } +% +% \csbf{interval}\FE will expand to the interval of \prm{number} into the \prm{sorted csv list of numbers}:§§ +% \begin{VerbLines}[commandchars=!()] +% (!red\interval){0}{3,5,12,20} (!nnn will expand to ) 0 +% (!red\interval){3}{3,5,12,20} (!nnn will expand to ) 1 +% (!red\interval){4}{3,5,12,20} (!nnn will expand to ) 1 +% (!red\interval){5}{3,5,12,20} (!nnn will expand to ) 2 +% (!red\interval){19}{3,5,12,20} (!nnn will expand to ) 3 +% (!red\interval){20}{3,5,12,20} (!nnn will expand to ) 4 +% (!red\interval){21}{3,5,12,20} (!nnn will expand to ) 4 +% \end{VerbLines} +% +% \cmditem+{locinterplin}{ number }{ sorted csv list of numbers }{ csv list of numbers } +% +% \abovedisplayskip=2pt \belowdisplayskip=2pt +% +% \csbf{locinterplin}\FE will locally and linearly interpolate the series $Y_i$ in \prm{csv list of numbers}:§ +% \hfill \csbf[\red]{locinterplin}\mprm{\dg$X$}\mprm{\dg$X_i$}\mprm{\blue$Y_i$} \hfill\null +% $$\llap{finds $i$ such that:¤¤} \dg X_i\leqslant X\leqslant X_{i+1}$$ +% and expands to the local linear interpolation $\blue Y$: +% $${\blue Y} = {\blue Y_i} + \dfrac{\dg X-X_i}{\dg X_{i+1}-X_i} \left({\blue Y_{i+1}-Y_i}\right)$$ +% +% $\dg X_i$ and $\blue Y_i$ must have the same number of elements. +% +% \end{ltxsyntax} +% +% \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 +% \renewrobustcmd\noexpand\cftsubsecfont{\footnotesize}} +% \renewcommand\thesubsection{I.\arabic{subsection}}^^A for toc +% +% \Subsection{Package identification} +% +% \begin{macrocode} +%<*package> +\NeedsTeXFormat{LaTeX2e}[1996/12/01] +\ProvidesPackage{etextools} + [2010/12/07 v3.1415926 e-TeX more useful tools for LaTeX package writers] +\csname ettl@onlyonce\endcsname\let\ettl@onlyonce\endinput +% \end{macrocode} +% +% \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$)... Moreover, catcode $4$ may have indesirable side effects if read inside \cs{halign} or \cs{valign}. +% 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{95}{11}% _ +\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 +% +%% A few helper macros +% \fi +% +%\begin{macro}{helper macros} \FE +% \begin{macrocode} +\let\ettl@ifdefined\ifdefined%\ifdefined% turn to \iffalse to test other implementation on pdfTeX +\long\def\ettl@fi#1\fi{\fi#1} +\long\def\ettl@else#1\else#2\fi{\fi#1} +\long\def\ettl@or#1\or#2\fi{\fi#1} +\def\ettl@expandaftwo{\expandafter\expandafter\expandafter} +\def\ettl@expandafthree{\expandafter\expandafter\expandafter% + \expandafter\expandafter\expandafter\expandafter} +\cslet{ettl@1of1}\@firstofone %% for internal use only +\cslet{ettl@1of2}\@firstoftwo %% for internal use only +\cslet{ettl@2of2}\@secondoftwo %% for internal use only +\long\def\rmn@firstoftwo#1#2{\z@#1} %% for romannumeral +\long\def\rmn@secondoftwo#1#2{\z@#2}%% for romannumeral +\long\def\ettl@cdr#1#2\@nil{#2} %% \@cdr should be a LONG macro +\long\def\ettl@car#1#2\@nil{#1} %% \@car should be a LONG macro +\long\csdef{ettl@1of3}#1#2#3{#1} +\long\csdef{ettl@2of3}#1#2#3{#2} +\long\csdef{ettl@3of3}#1#2#3{#3} +\long\csdef{ettl@12of3}#1#2#3{{#1}{#2}} +\long\def\ettl@carcar#1#2#3#4{#4} +\long\def\ettl@firstspace#1#2#3{\expandafter\ettl@firstsp@ce\detokenize{#1} \\{#3}{#2}//} +\long\def\ettl@firstsp@ce#1 #2\\{\ettl@nbk#1//} +\long\def\ettl@csname#1\endcsname{\fi\endcsname}%% useful to get out of \if +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ettl@char} +% \cs{ettl@char} expands to \prm{true} if its argument is a single character token. It is used in +% \cmdref*{ettl@ifnextchar}. +% \begin{macrocode} +\long\def\ettl@char#1{\csname ettl@\ifcat $\expandafter\ettl@cdr\detokenize{#1}\@nil$% + 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 +% +%%% \ettl@onlypdfTeX for internal use +% \fi +% +% \begin{macro}{\ettl@onlypdfTeX} +% This is an \textit{internal macro} used by the package: if the \prm{primitive} +% in \#1 is available (\eg \cs{pdfstrcmp}) then the \prm{command} in \#2 +% can be defined, otherwise, the \prm{command} is \cs{let} to the optional argument \#3. +% If there is no such optional argument, the \prm{command} throws an error (\eg \cs{ifstrmatch}). +% \begin{macrocode} +\def\ettl@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 +% +%%% \ettl@nbk argument to be tested//{ true }{ false }// +%% `/` has a catcode of 3 all along this package +% \fi +% +% \begin{Macro*}{ettl@nbk} +% \CSbf{ettl@nbk}\FEI is an optimized form of |\ifblank|. \TeX{} switches to the +% \prm{true} part if the expanded argument (delimited by \CH{\chcat/8\chcat/8}) is +% \txtbf[\rred]not \txtbf[\rred]blan\txtbf[\rred]k. +% +% Usage: |\ettl@nbk |\prm{string}\chcat/8\chcat/8\prm{true}\prm{false}\chcat/8\chcat/8 +% \begin{tabbing} +% \qquad\=if \prm{string} is blank:¤\=\#1=\CH/,¤`\#2=\o,¤\#3=\prm{true},¤\=\#4=\prm{false}\\ +% \>\hfil otherwise:\>\#3=\CH/,\>\#4=\prm{true}¤(and \#5=\prm{false}) +%\end{tabbing} +% \begin{macrocode} +\long\def\ettl@nbk #1#2/#3#4#5//{#4} +\long\def\ettl@nbk@else#1#2/#3#4#5//#6\else#7\fi{\fi#4} +% \end{macrocode} +% \end{Macro*} +% +%\begin{macro}{\ettl@ney} +% \cs{ettl@ney}\FEII is exactly |\ifnotempty| but with the syntax of |\ettl@nbk|: it may be used in place of |\ettl@nbk|: +% \begin{macrocode} +\long\def\ettl@ney#1//#2#3//{\romannumeral 0\csname @% + \ifcat $\detokenize{#1}$first\else second\fi oftwo\endcsname + { #2}{ #3}} +% \end{macrocode} +%\end{macro} +% +% \iffalse +% +%% The following macros are not used (here just for memory, in case of...) +% \fi +% +%\begin{macro}{\ettl@nbk@cat} \FE +% \CSbf{ettl@nbk@cat} switches to \prm{true} if \prm{string} is not blank AND if its first token has the +% same category code of \prm{tokenA}: +% +% Usage: |\ettl@nbkcat |\prm{tokenA}\prm{string}|//|\prm{same catcodes}\prm{different catcodes}|//| +% \begin{macrocode} +\long\def\ettl@nbk@cat#1#2#3/#4#5#6//{\ettl@nbk#6//% + {\ifcat#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ettl@nbk@ifx} \FE +% \CSbf{ettl@nbk@ifx} switches to \prm{true} if \prm{string} is not blank AND if its first token is +% equal to \prm{tokenA} in the sense of \cs{ifx}: +% +% USAGE: |\ettl@nbk@ifx |\prm{tokenA}\prm{string}|//|\prm{true}\prm{false}|//| +% \begin{macrocode} +\long\def\ettl@nbk@ifx#1#2#3/#4#5#6//{\ettl@nbk#6//% + {\ifx#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ettl@nbk@if} \FE +% \CSbf{ettl@nbk@if} switches to \prm{true} if \prm{string} is not blank AND if its first token is +% equal to \prm{tokenA} in the sense of \cs{if}: +% +% USAGE: |\ettl@nbk@if |\prm{tokenA}\prm{string}|//|\prm{true}\prm{false}|//| +% \begin{macrocode} +\long\def\ettl@nbk@if#1#2#3/#4#5#6//% + {\ettl@nbk#6//{\if#1#2\ettl@else#5\else\ettl@fi#6\fi}{#5}//} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ettl@nbk@IF} \FE +% More generally: |\ettl@nbk@IF[cat]|=|\ettl@nbk@ifcat|¤|\ettl@nbk@IF[x]|=|\ettl@nbk@ifx|¤|\ettl@nbk@IF[]|=|\ettl@nbk@if|: +% \begin{macrocode} +\long\def\ettl@nbk@IF[#1]#2#3#4/#5#6#7//{\ettl@nbk#7//% + {\csname if#1\endcsname\ettl@else#6\else\ettl@fi#7\fi}{#6}//} +% \end{macrocode} +%\end{macro} +% +% +%\iffalse +% +%%% \@gobblespace and The Space Token +% \fi +%\begin{Macro}{@gobblespace} +% \begin{macrocode} +\long\def\@gobblespace#1 {#1} +% \end{macrocode} +%\end{Macro} +% +% \iffalse +% +%%% \@gobblescape \cs-token +% \fi +% +% \begin{Macro}{@gobblescape} +% This sequence of commands is very often used (even in \sty{latex.ltx}). So +% it appears to be better to put it in a macro. It's aim is to reverse the +% mechanism of |\csname|...|\endcsname|: +% \begin{macrocode} +\newcommand*\@gobblescape{\romannumeral-`\q\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\expandaftercmds{#1} + {\expandafter@cmds{#3}{\expandafter#2#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} +\providecommand*\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 +% +%%% \thefontname +% \fi +% +%\begin{Macro}{thefontname} +% \begin{macrocode} +\newcommand\thefontname{\nfss@text{\expandafter\expandafter\expandafter\ettl@thefontname + \expandafter\expandafter\expandafter\meaning + \expandafter\the\expandafter\font + \expandafter\string\expandafter(% + \expandafter\string\the\font\string)}} +\ifcsname T1/cmr/m/n/10\endcsname + \letcs\ettl@thefontname{T1/cmr/m/n/10}% +\else + \font\ettl@thefontname=ecrm1000 +\fi +% \end{macrocode} +%\end{Macro} +% +% \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 +% +%%% \showthecs { csname } +% \fi +% +%\begin{Macro}{showthecs} +% \cs{showthecs} shows the value of the named register: +% \begin{macrocode} +\providecommand*\showthecs[1]{\expandafter\showthe\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} +%\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}[ifdefcount]{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*} +% +% \iffalse +% +%%% \avoidvoidcs [ replacement code ]{ cs-name } +%%% \avoidvoidcs*[ replacement code ]{ cs-name } +% \fi +% +%\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\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*} +% +% \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{\csname ettl@\ifx#1#21\else2\fi of2\endcsname} +% \end{macrocode} +% \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 +% +%%% \ifsingletoken{ tokenA }{ tokenB }{ true }{ false } +% \fi +% +%\begin{Macro}{ifsingletoken} +% \cs{ifsingletoken} is a safe \cs{ifx}-test: +% \begin{macrocode} +\newcommand\ifsingletoken[2]{\romannumeral\csname rmn@\ettl@firstspace{#2} + {\ettl@nbk#1#2//{second}{\ifcat $\detokenize{#1#2}$first\else\ifx#1#2first\else second\fi\fi}//} + {\ifcat $\detokenize\expandafter{\ettl@cdr#2\@nil}$% + \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} +% +% \iffalse +% +%%% \iffirsttoken token { string }{ true }{ false } +% \fi +%\begin{Macro}{iffirsttoken} +% \cs{iffirsttoken} tests if \#1 and \#2 begins with the same token (the \cs{ifx}-test is used): +% \begin{macrocode} +\providecommand\iffirsttoken[2]{\romannumeral\csname rmn@% + \ettl@nbk#2//% + {\ettl@nbk#1//% + {\expandnexttwo\ettl@ifx{\ettl@car#2\@nil}{\ettl@car#1\@nil}{first}{second}} + {\ifcat $\detokenize{#1}$secondoftwo\ettl@csname\fi + \ettl@firstspace{#2}{first}{second}}//}% + {\ettl@nbk#1//% + {\ifcat $\detokenize{#2}$secondoftwo\ettl@csname\fi + \ettl@firstspace{#1}{first}{second}} + {\ifcat $\detokenize{#1#2}$first\else second\fi}}//% + oftwo\endcsname} +% \end{macrocode} +%\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}{\ifcat $\detokenize{#1}$second\else first\fi}//} + {\ifcat $\detokenize\expandafter{\ettl@cdr#1\@nil}$% + 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} +\long\def\ifsinglechar#1#2{\romannumeral\csname rmn@\ettl@firstspace{#2} + {\ettl@nbk#2//{second}{\ifcat $\detokenize{#1#2}$first\else\ifx#1#2first\else second\fi\fi}//} + {\ifcat $\detokenize\expandafter{\ettl@cdr#2\@nil}$% + \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}{\ifcat $\detokenize{#1}$second\else first\fi}//} + {\ifcat $\expandafter\ettl@cdr\detokenize{#1}\@nil$% + 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}} + {\ifcat $\detokenize{#1}$secondoftwo\ettl@csname\fi + \ettl@firstspace{#2}{first}{second}}//}% + {\ettl@nbk#1//% + {\ifcat $\detokenize{#2}$secondoftwo\ettl@csname\fi + \ettl@firstspace{#1}{first}{second}} + {\ifcat $\detokenize{#1#2}$first\else second\fi}}//% + oftwo\endcsname} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \ifiscs { string }{ true }{ false } +% \fi +% +%\begin{Macro}{ifiscs} +% \cs{ifiscs}\prm{string} expands \prm{true} only if \prm{string} is a single control-word: +% \begin{macrocode} +\newcommand\ifiscs[1]{\romannumeral\csname rmn@\ettl@nbk#1//% + {\ifcat $\expandafter\ettl@cdr\detokenize{#1}\@nil$secondoftwo\ettl@csname\fi + \ifcat $\detokenize\expandafter{\ettl@cdr#1\@nil}$% + \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{\romannumeral\protectspace{\z@#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@\ifcat $\detokenize{#1}$% + 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@\ifcat $\detokenize{#1}$% + 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\ettl@deblank#1/ /} +\long\def\ettl@deblank#1 /{\ettl@deblank@i#1/} +\long\def\ettl@deblank@i#1/#2{\z@#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[\ifstrequal] +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \xifstrcmp{ string1 }{ string2 }{ true }{ false } +% \fi +% +% \begin{Macro}{xifstrcmp} +% The macro is based on the |\pdfstrcmp| primitive. +% \begin{macrocode} +\newcommand\xifstrcmp[2]{\csname @% + \ifnum\pdfstrcmp{#1}{#2}=0 first\else second\fi + oftwo\endcsname} +\ettl@onlypdfTeX\pdfstrcmp\xifstrcmp[\xifstrequal] +% \end{macrocode} +% \end{Macro} +% +% \begin{Macro}{xifstrequal} +% The macro is based on \xpackage{etoolbox}-|\ifstrequal|. +% \begin{macrocode} +\newrobustcmd\xifstrequal[2]{\begingroup + \protected@edef\@xifstrequal{\endgroup\noexpand\ifstrequal{#1}{#2}% + }\@xifstrequal} +% \end{macrocode} +% \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 +% +%%% \DeclareStringFilter[\global]{ \StringFilterMacro }{ string } +% \fi +% +%\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@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} +\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} +% +% \iffalse +%%---------------------------------------------------------------------------- +%% Purely Expandable Macros With Options / Star Forms / Variants +%%% \FE@testopt{ #1 }{ commands }{ default option } +% \fi +% +%\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} +\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//% + {\ifcat $\detokenize{#1#2}$first\else second\fi} + {second}//oftwo} +% \end{macrocode} +%\end{macro} +% +% \begin{Macro}{FE@testopt} +% Purely expandable |\@testopt|-like test: +% \begin{macrocode} +\newcommand\FE@testopt[3]{\ettl@FE@testopt#1/[/% + {#2#1}% + {#2[{#3}]{#1}}}%] +\long\def\ettl@FE@testopt#1[#2/#3#{\csname @\ifcat $\detokenize{#1#2}$% + first\else second\fi oftwo\endcsname} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \FE@ifstar{ #1 } { \StarredMacro }{ \NotStarredMacro } +% \fi +% \begin{Macro}{FE@ifstar} +% Purely expandable |\@ifstar|-like test: +% \begin{macrocode} +\newcommand\FE@ifstar[3]{\ettl@FE@ifstar#1/*/% + {#2}% + {#3{#1}}} +\long\def\ettl@FE@ifstar#1*#2/#3#{\csname @\ifcat $\detokenize{#1#2}$% + first\else second\fi oftwo\endcsname} +% \end{macrocode} +% \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} +\newcommand\FE@ifcharequal[3]{\ettl@FE@charequal#1/=/% + {#2}% + {#3{#1}}} +\long\def\ettl@FE@charequal#1=#2/#3#{\csname @\ifcat $\detokenize{#1#2}$% + first\else second\fi oftwo\endcsname} +% \end{macrocode} +%\end{macro} +% +% \iffalse +% +%%% \ettl@strfilt@dot{ #1 } { \MacroWith= }{ \NormalMacro } % used by the string filters +% \fi +% +%\begin{macro}{\ettl@ifchardot} \FE +% Used by |\ettl@strfilt@mod| to test if a character is a dot. It is used internally and is not the same +% as |\FE@ifchar.| +% \begin{macrocode} +\newcommand\ettl@ifchardot[1]{\ettl@FE@chardot#1/./} +\long\def\ettl@FE@chardot#1.#2/#3#{\csname @\ifcat $\detokenize{#1#2}$% + first\else second\fi oftwo\endcsname} +% \end{macrocode} +%\end{macro}% +% +% \iffalse +% +%%% \FE@ifchar{ }{ #1 }{ \SpecialFormMacro }{ \NormalMacro } +% \fi +% \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} +% +% \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 \@swap{{#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@supergobbleeight} 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@supergobbleeight{\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@supergobbleeight}#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} +% +% +% \Subsection{Define control sequence through groups} +% +%\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@fterGroup\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 +% +%%% \AfterAssignment{ code } +%\fi +% +%\begin{Macro}{AfterAssignment} +% \cs{AfterAssignment} can be given arbitray code: +% \begin{macrocode} +\newrobustcmd\AfterAssignment{\@ifstar{\ettl@AfterAssignment\@firstofone}{\ettl@AfterAssignment\unexpanded}} +\newrobustcmd\ettl@AfterAssignment[2]{% + \csedef{ettl@afterassignment@hook\number\numexpr\the\ettl@fter}{#1{#2}}% + \global\advance\ettl@fter\@ne + \expandafter\afterassignment\csname ettl@afterassignment@hook\the\ettl@fter\endcsname} +% \end{macrocode} +%\end{Macro} +% +%\iffalse +% +%%% \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$ calls to \cs{aftergroup} primitive.}:§§ +% \begin{macrocode} +\newrobustcmd*\aftergroup@def{\@ifstar\aftergroup@defstar\aftergroup@d@f} +\newrobustcmd*\@ftergroup@def[3]{% + \aftergroup#2\aftergroup#3\aftergroup#1% + \aftergroup\global \aftergroup\undef \aftergroup#1} +\newrobustcmd*\aftergroup@defstar[1]{% + \global\expandafter\let\csname ettl@ftergroup@def\the\numexpr\ettl@fter+1\endcsname#1% + \global\advance\ettl@fter\@ne + \expandafter\@ftergroup@def\csname ettl@ftergroup@def\the\ettl@fter\endcsname\let#1} +\newrobustcmd*\aftergroup@d@f[1]{% + \let\etex@let@primitive\let \def\let{\global\etex@let@primitive}% + \expandafter\LetLtxMacro\csname ettl@ftergroup@def\the\numexpr\ettl@fter+1\endcsname#1% + \global\advance\ettl@fter\@ne + \etex@let@primitive\let=\etex@let@primitive + \expandafter\@ftergroup@def\csname ettl@ftergroup@def\the\ettl@fter\endcsname\LetLtxMacro#1}% +\let\ettl@aftergroup@def\aftergroup@def +% \end{macrocode} +% \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} +\long\def\@ifchar#1#2{\ettl@ifnextchar #1{\@firstoftwo{#2}}} +% \end{macrocode} +%\end{Macro} +% +% \iffalse +% +%%% \@char@testopt{ code }{ single token }{ default value }{ single token } +% +% \fi +% +% \begin{Macro}{@char@testopt} +% \cs{@char@testopt} is a generalisation of \cs{@testopt} for other pairs of character than \string[ and \string] +% to pass optional parameters to macros. It is based on \cmdref{ettl@ifnextchar} and therefore on the \cmdref={character-test}. +% \begin{macrocode} +\newcommand\@char@testopt[4]{\ettl@ifnextchar#2{#1}{#1#2#3#4}} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \@ifnextchardigit{ true }{ false } +% +% \fi +% \iffalse +% \begin{Macro}{@ifnextchardigit} +% \begin{macrocode} +\newrobustcmd\@ifnextchardigit[2]{\begingroup + + \endgroup +}% \@ifnextchardigit +% \end{macrocode} +% \end{Macro} +% \fi +% +% \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 exit from |\if|...|\fi| conditionnals (even in the case where +% the macro parameter is |\else|, |\if| or |\fi|...): +% \begin{macrocode} +\newrobustcmd\ettl@ifnextchar[3]{\begingroup + \long\edef\1##1/##2/##3{##1\endgroup\unexpanded{#2}##3}% + \long\edef\2##1/##2/##3{##1\endgroup\unexpanded{#3}##3}% + \ifOneToken{#1} + {\csname ettl@\ifcat $\expandafter\ettl@cdr\detokenize{#1}\@nil$% OneChar + xifnch\else xifntk\fi\endcsname{#1}} + {\2//{}}} +% \end{macrocode} +% \end{Macro} +% +% \begin{macro}{\ettl@xifnch} +%\begin{macro}{\ettl@ifnch} +% \cs{ettl@xifnch} is used in case the token to test (first parameter of \cs{ettl@ifnextchar} is a character token. +% It gobbles the possible spaces and exits at one if a begin-group or end-group character is found: +% \begin{macrocode} +\long\def\ettl@xifnch#1{% + \ifx#1\@sptoken \def\ettl@xifnch{\ifx\@let@token\@sptoken\1\else\2\fi//{}}% + \else \def\ettl@xifnch{% + \ifx\@let@token\bgroup \2 + \else\ifx\@let@token\egroup \2 + \else\ifx\@let@token\@sptoken \ettl@ifnspace\ettl@xifnch + \else\ettl@ifnch + \fi\fi\fi/{#1}/{}}% + \fi\futurelet\@let@token\ettl@xifnch} +% \end{macrocode} +% \cs{ettl@ifnch} does the final comparison: the token is taken into the macro parameter +% to check if it is a single character (it was not possible to ensure this point for active characters that +% have been |\let| to something, unless by eating it in the parameter of a macro. It the test fails, +% the parameters is appended again to the input): +% \begin{macrocode} +\long\def\ettl@ifnch#1/#2/#3{#1\long\def\ettl@ifnch##1{\ettl@char{##1} + {\if\string##1\string#2\1\else\2\fi}\2//{##1}}\ettl@ifnch} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\ettl@xifntk} +%\begin{macro}{\ettl@ifntk} +% \cs{ettl@xifntk} is quite the same as \cs{ettl@xifnch} but for the case the token to test (\ie the first parameter +% of \cs{ettl@ifnextchar} is a control sequence: +% \begin{macrocode} +\long\def\ettl@xifntk#1{% + \ifx#1\bgroup\def\ettl@xifntk{\ifx\@let@token\bgroup\1\else\2\fi//{}}% + \else\ifx#1\egroup\def\ettl@xifntk{\ifx\@let@token\egroup\1\else\2\fi//{}}% + \else\def\ettl@xifntk{% + \ifx\@let@token\bgroup \2 + \else\ifx\@let@token\egroup \2 + \else\ifx\@let@token\@sptoken \ettl@ifnspace\ettl@xifntk% + \else\ettl@ifntk% + \fi\fi\fi/{#1}/{}}% + \fi\futurelet\@let@token\ettl@xifntk} +% \end{macrocode} +% \cs{ettl@ifntk} finishes the job. We need to ensure that |\@let@token| is not an active character having been +% let to the token to test: there is no such thing as an active character for \cs{ettl@ifnextchar}! +% \begin{macrocode} +\long\def\ettl@ifntk#1/#2/#3{#1\long\def\ettl@ifntk##1{\ettl@char{##1} + \2{\ifx##1#2\1\else\2\fi}//{##1}}\ettl@ifntk} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{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\def\ettl@ifnspace#1#2/#3/#4 {#2\futurelet\@let@token#1} +% \end{macrocode} +%\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} +\newrobustcmd*\futuredef{\begingroup\ettl@futdef\ettl@futuredef\detokenize} +\protected\def\ettl@futdef#1#2{\@ifstar% + {\ettl@futdef\ettl@futured@f#2} + {\@ifchar={\ettl@futdef#1\unexpanded} + {\@testopt{\ettl@futur@def#1#2}{}}}} +\long\def\ettl@futur@def#1#2[#3]{% + \csname ettl@\ifcat $\detokenize{#3}$1\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} +% \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} +\long\def\ettl@futuredef#1#2#3#4{% #1=detokenize #2=list, #3=macro result, #4=code-next + \def \ettl@futuredef@loop{\ettl@futuredef@test{}}% + \long \def \ettl@futuredef@test##1{% + \ifcat\noexpand\ettl@x\bgroup\ettl@futuredef@end{}\else + \ifcat\noexpand\ettl@x\egroup\ettl@futuredef@end{}\else + \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futuredef@space#1\else + \ettl@futur@def@collect#1\fi\fi\fi/Ne¤t/{#2}{##1}}% + \long \def \ettl@futuredef@end##1##2/Ne¤t/##3##4{##2\endgroup\def#3{##4}#4##1}% + \futurelet \ettl@x \ettl@futuredef@loop} +% \end{macrocode} +% \cs{ettl@futuredef@collect} captures the next token (because it was found in the list) and selectively +% append it to the \textsfsl{result} (the argument of \cs{ettl@futuredef@test}). Then it loops: +% \begin{macrocode} +\long\def\ettl@futuredef@collect#1#2/Ne¤t/#3#4#5{#2% + \ifcat\noexpand#5\relax \ettl@futuredef@filt\unexpanded + \else \ettl@futuredef@filt#1 + \fi{#5}{#3} + {\def\ettl@futuredef@loop{\ettl@futuredef@test{#4#5}}\futurelet\ettl@x\ettl@futuredef@loop} + {\ettl@futuredef@end{#5}/Ne¤t/{}{#4}}/Ne¤t/} +% \end{macrocode} +% \cs{ettl@futuredef@space} gobbles the space token and append a space to the \textsfsl{result}. Then it loops: +% \begin{macrocode} +\long\def\ettl@futuredef@space#1#2/Ne¤t/#3#4 {% + \ettl@futur@def@collect#1#2/Ne¤t/{#3}{#4}{ }} +% \end{macrocode} +% \cs{ettl@futuredef@collectall} is used when no option (no \prm{list of allowed tokens}) has been given to \cs{futuredef}. +% In this case, \cs{futuredef} will stop only at the next begin-group or end-group token: +% \begin{macrocode} +\long\def\ettl@futuredef@collectall#1#2/Ne¤t/#3#4#5{#2% + \def\ettl@futuredef@loop{\ettl@futuredef@test{#4#5}}\futurelet\ettl@x\ettl@futuredef@loop} +% \end{macrocode} +% \end{macro} +% +%\begin{macro}{\ettl@futur@def@filt} +% \cs{ettl@futur@def@filt} defines the \textslsf{filter macro} to check if the token is in the \prm{list of allowed tokens}: +% \begin{macrocode} +\long\def\ettl@futur@def@filt#1#2{% #1=token to check, #2=allowed list + \long\def\ettl@futdef@filt##1#1##2##3/##4##5##6/Ne¤t/{##5}% + \ettl@futdef@filt#2#1//} +\long\def\ettl@futuredef@filt#1#2\fi#3#4{\fi % #1=detokenize/unexpanded, #2=discard, #3=token,#4=allowed list + \expandafter\ettl@futur@def@filt\expandafter{#1{#3}}{#4}} +% \end{macrocode} +%\end{macro} +% +% \begin{macro}{futured@f (starred)} \cmdlabel{impl:starredfuturedef} +% \cs{ettl@futured@f} defines the \textsfsl{test-macro} (which is entitled to break the loop) and the \textsfsl{loop-macro}: +% \begin{macrocode} +\long\def\ettl@futured@f#1#2#3#4{% #1=detokenize #2=list, #3=macro result, #4=code-next + \let \ettl@y \@undefined + \def \ettl@futured@f@loop{\ettl@futured@f@test{}}% + \long \def \ettl@futured@f@test##1{% + \ifcat\noexpand\ettl@x\bgroup\ettl@futured@f@end\else + \ifcat\noexpand\ettl@x\egroup\ettl@futured@f@end\else + \ifcat\noexpand\ettl@x\ettl@sptoken\ettl@futured@f@space#1\else + \ettl@futur@def@collect#1\fi\fi\fi/Ne¤t/{##1}{#2}{}}% + \long \def \ettl@futured@f@end##1/Ne¤t/##2##3##4{##1\endgroup\def#3{##2}#4##4}% + \futurelet \ettl@x \ettl@futured@f@loop} +\long\def\ettl@futured@f@space#1#2/Ne¤t/#3#4#5 {% + \ettl@futur@def@collect#1#2/Ne¤t/{#3}{#4}{#5}{ }} +% \end{macrocode} +% \cs{ettl@futured@f@collect} collects the next token which is appended to the argument of \cs{ettl@futured@f@test} (the \textsfsl{result}) +% if it is in the \prm{list of allowed tokens}, otherwise expansion is tried: +% \begin{macrocode} +\long\def\ettl@futured@f@collect#1#2/Ne¤t/#3#4#5#6{#2% + \ifcat\noexpand\ettl@x\relax \ettl@futuredef@filt\unexpanded + \else \ettl@futuredef@filt#1 + \fi{#6}{#4} + {\let \ettl@y \@undefined \ettl@futured@f@append/Ne¤t/{#3}{}{#6}}% + {\ettl@futured@f@try@expand{#3}\ettl@futured@f@end{#6}}/Ne¤t/} +% \end{macrocode} +% \cs{ettl@futured@f@collectall} is used when \cs{futuredef*} is called with an empty optional argument: +% \begin{macrocode} +\long\def\ettl@futured@f@collectall#1#2/Ne¤t/#3#4#5#6{#2% + \ettl@futured@f@try@expand{#3}\ettl@futured@f@append{#6}} +% \end{macrocode} +% \cs{ettl@futured@f@space} is used in case the token is a space token: +% \begin{macrocode} +\long\def\ettl@futured@f@space#1#2/Ne¤t/#3#4#5 {% + \ettl@futur@def@collect#1#2/Ne¤t/{#3}{#4}{#5}{ }} +% \end{macrocode} +% \cs{ettl@futured@f@try@expand} checks if the token shall be expanded, or if the loop shall be broken (in case the +% \prm{list of allowed tokens} is specified) or if this token shall be appended to the result +% (in case the \prm{list of allowed token} is empty): +% \begin{macrocode} +\long\def\ettl@futured@f@try@expand#1#2#3{% + \expandafter\ifx\noexpand\ettl@x\ettl@x + \let\ettl@y=#2% + \else\ettl@futured@f@CheckSpecials{#3}% + {\let \ettl@y=#2}% + {\ifx\ettl@x\ettl@y \let \ettl@y \ettl@futured@f@end\else + \let \ettl@y \ettl@futured@f@expand\fi}% + \fi\ettl@y/Ne¤t/{#1}{}{#3}} +% \end{macrocode} +% \cs{ettl@futured@f@expand} expands the next token because it is not in the list and +% goes back to the loop: +% \begin{macrocode} +\long\def\ettl@futured@f@expand/Ne¤t/#1#2#3{\let\ettl@y\ettl@x + \expandafter\futurelet\expandafter\ettl@x\expandafter\ettl@futured@f@loop#3} +% \end{macrocode} +% \cs{ettl@futured@f@CheckSpecials} checks if the token is undefined or a |\if|... or |\else| etc. This is compulsory +% because we do not have to attempt expansion of such tokens (unless we want to get an error from \TeX): +% \begin{macrocode} +\long\def\ettl@futured@f@CheckSpecials#1{\ifintokslist{#1}{% + \@undefined\if\ifcat\ifnum\ifdim\ifodd% + \ifvmode\ifhmode\ifmmode\ifinner\ifvoid\ifhbox\ifvbox% + \ifx\ifeof\iftrue\iffalse\ifcase\ifdefined\ifcsname\iffontchar% + \else\fi\or}} +% \end{macrocode} +% Finally, \cs{ettl@futured@f@append} appends the token to the result and goes back to the loop: +% \begin{macrocode} +\def\ettl@futured@f@append/Ne¤t/#1#2#3{% + \def\ettl@futured@f@loop{\ettl@futured@f@test{#1#3}}% + \futurelet\ettl@x\ettl@futured@f@loop}% +% \end{macrocode} +% \end{macro} +% +% \iffalse +% +%%---------------------------------------------------------------------------- +% \fi +% +% \Subsection{Loops and Lists Management} +% +% \subsubsection{naturalloop} +% +% \iffalse +% +%%% \naturalloop [ auxiliary commands (default \do) ]{ n times }{ argument } +% \fi +% +% \begin{Macro}{naturalloop} +% This macro uses the capability of \eTeX{} to build purely expandable loop using \cs{numexpr}: +% \begin{macrocode} +\newcommand\naturalloop[1]{\FE@testopt{#1}\ettl@naturalloop{\do}} +\def\ettl@naturalloop[#1]#2#3{% + \ifnum\numexpr#2>0 \expandafter\@swaparg\expandafter{\romannumeral-`\q#1[0]{#3}{#3}}% + {\ettl@naturall@@p[{#1}]{#2-1}{0}{#3}} +% \ExpandNext{\ettl@naturall@@p[{#1}]{#2-1}{1}{#3}}{#1[1]{#3}{#3}}% + \else\@swap{\unexpanded{#3}}% + \fi} +\def\ettl@naturall@@p[#1]#2#3#4#5#6\fi{\fi% + \ifnum\numexpr#2>0 \expandafter\@swaparg\expandafter{\romannumeral-`\q% + \expandafter\@swap\expandafter{\expandafter[\number\numexpr#3+1]}{#1}{#4}{#5}}% + {\ettl@naturall@@p[{#1}]{#2-1}{#3+1}{#4}}% + \else\@swap{\unexpanded{#5}}% + \fi} +% \end{macrocode} +% +% \end{Macro} +% +% \subsubsection{Lists of single tokens} +% +% \iffalse +% +%%% \ifinttokslist{ item }{ list of tokens }{ true }{ false } +% \fi +% +%\begin{Macro*}{ifintokslist} \FE +% \cs{ifintokslist}\prm{token}\prm{list of single tokens} breaks the loop at once when \prm{token} +% is found in the list. The test for the end of the list is made by \cs{ettl@nbk}... of course: +%\begin{Macro}{ifincharlist} +% \cs{ifincharlist}\prm{character or token}\prm{list of single characters or tokens} is the same, with a +% different test macro: \cs{ettl@ifchar} is used instead of \cs{ettl@ifx}: +% \begin{macrocode} +\newcommand\ifintokslist[2]{\romannumeral\csname rmn@% + \expandafter\ettl@nbk\romannumeral\ettl@dosinglelist{\ettl@ifintokslist{#1}}{#2}\z@//% + {first}{second}//oftwo\endcsname} +\long\def\ettl@ifintokslist#1#2{\ifx#1#2\ettl@breakloop\z@\fi} +\newcommand\ifincharlist[2]{\romannumeral\csname rmn@% + \expandafter\ettl@nbk\romannumeral\ettl@dosinglelist{\ettl@ifincharlist{#1}}{#2}\z@//% + {first}{second}//oftwo\endcsname} +\long\def\ettl@ifincharlist#1#2{\ettl@ifchar{#1}{#2}{\ettl@breakloop\z@}{}} +% \end{macrocode} +%\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 +% +%%% \gettokslistindex { item }{ list of tokens } +%%% \gettokslistcount { item }{ list of tokens } +%%% \gettokslisttoken { item }{ list of tokens } +% \fi +% +% \begin{Macro*}{gettokslistindex} +% \begin{Macro*}{getcharlistindex} +% \begin{Macro*}{gettokslistcount} +% \begin{Macro*}{getcharlistcount} +% \begin{Macro*}{gettokslisttoken} +% \begin{Macro}{getcharlisttoken} +% +% \cs{gettokslistindex}\prm{item}\prm{tokenlist-macro} +% +% \cs{gettokslistindex} is always purely expandable (|\ifx| test). +% +% The following three macros are the \textsl{entry points}. +% \cs{ExpandAftercmds} is applied to \cs{ettl@getsinglelist} which initiates the loop: we ask for total expansion. +% After expansion, \cs{ettl@setresult} will extract the wanted register by projection: +% The result comes from in the first +% register for \textvb{count}, the second for \textvb{index} and the third for \textvb{token}, therefore, we use the +% \cs{ettl@XofY} macros: +% \begin{macrocode} +\newcommand\gettokslistindex[2]{\number\ifnotempty{#2}{\ettl@nbk#1//% + {\ExpandAftercmds{\ettl@setresult 2of3><}{\ettl@getsinglelist{\ettl@ifx{#1}}{#2}}} + {-1}//}{-1}} +\newcommand\getcharlistindex[2]{\number\ifnotempty{#2}{\ettl@nbk#1//% + {\ExpandAftercmds{\ettl@setresult 2of3><}{\ettl@getsinglelist{\ettl@ifchar{#1}}{#2}}} + {-1}//}{-1}} +\newcommand\gettokslistcount[1]{\number\ifnotempty{#1}% + {\ExpandAftercmds{\ettl@setresult 1of3><}{\ettl@getsinglelist{\ettl@ifx{\\}}{#1}}} + 0} +\newcommand\getcharlistcount[1]{}% +\let\getcharlistcount=\gettokslistcount +\newcommand\gettokslisttoken[2]{\ifnotempty{#2}{\ettl@nbk#1//% + {\ExpandAftercmds{\ettl@setresult 3of3><}{\ettl@getsinglelist{\ettl@ifx{#1}}{#2}}} + {}//}{}} +\newcommand\getcharlisttoken[2]{\ifnotempty{#2}{\ettl@nbk#1//% + {\ExpandAftercmds{\ettl@setresult 3of3><}{\ettl@getsinglelist{\ettl@ifchar{#1}}{#2}}} + {}//}{}} +% \end{macrocode} +% \cs{ettl@getsinglelist}\cmdlabel{impl:ettl@getsinglelist} initiates the loop (we test if the list or the \prm{item} is empty first): +% \begin{macrocode} +\long\def\ettl@getsinglelist#1#2{\ettl@singlelist@loop{-1}{-1}{}#2//% + {\ettl@expandafthree\ettl@singlelist@loop#1}% + {\expandafter\ettl@singlelist@result\@thirdofthree}/End§List/} +% \end{macrocode} +% \cs{ettl@singlelist@loop} tests each token and update registers: +% \begin{macrocode} +\long\def\ettl@singlelist@loop#1#2#3#4#5/#6#7#8/End§List/{% + #7{#4} + {{#1+1}{#2+1+0*(0}{#4}} + {{#1+1}{#2+1}{#3}}#5//{#7}{#8}/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. +% +% \#2 is the current index. It is incremented by $1$ and will be equal to the length of the list, at the end. +% \#3 is the index of the \prm{item} (if found): it is incremented by $1$ but at the time +% \prm{item} is found is the list, the next increments are canceled (multiplication by $0$). +% +% The fourth parameter remains the same (\#4=\#4=|empty|, set at the initiation of the loop) but at the time \prm{item} +% is found, \#4 becomes this \prm{item} (precisely the matching item found in the list: \#5). +% +% \#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} +\def\ettl@singlelist@result#1#2#3#4/End§List/{\ExpandNextTwo\@swaptwo% + {\number\numexpr\ifempty{#3}{-1}{#2)}}{\number\numexpr#1}{#3}} +% \end{macrocode} +% Then \cs{ettl@setresult} finishes the job: +% \begin{macrocode} +\def\ettl@setresult#1of#2>#3<{\ettl@nbk #3//% + {\ettl@set@result#1of#2>#3<} + {\csname ettl@#1of#2\endcsname}//} +\def\ettl@set@result#1of#2>#3<#4{\ifdefcount{#3} + {#3=\csname ettl@#1of#2\endcsname#4} + {\expandafter\edef\noexpand#3{\csname ettl@#1of#2\endcsname{#4}}}% +} +% \end{macrocode} +% \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} +\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} +% \cs{ettl@defcmdparser} does the definitions: \cs{parser->start} initiates the loop (and add a separator +% at the end of the list) and \cs{parser->loop} loops into the list, expanding the (optional, default |\do|) user code +% for each item. +% +% In case the \CH{\ttbf+} form is used, the auxiliary macro \cs{ettl@doitemidx} overloads +% the user-code. Otherwise (simple form without index): \cs{ettl@doitem} overloads the user-code. +% \begin{macrocode} +\protected\long\def\ettl@defcmdparser#1#2#3#4#5#6#7{%#1=global,#2=command,#3=sep,#4=start,#5=loop,#6=loop+ + #1\long\def#4##1##2[##3]##4{% ##1=case, ##2=expandafter??? , ##3=do, ##4=list + ##2{##4}% ifiscs or @thirdofthree + {\expandafter\@swaparg\expandafter{##4}{#4{##1}\@thirdofthree[{##3}]}} + {\ettl@nbk##4//% + {\ifcase##1 \ettl@or\@swaplast{\number\numexpr#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{\ifx##10\expandafter\relax\fi}}% + }{\ettl@breakloop{}}///End§List/}}% + #1\long\def#5##1##2#3##3##4/##5##6##7/End§List/{% + \ifcat $\detokenize{##2}$\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/{% + \ifcat $\detokenize{##3}$\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*}{####1}}} + {\@ifchar+{\@ifchar*% + {\ettl@forloop{\expandafter#2\expandafter*\expandafter+}{[####1]####2}} + {\ettl@forloop{\expandafter#2\expandafter+}{[####1]####2}}} + {\ettl@forloop{\expandafter#2}{####1}}}} + #1\def#2{\ettl@lst@modif#423\ifiscs}} +% \end{macrocode} +% \cs{ettl@lst@doitem} gives the current item to the auxiliary macro, while \cs{ettl@lst@doitemidx} gives the index as well. +% \cs{ettl@lts@getitem} is the helper macro in case we ask for an item (cf. |\csvloop[4]\mylist|) and +% \cs{etttl@lst@count} is as basic as it can be! +% \begin{macrocode} +\long\def\ettl@lst@getitem#1[#2]#3{% + \ifnum\numexpr#1<0 \@swap{\breakloop{}}\fi + \ifnum\numexpr#1=#2 \@swap{\breakloop{#3}}\fi} +\long\def\ettl@lst@count[#1]#2{+\ettl@nbk#2//10//} +% \end{macrocode} +%\end{Macro} +% +% \begin{macro}{\ettl@lst@modif} \cmdlabel{impl:ettl@lst@modif} \FE +% \cs{ettl@lst@modif} is used by any command-list-parser at the beginning to set the options. This macro is interesting +% because it is recursive: each allowed modifier is parsed one after the other in a purely expandable way, setting +% the registers (\#1 to \#4) to the value corresponding to the modifier used (the registers are initialized to their default value). +% +% Such a code is interesting because it may be used elsewhere: the aim is to parse modifiers without taking care of their +% order (\cs{csvloop}\stform*\stform+ is the same as \cs{csvloop}\stform{+*}): +% \begin{macrocode} +\long\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{#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}{breakloop} +% \cs{breakloop} gobbles anything until the \CH{/End§List/} delimiter: +% \begin{macrocode} +\long\def\ettl@breakloop#1#2/End§List/{#1} +\let\breakloop\ettl@breakloop +% \end{macrocode} +% \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% +}% \ettl@for@nested +% \end{macrocode} +%\end{macro} +% +% \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} +\DeclareCmdListParser\csvloop{,} +% \end{macrocode} +% \end{Macro} +%\end{Macro*} +% +% \begin{codecomment} +% \begin{Macro*}{listloop} +%\begin{Macro}{forlistloop} +% Definition of |\listloop| (with a `\,\textbar\,' of catcode 3 (math shift) -- cf.\xpackage{etoolbox}). \cs{forlistloop} is +% defined by \cmdref{DeclareCmdListParser} but is not purely expandable: +% \begin{macrocode} +\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 +% +%%% \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*}{csvlistadd} +%\begin{Macro*}{csvlistgadd} +%\begin{Macro*}{csvlisteadd} +%\begin{Macro}{csvlistxadd} +% \begin{macrocode} +\providerobustcmd\csvlistadd[2]{\ettl@nbk#2//{\appto#1{#2,}}{}//} +\providerobustcmd\csvlistgadd[2]{\ettl@nbk#2//{\gappto#2{#2,}}{}//} +\providerobustcmd\csvlisteadd[2]{\begingroup \protected@edef#1{#2}% + \expandafter\ettl@nbk#1//{\expandafter\endgroup + \expandafter\appto\expandafter#1\expandafter{#1,}}\endgroup//} +\providerobustcmd\csvlistxadd[2]{\begingroup \protected@edef#1{#2}% + \expandafter\ettl@nbk#1//{\expandafter\endgroup + \expandafter\gappto\expandafter#1\expandafter{#1,}}\endgroup//} +% \end{macrocode} +%\end{Macro} +%\end{Macro*} +%\end{Macro*} +%\end{Macro*} +% +% \iffalse +% +%%% \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} +\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} +% +% \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} +\newcommand\listtocsv[1]{\FE@ifstar{#1}{\ettl@convertlist{{\listloop*}\ettl@do@listtocsv}} + {\ettl@convertlist{\listloop\ettl@do@listtocsv}}} +\long\def\ettl@do@listtocsv#1{\unexpanded{#1,}} +% \end{macrocode} +%\end{Macro} +% +% \iffalse +%%% \tokstolist [\ListMacro] { \toksListMacro / token token token } +% \fi +% +% \begin{Macro}{tokstolist} +% This is the first application of |\toksloop|: +% \begin{macrocode} +\newcommand\tokstolist[1]{\FE@ifstar{#1}{\ettl@convertlist{{\toksloop*}\ettl@do@tokstolist}} + {\ettl@convertlist{\toksloop\ettl@do@tokstolist}}} +\begingroup\catcode`\|=3% etb catcode +\long\gdef\ettl@do@tokstolist#1{\unexpanded{#1}|} +\endgroup +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \csvtolistadd \ListMacro \csvListMacro +%%% \csvtolistadd* \ListMacro {item,item,item} +% \fi +% \begin{Macro}{csvtolistadd} +% \cs{csvtolistadd} is not purely expandable: +% \begin{macrocode} +\newrobustcmd*\csvtolistadd{\@ifstar{\ettl@csvtolistadd*}{\ettl@csvtolistadd{}}} +\long\def\ettl@csvtolistadd#1#2#3{\eappto#2{\csvtolist#1[]{#3}}} +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%% \tokstolistadd \ListMacro { \toksListMacro / token token token } +% \fi +% +% \begin{Macro}{tokstolistadd} +% \cs{tokstolistadd} is not purely expandable: +% \begin{macrocode} +\newrobustcmd*\tokstolistadd{\@ifstar{\ettl@tokstolistadd*}{\ettl@tokstolistadd{}}} +\long\def\ettl@tokstolistadd#1#2#3{\eappto#2{\tokstolist#1[]{#3}}} +% \end{macrocode} +% \end{Macro} +% +%\begin{macro}{\ettl@RemoveInList} \cmdlabel{impl:ettl@RemoveInList} +% This is the general constructor for deletion into lists with any separator: +% \begin{macrocode} +\newrobustcmd\ettl@RemoveInList[2]{\begingroup +% #1 = \global #2 = macro name + \def\ettl@RemoveInList##1{% + \edef\ettl@RemoveInList####1####2{% + \ettl@Rem@veInList{####1}####2\noexpandcs{##1->remove}\noexpandcs{##1->result}% + }\ettl@RemoveInList{#1}#2% + }\expandafter\ettl@RemoveInList\expandafter{\romannumeral-`\q\@gobblescape#2}} +\protected\long\def\ettl@Rem@veInList#1#2#3#4#5#6#7#8{% + \long\def#3[##1]##2#5#8#5##3##4/##5##6##7/End§List/{##6[##1+1]##2#5##3##4//##6##7/End§List/}% + \ifnotempty{#5}%% special case if no separator + {\long\def#4[##1]#5##2#5#5##3//##4/End§List/{\unexpanded{#1\def#7{##2#5}}% + \ettl@nbk#6//{\ettl@setresult 1of1>#6<{\number\numexpr##1-1\relax}}{}//}}% + {\long\def#4[##1]##2//##3/End§List/{\unexpanded{#1\def#7{##2}}% + \ettl@nbk#6//{\ettl@setresult 1of1>#6<{\number\numexpr##1-1\relax}}{}//}}% + \long\def#2##1{#3[0]#5##1#5#5#8#5//#3#4/End§List/}% + \edef#7{\endgroup\expandafter#2\expandafter{#7}}#7} +\def\ettl@gobble@relax#1\relax{} +% \end{macrocode} +%\end{macro} +% +% \iffalse +% +%%% \listdel \listMacro { item } +%%% \listgdel \listMacro { item } +%%% \listedel \listMacro { item } +%%% \listxdel \listMacro { item } +% \fi +% +% \begin{Macro*}{listdel} +% \begin{Macro*}{listedel} +% \begin{Macro*}{listgdel} +% \begin{Macro}{listxdel} +% \cs{listdel} removes an \prm{item} from a list, \cs{listedel} expands the \prm{item} (with |\protected@edef|) first, +% \cs{listgdel} make the assignment to the (shorter-)list global and \cs{listxdel} both expands the \prm{item} and +% makes the assignment global: +% \begin{macrocode} +\edef\ettl@restore@catcode{\catcode124 \the\catcode124}% |=124 +\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}} +\ettl@restore@catcode\undef\ettl@restore@catcode +\newrobustcmd\ettl@listedel[6]{\begingroup\protected@edef#5{#6}\expandafter\endgroup + \expandafter\@swaparg\expandafter{#5}{\ettl@RemoveInList#1#2{#3}{#4}#5}} +% \end{macrocode} +% \end{Macro} +% \end{Macro*} +% \end{Macro*} +% \end{Macro*} +% +% \iffalse +% +%%% \csvdel \listMacro { item } +%%% \csvgdel \listMacro { item } +%%% \csvedel \listMacro { item } +%%% \csvxdel \listMacro { item } +% \fi +% +% \begin{Macro*}{csvdel} +% \begin{Macro*}{csvedel} +% \begin{Macro*}{csvgdel} +% \begin{Macro}{csvxdel} +% \cs{csvdel} removes an \prm{item} from a list, \cs{csvedel} expands the \prm{item} (with |\protected@edef|) first, +% \cs{csvgdel} make the assignment to the (shorter-)list global and \cs{csvxdel} both expands the \prm{item} and +% makes the assignment global: +% \begin{macrocode} +\newrobustcmd\csvdel[1][]{\ettl@RemoveInList{}\csvdel,{#1}} +\newrobustcmd\csvgdel[1][]{\ettl@RemoveInList\global\csvdel,{#1}} +\newrobustcmd\csvedel[1][]{\ettl@listedel{}\csvdel,{#1}} +\newrobustcmd\csvxdel[1][]{\ettl@listedel\global\csvdel,{#1}} +% \end{macrocode} +% \end{Macro} +% \end{Macro*} +% \end{Macro*} +% \end{Macro*} +% +% \iffalse +% +%%% \toksdel \listMacro { item } +%%% \toksgdel \listMacro { item } +%%% \toksedel \listMacro { item } +%%% \toksxdel \listMacro { item } +% \fi +% +% \begin{Macro*}{toksdel} +% \begin{Macro*}{toksedel} +% \begin{Macro*}{toksgdel} +% \begin{Macro}{toksxdel} +% \cs{toksdel} removes an \prm{item} from a list, \cs{toksedel} expands the \prm{item} (with |\protected@edef|) first, +% \cs{toksgdel} make the assignment to the (shorter-)list global and \cs{toksxdel} both expands the \prm{item} and +% makes the assignment global: +% \begin{macrocode} +\newrobustcmd\toksdel[1][]{\ettl@RemoveInList{}\toksdel{}{#1}} +\newrobustcmd\toksgdel[1][]{\ettl@RemoveInList\global\toksdel{}{#1}} +\newrobustcmd\toksedel[1][]{\ettl@listedel{}\toksdel{}{#1}} +\newrobustcmd\toksxdel[1][]{\ettl@listedel\global\toksdel{}{#1}} +% \end{macrocode} +% \end{Macro} +% \end{Macro*} +% \end{Macro*} +% \end{Macro*} +% +%\iffalse +% +% +%%% \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\long\def\ettl@getlistindex##1#4#6#4##2/End§List/{\endgroup + \ExpandAftercmds{\ettl@setresult 1of1>#1<}{\ettl@nbk##2//{#3*!{##1}}{-1}//}% + }#2\ettl@getlistindex#5#4#6#4/End§List/} +\newrobustcmd\getlistindex{\@ifstar + {\@testopt{\ettl@get@listindex\relax}{}} + {\@testopt{\ettl@get@listindex\expandafter}{}}} +\begingroup\catcode`\|=3% etb catcode +\protected\long\gdef\ettl@get@listindex#1[#2]#3#4{% + \ifx#1\relax + \ettl@getlistindex{#2}{}\listloop|{#4}{#3}% + \else \ifiscs{#4} + {\ettl@getlistindex{#2}#1\listloop|{#4}{#3}} + {\ettl@getlistindex{#2}\listloop|{#4}{#3}}% + \fi} +\endgroup%\catcode group +% \end{macrocode} +% \end{Macro} +% +% \iffalse +% +%%\getcsvlistindex [\result]{ item }{ csvlistmacro } +%%\getcsvlistindex*[\result]{ item }{ item,item,item } +% \fi +% \begin{Macro}{getcsvlistindex} +% The command is robust, not purely expandable: +% \begin{macrocode} +\newrobustcmd\getcsvlistindex{\@ifstar + {\@testopt{\ettl@get@csvlistindex\relax}{}} + {\@testopt{\ettl@get@csvlistindex\expandafter}{}}} +\protected\long\gdef\ettl@get@csvlistindex#1[#2]#3#4{% + \ifx#1\relax + \ettl@getlistindex{#2}{}\csvloop,{#4}{#3}% + \else \ifiscs{#4} + {\ettl@getlistindex{#2}#1\csvloop,{#4}{#3}} + {\ettl@getlistindex{#2}\csvloop,{#4}{#3}}% + \fi} +% \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} +\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*}{ifincsvlist} +% A robust command with a star form. +% \begin{Macro}{xifincsvlist} +% The same with |\protected@edef|. +% \begin{macrocode} +\ettl@if@inlist\ifincsvlist{,} +\ettl@xif@inlist\xifincsvlist{,} +\undef\ettl@if@inlist +\undef\ettl@xif@inlist +% \end{macrocode} +% \end{Macro} +% \end{Macro*} +% +% \iffalse +% +%%% \interval{ number }{ sorted comma separated list of numbers } +% \fi +% +%\begin{Macro}{interval} +% \cs{interval} will expand to the number of the interval of \prm{number} into the \prm{sorted comma separated list of integers}: +% \begin{macrocode} +\newcommand\interval[2]{\romannumeral-`\q% + \ExpandNext{\avoidvoid[\csvloop!{#2}]}{\csvloop+[\ettl@do@interval{#1}]{#2}}} +\def\ettl@do@interval#1[#2]#3{\ifdim#1\p@<#3\p@ \@swap{\breakloop{#2}}\fi} +% \end{macrocode} +%\end{Macro} +% +% \iffalse +% +%%% \interplin{ number }{ sorted comma separated list of numbers }{ comma separated liist of numbers } +% \fi +% +%\begin{Macro}{locinterplin} +% \begin{macrocode} +\newcommand\locinterplin[3]{\romannumeral-`\q + \unless\ifnum\numexpr(\csvloop!{#2})-(\csvloop!{#3})=0 + \PackageError{etextools}{Using \string\locinterplin\space the lists in argument 1 and 2\MessageBreak + must have the same number of elements} + {You're in trouble here and I cannot proceed...} + \fi + \ExpandNextTwo{\ettl@locinterplin{#1}{#3}{#2}}{\interval{#1}{#2}}{\csvloop!{#2}}} +\begingroup\catcode`\/ 12% +\gdef\ettl@locinterplin#1#2#3#4#5{% + \ifnum#4=0 \csvloop[#4]{#2}% + \else\ifnum#4=#5 \expandafter\csvloop\expandafter[\number\numexpr#5-1]{#2}% + \else\ifdim#1\p@=\expandafter\csvloop\expandafter[\number\numexpr#4-1]{#3}\p@ + \expandafter\csvloop\expandafter[\number\numexpr#4-1]{#2}% + \else\strip@pt\dimexpr% + \expandafter\csvloop\expandafter[\number\numexpr#4-1]{#2}\p@+% + (#1\p@-\expandafter\csvloop\expandafter[\number\numexpr#4-1]{#3}\p@)*% + (\expandafter\csvloop\expandafter[\number\numexpr#4-1]{#2}-\csvloop[#4]{#2})/% + (\expandafter\csvloop\expandafter[\number\numexpr#4-1]{#3}-\csvloop[#4]{#3})\relax + \fi\fi\fi} +\endgroup% catcode group +% \end{macrocode} +%\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 - not to be used - experimental +\ProcessOptions*\relax +% \end{macrocode} +% +% \begin{macrocode} +% +% \end{macrocode} +% +% \Section*{Examples} \refstepcounter{section} +% \label{sec:examples} +% ^^A\addcontentsline{toc}{section}{\texorpdfstring\dr{}\hskip\dimexpr\cftsecnumwidth-4pt Implementation}^^A do not add to .cmd file +% \addcontentsline{toc}{section}{\protect\numberline{II}\cftsecfont Examples}^^A do not add to .cmd file +% \addtocontents{toc}{\cftbeforesubsecskip=-2pt plus\gluestretch\cftbeforesubsecskip\relax} +% ^^A\renewrobustcmd\noexpand\cftsubsecfont{\footnotesize}}\renewcommand\thesubsection{I.\arabic{subsection}}^^A for toc +% +% This is the code of \sty{etextools-example.tex} which comes with the package. +% +% \begin{macrocode} +%<*example> +\ProvidesFile{etextools-examples} +\documentclass[11pt,french,a4paper,oneside]{scrartcl} +\usepackage[latin1]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[american]{babel} +\usepackage{geometry,doc,ltxdockit,txfonts,fancyhdr,stmaryrd,graphicx,enumitem} +\usepackage{etextools} +% +\usepackage{fancyvrb} +% +\makeatletter +\let\org@newif\newif +\def\newif#1{\ifx#1\ifnotempty\else\expandafter\org@newif\fi} +\usepackage{umrand} +\renewcommand\ifne[1]{\csname @\ifcat $\detokenize{#1}$first\else second\fi oftwo\endcsname\iffalse\iftrue} +\let\newif\org@newif +\font\umranda=umranda \def\Ch{\char'} +% +\def\textvb#1{{\usefont{T1}{txtt}{m}{n}#1}} +\newrobustcmd\thispackage{\xpackage{\spot etextools}\xspace} +\newrobustcmd\xpackage[1]{{\usefont{T1}{lmss}{bx}{n}\db\mbox{#1}}} +\hypersetup{colorlinks,pdfstartview={FitH}} +\geometry{top=1.5cm,bottom=1.2cm,left=2.5cm,right=1cm} +\fancyhf{} +\fancyhead[L]{Examples for the \thispackage package} +\pagestyle{fancy} +\DefineShortVerb{\|} +\catcode`\^^a7 \active\def^^a7{\par\nobreak\vskip-\parskip} +\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} +\definecolor{dg}{rgb}{0.00,0.37,0.00} \newrobustcmd\dg{\color{dg}} \newrobustcmd\dgbf{\dg\bfseries} +\definecolor{spot}{rgb}{1.00,0.33,0.00} \newrobustcmd\spot{\color{spot}} +\definecolor{db}{rgb}{0.00,0.00,0.25} \newrobustcmd\db{\color{db}} +\newrobustcmd\blue{\color{blue}} +\newrobustcmd\nnn{\normalfont\mdseries\upshape} +% +\newrobustcmd\ClearPage{\@ifstar\clearpage{}} +\def\make@macro#1{\string\def\string#1\parameters@meaning#1\string{\strip@meaning#1\string}} +\newcommand\preline{\@ifstar{\@preline}{\hrulefill\par\@preline}} +\newcommand\@preline[2][1.5ex]{\noindent\hskip6pt\textvb{\make@macro#2}\par\ifblank{#1}{}{\vskip#1}} +% +\ifdef\pdfstrcmp{\let\ifpdfTeX\iffalse}{\let\ifpdfTeX\iftrue} +% +\newcommand*\test{\@ifstar{\let\fe\pdfFE\testi}{\let\fe\FE\testi}} +\newcommand\testi[1]{% + \csname test#1\endcsname + \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{\vskip-2cm\thispackage\ examples} +\subtitle{Examples for some macros provided by the \thispackage package} +\author{\small} +\date{} +% +\newsavebox\helpbox \newsavebox\helpboxx +\newrobustcmd*\mydotleader[2][\z@]{\leavevmode\xleaders\hbox to\dimexpr1.7pt+#1{\hss\raise#2\hbox{$\scriptscriptstyle\cdotp$}\hss}} +\begingroup\let\clearpage\@empty +\setbox\helpbox\hbox to13cm{\hss\lower3cm\vbox to1.8cm{\maketitle\vss}\hss} +\fboxsep\z@ +\newrobustcmd\corner[2][\spot\umranda]{\hbox{#1\rlap{\char'115}\char'#2}} +\null\vskip-1cm\hskip-1cm\null\hfil\RandBox {\fbox{\copy\helpbox}} + font {\umranda} [0pt] + (\corner{17}) ([\Ch111]) (\corner{14}) + ([\Ch112]) ([\Ch112]) + (\corner{21}) ([\Ch111]) (\corner{11}) +\endgroup +% +\tableofcontents\hyperdef{ettlex}{toc}{} +% +\section{\cmd{expandnext} examples} +% +\subsection{Test if the replacement text of macro is really empty} +% +\def\xx{ } +\def\testexpandnext{% + \edef\expandnextTest{\string\xx\ is \expandnext\ifempty{\xx}{}{not} empty} +} +\preline\xx +\test{expandnext} +% +\def\xx{} +\preline\xx +\test{expandnext} +% +\ClearPage* +\subsection{Test if the replacement text of a macro is blank (empty or spaces)} +% +\def\xx{something} +\def\testexpandnext{% + \edef\expandnextTest{\string\xx\ is \expandnext\ifblank{\xx}{}{not} blank} +} +\preline\xx +\test{expandnext} +% +\def\xx{ } +\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{Test the parameter string of a macro} +% +The following commands create the filter for the string: "\textvb{[\#1]\#2"}":^^a7 +\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} +% +\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} +% +\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 +% +\ClearPage* +\section{Testing characters} +\subsection{\cmd{ifsinglechar} versus \cmd{iffirstchar}} +\def\testifsinglechar{% + \edef\ifsinglecharTest{\ifsinglechar *{*hello*}{ single star }{ something else }} +}\hrulefill\par +\test{ifsinglechar} +% +\def\testifsinglechar{% + \edef\ifsinglecharTest{\ifsinglechar *{ *}{ single star }{ something else }} +}\hrulefill\par +\test{ifsinglechar} +% +\def\testifsinglechar{% + \edef\ifsinglecharTest{\ifsinglechar *{ * }{ single star }{ something else }} +}\hrulefill\par +\test{ifsinglechar} +{\small Note the space \textbf{after} the star $\uparrow$.} +% +\def\testiffirstchar{% + \edef\iffirstcharTest{\iffirstchar *{*hello*}{ first char is star }{ something else }} +}\hrulefill\par +\test{iffirstchar} +% +\subsection{Fully Expandable starred macros} +\def\starmacro#1{\FE@ifstar{#1}\starred\notstarred} +\def\starred#1{your "#1" will be processed by the STAR form} +\def\notstarred#1{your "#1" will be processed by the NORMAL form} +\def\testFE@ifstar{% + \edef\FE@ifstarTest{\starmacro{sample text}}} +\preline\starmacro +\preline*\starred +\preline*\notstarred +\test{FE@ifstar} +% +\def\testFE@ifstar{% + \edef\FE@ifstarTest{\starmacro*{sample text}}} +\hrulefill\par +\test{FE@ifstar} +% +\subsection{Fully Expandable macros with options} +\def\optmacro#1{\FE@testopt{#1}\OPTmacro{Mr.}} +\def\OPTmacro[#1]#2{#1 #2} +\def\testFE@testopt{% + \edef\FE@testoptTest{\optmacro{Woody Allen}}} +\preline\optmacro +\preline*\OPTmacro +\test{FE@testopt} +% +\def\testFE@testopt{% + \edef\FE@testoptTest{\optmacro[Ms.]{Vanessa Paradis}}} +\hrulefill\par +\test{FE@testopt} +% +\ClearPage* +\section{Lists management} +% +\subsection{\cmd{csvloop} and \cmd{csvloop*} examples} +% +\subsubsection{\cmd{makequotes}} +\def\makequotes#1{"#1"\space} +\def\testcsvloop{% + \edef\csvloopTest{\csvloop*[\makequotes]{hello,world}} +} +\preline\makequotes +\test{csvloop} +% +\subsubsection{\cmd{detokenize}} +\def\testcsvloop{% + \edef\csvloopTest{\csvloop*[\detokenize]{\un,\deux}} +}\hrulefill\par +\test{csvloop} +% +\subsubsection{\cmd{numexpr}} +\def\mylist{1,2,3,4,5}\def\BySeven#1{$#1\times 7 = \number\numexpr#1*7\relax$\par} +\def\testcsvloop{% + \edef\csvloopTest{\csvloop[\BySeven]\mylist}} +\preline\mylist +\preline*\BySeven +\test{csvloop} +% +\subsubsection{protected \cmd{textbf}} +\def\testcsvloop{% + \protected@edef\csvloopTest{\csvloop*[\textbf]{hello ,my ,friends}} +}\hrulefill\par +\test{csvloop} +% +\subsection{Index in lists and items by index} +% +\subsubsection{\cmd{listloop}: getting specific item} +\csvtolist*[\mylist]{one,two,three,four,five,alpha,beta,gamma} +\def\testgetlistitem{% + \edef\getlistitemTest{\listloop[4]\mylist} +}\hrulefill\par +\noindent\hskip6pt|\csvtolist*[\mylist]{one,two,three,four,five,alpha,beta,gamma}|\par\vskip1.5ex +\test{getlistitem} +% +\ClearPage* +\subsubsection{\cmd{getlistindex}} +\ifpdfTeX +\leavevmode\vadjust{\textsl{Require the }\string\pdfstrcmp\ \textsl{primitive (pdf\TeX{}) :}} +\def\testgetlistindex{% + \edef\getlistindexTest{\getlistindex{alpha}\mylist} +}\hrulefill\par +\noindent\hskip6pt|\csvtolist*[\mylist]{one,two,three,four,five,alpha,beta,gamma}|\par\vskip1.5ex +\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} +\fi +\hrulefill\par +% +\getlistindex[\myindex]{alpha}\mylist +{\color{blue}\noindent\hskip6pt\llap\smex|\getlistindex[\myindex]{alpha}\mylist|\par\vskip1.5ex} +{\tt\string\myindex=\quad\textbf{\meaning\myindex}} +\par\hrulefill\par\vskip.5ex +% +\hrulefill\par +\newcount\myindex +\getcsvlistindex*[\myindex]{alpha}{one,two,three,four,five,alpha,beta} +\noindent\hskip6pt|\newcount\myindex|\par +{\color{blue}\noindent\hskip6pt\llap\smex|\getcsvlistindex*[\myindex]{alpha}{one,two,three,four,five,alpha,beta}|}\par\vskip.5ex +{\tt\string\the\string\myindex=\qquad\textbf{\the\myindex}} +\par\hrulefill\par\vskip.5ex +% +\ClearPage +\subsubsection{\cmd{gettokslistindex} with \cmd{ifcase}} +% +\hrulefill\par\vskip2ex\noindent +\llap{\FE\,\smex}\par\vskip-2.5\baselineskip\strut +\leavevmode\vadjust{Always purely expandable (no need of |\pdfstrcmp|, comparison done by |\ifx|):} +\begin{Verbatim} + \ifcase \gettokslistindex{D}{LRDF\relax O} + What do to if L + \or What do to if R + \or What do to if D + \or What do to if F + \or What do to if \relax + \or What do to if O + \else Problem + \fi +\end{Verbatim} +% +{\tt Result=\qquad\bfseries +\ifcase\gettokslistindex{D}{LRDF} + What do to if L +\or What do to if R +\or What do to if D +\or What do to if F +\else Problem +\fi}\par +\hrulefill\par\vskip.5ex +% +\end{document}\endinput +% +% \end{macrocode} +% +% \phantomsection +% \Section*{Revision history} +% \addcontentsline{toc}{section}{\texorpdfstring\dr{}\hskip\dimexpr\cftsecnumwidth-4pt Revision history}^^A not in .cmd file +% +% \begin{changelog}\footnotesize +% +% \begin{release}{3.1415926}{2010-12-07} +% \item Addition of \cmdref{@char@testopt} +% \item Correction of a but in \cmdref{ifempty} and \cmdref{ifnotempty}. +% \item Correction (again...) in \cmdref{thefontname}: now use of \cs{nfss@text} (better if in math mode). +% \item Documentation revisited with \Xpackage{interfaces}. +% \end{release} +% +% \begin{release}{3.14159}{2010-04-20} +% \item \cs{ettl@thefontname} overwrote \cs{T1/cmr/m/n/10} on the log file when the font \sty{ecmr1000} was used.\\ +% Fixed + modification of \cmdref{thefontname} in order to get both \TeX{} and \LaTeX{} font names. +% \item Correction of bugs into \cmdref{listdel} +% \item Joining the example file \sty{etextools-examples.tex} to this \sty{.dtx} file. +% \end{release} +% +% \begin{release}{3.1415}{2009-10-14} +% \item Correction of a bug in \cmdref{locinterplin}. +% \end{release} +% +% \begin{release}{3.141}{2009-10-08} +% \item |\relax| added after \cmdref{listloop}\stform! (\cmdref{csvloop}\stform! etc.) in order to explicitly stop |\numexpr|. +% \end{release} +% +% \begin{release}{3.14}{2009-10-04} +% \item Stabilisation of some commands. +% \end{release} +% +% \begin{release}{3.0}{2009-09-09} +% \item Definition of \cmdref{DeclareStringFilter}, \cmdref{FE@modifiers} and \cmdref{ettl@supergobble} +% +% \end{release} +% +% \begin{release}{2k}{2009-09-04} +% \item Addition of \\ +% \cmdref{ExpandNext} \\ +% \cmdref{naturalloop} \\ +% the star form of \cmdref{futuredef} \\ +% the \cs{global} option of \cmdref{DeclareCmdListParser} +% \item Reimplementation of \\ +% the lists macros for optimisation (cf \cmd{ettl@ifnotblank}) \\ +% \cmdref{ifsinglechar} for optimisation +% \item Addition of examples to the \sty{etextools-examples.tex} +% \item Test on pdf\LaTeX{} and Xe\TeX. +% \end{release} +% +% \begin{release}{2i}{2009-08-31} +% \item +% Addition of \cmdref{futuredef} a macro (and vectorized) version of \cs{futurelet}. +% \item +% Redesign of \cmdref{expandnext}: the first argument can now be arbitrary code +% (before, it was necessarily a single control sequence, as for \CS{expandafter}). +% \item +% Redesign of \cmdref{deblank}, after a solution provided by \xpackage{environ.sty}. +% \item +% Addition of \cmdref{ifincsvlist}, \cmdref{ifintokslist} and \cmdref{xifincsvlist}. +% \item +% Addition of \cmdref{forcsvloop}, \cmdref{forlistloop} and \cmdref{fortoksloop}. +% \item +% Addition of \cmdref{csvdel}, \cmd{csvedel}, \cmd{csvgdel} and \cmd{csvxdel} +% \item +% Optimization of \cmdref{getlistindex} and \cmdref{getcsvlistindex} +% \end{release} +% +% \begin{release}{2t}{2009-08-15} +% \item +% Addition of \cmdref{ifnotempty}, \cmdref{ifstrcmp}, \cmdref{ifstrmatch} +% +% \end{release} +% +% \begin{release}{2h}{2009-08-14} +% \item +% \cmdref{getlistindex} is now fully expandable +% +% \item Addition of\\ +% \cmdref{toksloop} +% +% \item Addition of\\ +% \cmdref{FE@ifchar} as a generalization of \cmdref{FE@ifstar}. +% +% \end{release} +% +% \begin{release}{2z}{2009-08-12} +% \item Addition of \\ +% \cmdref{ifempty}, \cmdref{toksloop}, \cmdref{tokstolist} and \cmdref{tokstolistadd} +% \item +% Modification of \cmdref{ifsinglechar}\\ +% \cmdref{ifsinglechar} now works with \cmdref{ifempty} so that:\\ +% \begin{tabbing} +% \quad\=|\macro{ * }|\quad\= is no more considered as a starred form \\ +% \>\>because of the spaces following the |*| \\ +% \>\> however, the spaces \textbf{before} are skipped, \\ +% \>\>as does |\@ifnextchar| from the \LaTeX{} kernel. +% \end{tabbing} +% +% \item +% Index added to this documentation paper. +% \end{release} + +% \begin{release}{2e}{2009-07-14} +% \item +% First version (include an example file) +% \end{release} +% +% \end{changelog} +% +% \begin{thebibliography}{9} +% +% \bibitem{etex} +% David Carlisle and Peter Breitenlohner +% \textit{The \xpackage{etex} package}; +% 1998/03/26 v2.0; +% \CTAN{macros/latex/contrib/etex-pkg/}. +% +% \bibitem{etoolbox} +% Philipp Lehman +% \textit{The \xpackage{etoolbox} package}; +% 2008/06/28 v1.7; +% \CTAN{macros/latex/contrib/etoolbox/}. +% +% \end{thebibliography} +% +% \setcounter{IndexColumns}{2}\clearpage +% \PrintIndex +% \makeatletter +% \immediate\write\@mainaux{\noexpand\newlabel{LastPage}{{}{\thepage}{}{page.\arabic{page}}{}}} +% \Finale \ No newline at end of file -- cgit v1.2.3