% \iffalse meta-comment %%% etextools : e-TeX tools for LaTeX Users and package Writers (v.3.1415 - 2009/10/14) % % 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 2009/10/14 v.3.1415 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}}% } \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.1415} \def\thisdate{14 October 2009} \newcommand\makebookmark[1]{} %-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= \documentclass[a4paper,oneside]{ltxdockit} \usepackage[latin1]{inputenc} \usepackage[american]{babel} \usepackage{doc,tocloft,stmaryrd,amsmath,amssymb,xspace,graphics,geometry,fancyhdr,titlesec,relsize,framed,bbding,enumitem,embedfile,etoolbox,marvosym,wasysym,soul,makecell,arydshln,numprint} \CodelineNumbered\CodelineIndex \usepackage{fancyvrb,microtype} \makeatletter\let\org@newif\newif\def\newif#1{\ifx#1\ifnotempty\else\expandafter\org@newif\fi} \usepackage{umrand} \let\newif\org@newif \makeatother \newrobustcmd*\cmdLabel[1]{\csgdef{cmdlabel->#1}{}} \embedfile{\thisfile.dtx} \geometry{left=4.5cm,marginparwidth=14pt,right=1.5cm,top=3mm,headsep=3mm,bottom=3mm,footskip=8mm,includeheadfoot} \titlepage{% title={The \Thispackage macros}, subtitle={An \etex package providing useful (purely expandable) tools \\ for LaTeX Users and package Writers}, url={http://www.ctan.org/tex-archive/macros/latex/contrib/etextools/}, author={\footnotesize Florent CHERVET}, email={\footnotesize\mdseries florent.chervet@free.fr}, revision={\footnotesize\thisrevision}, date={\footnotesize\thisdate}} \hypersetup{% hyperindex=true, pdftitle={The etextools package}, pdfsubject={An e-TeX package providing useful tools for LaTeX package writers -- essay on purely expandability}, pdfauthor={Florent CHERVET}, colorlinks,linkcolor=reflink,urlcolor=spot, pdfkeywords={tex, e-tex, latex, package, programming}, bookmarksopen=true,bookmarksopenlevel=2} \begin{document} \DocInput{\thisfile.dtx} \end{document} % % \fi % % \CheckSum{2866} % % \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} % \hypersetup{hyperindex=true} % % \makeatletter % \AtEndDocument{\immediate\write\@outlinefile{\let\noexpand\makebookmark\noexpand\@firstofone}}^^A \immediate because there is no more \shipout... % \immediate\write\@outlinefile{\noexpand\makeatletter} % \newrobustcmd\AddBookMark[1]{\write\@outlinefile{\noexpand\makebookmark{\noexpand\pdfoutline#1}}} % ^^A\let\ClearPage\clearpage^^A problem with Verbatim and page break-to be fixed for final print % \newrobustcmd\ClearPage{\@ifstar{\clearpage}{}} % \newrobustcmd\thispackage{\xpackage{\spot\thisfile}\xspace} % \newrobustcmd\Thispackage{\Xpackage[\thisfile]{\spot\thisfile}\xspace} % \newrobustcmd\xpackage[1]{{\usefont{T1}{lmss}{bx}{n}\db\mbox{#1}}} % \newcommand\Xpackage{\@dblarg\X@package} % \protected\def\X@package[#1]#2{\xpackage {#2\footnotemark}\footnotetext {\noindent \xpackage{#2}: \CTAN{macros/latex/contrib/#1}}} % \newrobustcmd*\CTAN[1]{\href{http://www.ctan.org/tex-archive/#1}{\nolinkurl{CTAN:#1}}} % \font\ding=dingbat scaled 800 % \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} % ^^A\newrobustcmd\mymprm[1]{\mbox{\{\prm{ \ignorespaces#1\ignorespaces\ }\}}} % \renewrobustcmd\ltxsyntaxlabelfont{\spot\usefont{T1}{pcr}{b}{n}} % \newrobustcmd\mycolorbox[1][{[rgb]{1.00,1.00,0.79}}]{\@testopt{\my@colorbox[{#1}]}{\red}} % \protected\long\def\my@colorbox[#1][#2]#3{\colorbox#1{#2#3}} % ^^A\newrobustcmd\mycolorbox[1]{\colorbox[rgb]{1.00,1.00,0.79}{\red #1}} % \def\Underbrace#1_#2{$\underbrace{\vtop to2ex{}\hbox{#1}}_{\footnotesize\hbox{#2}}$} % \newrobustcmd*\mydotleader[2][\z@]{\leavevmode\xleaders\hbox to\dimexpr1.7pt+#1{\hss\raise#2\hbox{$\scriptscriptstyle\cdotp$}\hss}} % \globcount\ettl@AfterGroup % \newrobustcmd\AfterGroup[1]{\global\advance\ettl@AfterGroup1\relax % \csxdef{ettl@aftergroup@hook\the\ettl@AfterGroup}{\expandonce{#1}}% % \expandafter\aftergroup\csname ettl@aftergroup@hook\the\ettl@AfterGroup\endcsname} % \long\def\avoidcsvoid[#1]#2{\expandafter\ifcsvoid\expandafter{\romannumeral-`\q#2}{#1}{#2}} \let\avoidvoidcs\avoidcsvoid % \long\def\avoidvoid[#1]#2{\ifdefvoid{#2}{#1}{#2}} % \newrobustcmd*\movepage[2][]{\advance\hsize by#2\hoffset\ifblank{#1}{-#2}{#1}\linewidth\the\hsize\textwidth\the\hsize} % \newrobustcmd\pagenumberdisplay{\leavevmode\lower5pt\hbox{\ttfamily\oldstylenums{\thepage} / \oldstylenums{\pageref{LastPage}}}} % \fancypagestyle{corpus}{\fancyhf{}\let\headrulewidth\z@ \footskip=\z@ % \fancyhead[L]{\deflength\@tempdima{\the\hsize+\the\thesecwidth}\rmkcolor % \hskip-\thesecwidth\rlap{\lower6pt\hbox to\@tempdima{\mydotleader\z@\hfill}}\hfill % \small The \textcolor{black}{\thispackage}\ macros -- an \eTeX{} package for \LaTeX\hfill} % \fancyfoot[L]{\color[gray]{.35}\footnotesize\textcolor{black}{\thispackage\unskip\enspace\copyright}\enspace\scriptsize\lower.3ex\hbox{\NibRight}\enspace Florent Chervet} % \fancyfoot[R]{\pagenumberdisplay}} % \fancypagestyle{toc}{\fancyhf{}\let\headrulewidth\z@ \fancyfoot[R]{\pagenumberdisplay}} % \fancypagestyle{empty}{\fancyhf{}\let\headrulewidth\z@} % ^^A COLORS : % \let\Org@definecolor\definecolor % \renewrobustcmd\definecolor[1][]{\ettl@definecolor{#1}} % \newrobustcmd\ettl@definecolor[4]{\Org@definecolor{#2}{#3}{#4}% % \ifblank{#1}{\ifcsname#2\endcsname\expandafter\expandafter\expandafter\renewrobustcmd % \else\expandafter\expandafter\expandafter\newrobustcmd % \fi\csname#2\endcsname{\color{#2}}} % {\newrobustcmd#1{\color{#2}}}} % \definecolor{spot}{rgb}{1.00,0.33,0.00} \definecolor{fecc}{rgb}{.2,.6,.2} % \definecolor[\macrocodecolor]{macrocode}{rgb}{0.18,0.00,0.45} % \definecolor{ly}{rgb}{0.81,1.00,0.42} % \definecolor{dc}{rgb}{0,0.6,0.6} % \definecolor{cream}{rgb}{1.00,1.00,0.77} \definecolor{db}{rgb}{0.00,0.00,0.25} % \newrobustcmd\black{\color{black}} \newrobustcmd\blue{\color{blue}} % \renewcommand*\MacroFont{\usefont{T1}{lmtt}{m}{n}\macrocodecolor} % \pretocmd\macrocode{\def§{\IeC{\S}}\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 % \renewrobustcmd\ltd@cmditem[1][]{\goodbreak % \@ifchar-{\my@cmditem@starred[{#1}]\@gobble} % {\@ifstar{\my@cmditem@starred[{#1}]\@firstofone}{\my@cmditem[{#1}]}}} % \newcommand\my@cmditem@starred[3][]{% % \edef\laststarredcmditem{\ifblank{#1}{#3}{#1}}% % \edef\cmditem@end@hook{\cmditem@labelize{\ifblank{#1}{#3}{#1}}}% % #2{\refstepcounter{command} % \expandafter\addcommand\expandafter{\laststarredcmditem}{}{#3}}% % \Org@ltd@cmditem{#3}}^^A Make bookmark anyway (no star form) % \newrobustcmd\my@cmditem[1][]{\@ifchar+% % {\@ifchar @{\my@cmd@item[{#1}]{\spot}\@gobble}{\my@cmd@item[{#1}]{\spot}\@firstofone}} % {\@ifchar @{\my@cmd@item[{#1}]\@firstofone\@gobble}{\my@cmd@item[{#1}]\@firstofone\@firstofone}}} % \newrobustcmd\my@cmd@item[4][]{% % \let\lastcmditem\@empty\let\laststarredcmditem\@empty % \edef\lastcmditem{\ifblank{#1}{#4}{#1}}% % \def\cmditem@end@hook{\cmditem@labelize@display{\avoidvoid[\laststarredcmditem]\lastcmditem}} % \refstepcounter{command} % \expandafter\addcommand\expandafter{\lastcmditem}{#2}{#4}% % #3{\Org@ltd@cmditem{#4}}} % \newrobustcmd\addcommand[3]{% % \addcontentsline{cmd}{command}{\protect\numberline{\cftcommandnum{#1}{#2\arabic{command}}}\cftcommandfont#2{\protect\textbackslash#3}}} % \newrobustcmd\cftcommandnum[2]{\ifinlist{#1}\listofFEcommands \FEtiny{}\cftcommandfont \mdseries\sffamily\scriptsize\hfill #2\kern.4em} % \AtEndDocument{\immediate\write\@mainaux{% % \begingroup\catcode124 3\relax\gdef\noexpand\listofFEcommands{\detokenize\expandafter{\FEcmdlist}}\endgroup}} % \unless\ifdefined\listofFEcommands\let\listofFEcommands\@empty\fi % \newrobustcmd\seeimpl@display[1][]{\seeimpl[{#1}]{\avoidvoid[\laststarredcmditem]\lastcmditem}}% % \newrobustcmd\cmditem@labelize@display[1]{\cmdlabel{#1}\hfill\par} % \newrobustcmd\cmditem@labelize[1]{\cmdlabel{#1}\hfill\par} % ^^A At the end of the ltxdockit scanner for \cmditem, the labelize-macro must be expanded: % \apptocmd\ltd@parseargs@end{\cmditem@end@hook}{}{} % ^^A Now Macro envir may use the labels: % \def\@Macro#1{\begin{macro}{#1}} % \newenvironment{Macro}[2][]{% % \expandafter\@Macro\expandafter{\@backslashchar#2} \cmdlabel{impl:#2}% % \ifblank{#1}{\Check@FEList{#2}\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}} % \newlistof{command}{cmd}{\listcommandname}\let\listcommandname\@empty % \DefineVerbatimEnvironment{VerbLines}{Verbatim}{gobble=1,frame=lines,framesep=6pt,fontfamily=txtt,fontseries=b} % \DefineVerbatimEnvironment{Verb}{Verbatim}{gobble=1} % \DefineVerbatimEnvironment{VerbZ}{Verbatim}{gobble=1} % \cftbeforepartskip=6pt % \cftsubsecnumwidth=1.5em % \renewcommand\cftsubsecpresnum{\hbox to.5em\bgroup\hss} % \renewcommand\cftsubsecaftersnum{\egroup\hbox to1em{\hss\tinybullet\hss}} % \renewcommand\cftsubsecpagefont{\scriptsize} % \renewrobustcmd\cftsubsecleader{\kern.4em\mydotleader[1pt]\z@\hfill} % \cftbeforesubsecskip=-.7pt^^Aplus.01fil % \cftbeforesecskip=3pt^^Aplus.01fil % \cftsecnumwidth=1.5em % \renewrobustcmd\cftsecfont{\usekomafont{section}\large\bfseries\red} % \renewcommand\cftpartfont{\usekomafont{section}\large\bfseries} % \renewcommand\cftsecpresnum{\cftsecfont\hbox to.5em\bgroup\hss} % \renewcommand\cftsecaftersnum{\egroup\raise.2ex\hbox to1em{\hss\scriptsize\Forward\hss}} % \cftcommandnumwidth=1.5em % \let\cftcommandleader\cftsubsecleader % \renewcommand\thecommand{\arabic{command}} % \renewrobustcmd\cftcommandfont{\large\sfbf\db} % \newlength\thesecwidth\thesecwidth=2.2cm % \titleformat\section[hang]{\LARGE\bfseries} % {\llap{\hbox to\thesecwidth{\hfil\arabic{section}\hfil\kern.4em{\spot\Forward}\kern.4em\hfil}}}\z@{} % \titlespacing\section\z@{6pt plus4pt minus2pt}{3pt plus2pt minus1pt} % \newcommand\sectionbreak{\penalty-3000} % \newrobustcmd\normalsubsecformat{% % \titleformat\subsection[hang]{\Large\bfseries} % {\llap{\hbox to\thesecwidth{\arabic{section}\textbullet\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}}\z@{}% % \titlespacing\subsection\z@{6pt plus4pt minus2pt}{3pt plus2pt minus1pt}% % \renewcommand\sectionmark[1]{\addcontentsline{cmd}{section}{\protect\numberline{\arabic{section}}##1}}}% % \newrobustcmd\implementationsubsecformat{% % \titleformat\subsection[hang]{\Large\bfseries} % {\llap{\hbox to\thesecwidth{I\textbullet\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}}\z@{}% % \titlespacing\subsection\z@{6pt plus4pt minus2pt}{3pt plus2pt minus1pt}% % \titleformat\subsubsection[hang]{\large\bfseries} % {\llap{\hbox to\thesecwidth{I\textbullet\arabic{subsection}\textbullet\arabic{subsubsection}\hfil{\fecc--}\hfil}}}\z@{}% % }% % ^^A\renewcommand\sectionmark[1]{\addcontentsline{cmd}{section}{\protect\numberline{I.\arabic{subsection}}##1}}} % \newrobustcmd\firstsubsecformat{% % \titleformat\subsection[hang]{\large\bfseries} % {\llap{\hbox to\thesecwidth{\hss\arabic{subsection}\hfil{\fecc\manerrarrow}\hfil}}}\z@{} % \titlespacing\subsection\z@{5pt plus2pt minus2pt}{3pt plus2pt minus1pt}% % \let\sectionmark\@gobble % }\firstsubsecformat % \newcommand\subsectionbreak{\penalty-500} % \newcommand\Section{\@ifstar{\section*}{\@ifchar.{\@dblarg{\@Section.}}{\@dblarg{\@Section{}}}}} % \long\def\@Section#1[#2]#3{% % \ifblank{#1}{}{\let\WriteBookmarks\relax}% % \section[{\texorpdfstring{\protect\cftsecfont}{}#2}]{#3}% % \ifblank{#1}{}{\let\WriteBookmarks\@empty\numdef\Hy@currentbookmarklevel{\Hy@currentbookmarklevel-1}}} % \newcommand\Subsection{\@ifstar{\subsection*}{\@ifchar.{\@dblarg{\@Subsection.}}{\@dblarg{\@Subsection{}}}}} % \long\def\@Subsection#1[#2]#3{% % \ifblank{#1}{}{\let\WriteBookmarks\relax}% % \subsection[{#2}]{#3}% % \ifblank{#1}{}{\let\WriteBookmarks\@empty\numdef\Hy@currentbookmarklevel{\Hy@currentbookmarklevel-1}}} % \newsavebox\helpbox \newsavebox\helpboxx % \newcommand\hpbox{\copy\helpbox} \newcommand\hpboxx{\copy\helpboxx} % \lastlinefit999 \parindent\z@ \topsep\z@ \partopsep\z@ \parskip.3\baselineskip % \fontfamily{ua1}\selectfont \pagestyle{corpus} % \MakeShortVerb{\|} % \makeatother % % ^^A TITLE PAGE + TABLE OF CONTENTS % \begingroup \movepage{2cm}\voffset-1.5\baselineskip \skip\footins=-1.5cm % \tocloftpagestyle{toc} % \pretocmd\pagenumberdisplay{\vspace*{1cm}}{}{} \enlargethispage{1.5cm} % \definecolor{reflink}{gray}{0}\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 % ^^A\printtitlepage % \AddBookMark{attr{/F 2}goto page 1{/FitH}{etextools}} % % \begingroup\makeatletter\parfillskip\z@ % ^^A\cftsetpnumwidth{0pt} % \renewcommand\cfttoctitlefont{\mydotleader{.5ex}\hfill\kern.5em\Large\bfseries} % \renewcommand\cftaftertoctitle{\kern.5em\mydotleader{.5ex}\hfill\kern\z@\par\vskip-12pt} % \renewcommand\cftpartleader{\kern.4em\mydotleader{.4ex}\hfill\hbox to\z@{\mydotleader{.4ex}\hskip\@pnumwidth\kern\z@\hss}} % \cftbeforesubsecskip=-.7ptplus.01fil % \cftbeforesecskip=2ptplus.01fil % \definecolor{reflink}{rgb}{0.37,0.00,0.37} % ^^A\immediate\write18{copy \jobname.tocc \jobname.toc} % \vskip-2pt\tableofcontents % \vskip-2\parskip\leavevmode\mydotleader{0pt}\hfill\kern0pt\par\vskip-\parskip % \endgroup ^^A\the\pagetotal % % \vskip-6pt\begin{shaded}\parindent0pt\noindent\normalsize\topsep=-\parskip\itemsep=-\parskip % \let\reflink\reflinkabstract % % {\bfseries\catcode`\ \active\let =\,\hfil\NibSolidRight¤¤\raise3pt\hbox{ A b s t r a c t }¤¤\NibSolidLeft\hfil}\par % % The \thispackage package is based on the \xpackage{etex} and \xpackage{etoolbox} % packages and defines a lot of macros for \LaTeX\ Users or package Writers. % Before using this package, it is highly recommended to read the % documentation (of this package and...) of the \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 ---------------------------------------------------------------------------------------------- % \clearpage % \endgroup % ^^A\stop % \begingroup \movepage{1cm} % \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}. % % \hfil\begin{tabular}{|>{\rred}c|l|}\hline % \thead{levels} & \thead{sequence to get the result} \\ \hline % $\mathbf1$ & \cs[\red]{expandnext}|{\def\result}{|\cs[\copper]{FEmacro}\mprm{arguments}|}| \\ \hdashline[1pt/1pt] % $\mathbf2$ & \cs[\red]{expandnext}\cs[\red]{expandnext}|{\def\result}{|\cs[\copper]{FEmacro}\mprm{arguments}|}| \\ \hdashline[1pt/1pt] % more & \cs[\red]{ExpandNext}|{\def\result}{|\cs[\copper]{FEmacro}\mprm{arguments}|}| \footnotemark \\ \hline % \end{tabular}\hfil % \footnotetext{\cs{ExpandNext} is not alway enough: \cs{csvloop} for exemple requires \cs{edef} (or \cs{csname}...) to be completely expanded.}. % % 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}% % ^^A\immediate\write18{copy \jobname.ccmd \jobname.cmd} % \def\@begincmdhook{\multicolsep\z@\let\normalcolor\spot\columnseprule.4pt\columnsep=1.5cm\begin{multicols}{2}} % \def\@endcmdhook{\AfterGroup{\enlargethispage{2\baselineskip}\mydotleader{-1ex}\hfill\kern\z@}\end{multicols}} % \cftsecindent=\glueexpr-\wd\FEtiny@box-.35em % \renewrobustcmd\cftsecfont{\sfbf\large\black} % \renewcommand\cftcmdtitlefont{\leavevmode\mydotleader{.4ex}\hfill\kern.5em\LARGE\bfseries} % \renewcommand\cftaftercmdtitle{\kern.5em\mydotleader{.4ex}\hfill} % \renewcommand\listcommandname{\makecellbox[bc]{\thispackage\\[-1ex]List of Commands Provided}} % \cftaftercmdtitleskip=6pt % \cftbeforesecskip=2pt plus.1fil % \cftbeforecommandskip=2pt plus.1fil % \tocloftpagestyle{empty}\catcode`\+ 12 \catcode`\! 12 % \pdfdest name{ListOfCommands} xyz\hyperdef{Part}{ListOfCommands}{} % \addtocontents{toc}{\protect\contentsline{part}{\protect\colorbox[rgb]{1.00,1.00,0.79}{\protect\hyperref{}{Part}{ListOfCommands}{\blue List of commands}}}{}{}} % \vspace*{-18mm}\listofcommand % \AddBookMark{attr{/F 2/C[0 0 1]}goto name{ListOfCommands}{List of commands}} % \clearpage % \endgroup % ^^A\stop % % \part*{{\spot\blacksmiley}\hfill All User Commands\hfill{\spot\blacksmiley}} % % \hypersetup{bookmarksopenlevel=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} 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}{ csname } % % \cs{showcs} does \cs{show} on the named control sequence. % % \cmditem{meaningcs}{ csname } % % \cs{meaningcs}\FEII gives the \cs{meaning} of the named control sequence. However, if the control sequence is % not defined, \cs{meaningcs} expands to |\meaning\@undefined| (\ie the word \CH{undefined}) rather than the expected |\relax|. % % \cmditem{strip@meaning}{ cs-token } % \cmditem*{strip@meaningcs}{ csname } \FEII* % % \csbf{strip@meaning}\FEII gives the \cs{meaning} of the \prm{cs-token}: % \begin{enumerate}[label=\roman*)~] % \item without the prefix `\,|macro:|\#1\#2...|->|)\,` ¤ if \prm{cs-token} is a macro % \item integrally if \prm{cs-token} is defined and is not a macro % \item expands to an empty string if \prm{cs-token} is undefined. % \end{enumerate} % % \cs{strip@meaningcs} does the same for named control sequences. % % \cmditem{parameters@meaning}{ cs-token } % \cmditem*{parameters@meaningcs}{ csname } \FEII* % % \csbf{parameters@meaning}\FEII expands to the part of the \cs{meaning} which corresponds % to the \textitbf{parameter string}. If a macro has no parameter, then it expands to an empty string. % If the \prm{cs-token} or the \prm{csname} given is not a macro, it also expands to an empty string. % % \newcommand*\mycell{\small\makecell[c]} \newcommand*\macpf{\vb macro:} \let\theadfont=\nbf % \hskip-1.5em\begin{tabular}{|>{\vb\cs{}}l|c|c|c|}\hline % \multicolumn{4}{c}{\textbfbf{to summarize}} \\ \hline % \omit&\omit&\omit&\omit \\[.3ex] \cline{2-4} % \multicolumn{1}{l|}{} & \thead{macro} & \thead{not macro} & \thead{undefined} \\ \hline % meaning & \mycell{the meaning \\ \eg \macpf[\#1]\#2->\#1\#2} & \mycell{the meaning \\ \eg \cs{count21}} & \vb undefined \\ % meaningcs & \mycell{the meaning \\ \eg \macpf[\#1]\#2->\#1\#2} & \mycell{the meaning \\ \eg \cs{count21}} & \vb undefined \\\hdashline[1pt/1pt] % strip@meaning & \mycell{the replacement text \\ \eg \#1\#2} & \mycell{the meaning \\ \eg\cs{count21}} & an empty string \\ % strip@meaningcs & \mycell{the replacement text \\ \eg \#1\#2} & \mycell{the meaning \\ \eg\cs{count21}} & an empty string \\\hdashline[1pt/1pt] % parameters@meaning & \mycell{the parameter string \\ \eg[\#1]\#2} & an empty string & an empty string \\ % parameters@meaningcs & \mycell{the parameter string \\ \eg[\#1]\#2} & an empty string & an empty string \\ \hline % \end{tabular} % \medbreak % % \cmditem{ifdefcount}{ single token }{ true }{ false } % \cmditem*{ifdeftoks}{ single token }{ true }{ false } \FEII* % \cmditem[ifdefskip]@{ifdefdimen\tsptb ifdefskip\tsptb ifdefmuskip} % \cmditem-{ifdefdimen} {cs-token }{ true }{ false } \FEII* % \cmditem-{ifdefskip}{ single token }{ true }{ false } \FEII* % \cmditem-{ifdefmuskip}{ single token }{ true }{ false } \FEII* % \cmditem[ifdefchar]@{ifdefchar\tsptb ifdefmathchar} % \cmditem-{ifdefchar}{ single token }{ true }{ false } \FEII* % \cmditem-{ifdefmathchar}{ single token }{ true }{ false } \FEII* % % \xpackage{etoolbox}\FEII provides \cs{ifdefmaco} to test if a given control sequence is defined as a macro. % \thispackage provides tests for other types of tokens. % % Test is made by a filter on the meaning of the \prm{single token} given as argument. The test is always false % if this \prm{single token} is an undefined control sequence. % \iffalse % \cs{ifdefblankspace} will expand \prm{true} if the \prm{single token} is a blank space.§ % \cs{ifdefthechar} will expand \prm{true} is the \prm{single token} has a meaning of the form: |the character|\stform[\blue]\textellipsis§ % \cs{ifdeftheletter} will expand \prm{true} is the \prm{single token} has a meaning of the form: |the letter|\stform[\blue]\textellipsis§ % % {\rmk \cs{ifdefcount} is used -- indirectly -- in the definition of \cmdref{getlistindex} and the other macros % for getting indexes: \cmdref{getcsvlistindex} etc.} % \fi % \ClearPage % % \cmditem[avoidvoid]+@{avoidvoid \tsptb avoidvoidcs} % \cmditem-{avoidvoid} [ replacement code ]{ cs-token / string } \FEII* % \cmditem-{avoidvoid\stform*}[ replacement code ]{ cs-token / string } \FEII* % % \csbf{avoidvoid}\FEII will test the \prm{cs-token} with \cs{ifdefvoid} (from \xpackage{etoolbox}). In case % \prm{cs-token} is void (that means: it is either undefined or has been |\let| to |\relax| or it is a parameterless macro % with blank -- \ie empty or space -- replacement string), then \cs{avoidvoid} expands \prm{replacement code} % (optional parameter whose default is an empty string). % % Otherwise, \prm{cs-token} is not void (that means: it is defined, its meaning is not |\relax| AND it is either % a macro with parameters or a parameterless macro with a replacement string which is NOT blank) % then \cs{avoidvoid} expands \prm{cs-token}:§§ % \begin{VerbLines}[commandchars=$()] % ($red\avoidvoid) {\@undefined} ($nnn will expand to an empty string) % ($red\avoidvoid) [($copper\macro)]\relax ($nnn will expand) ($md$copper\macro) % ($red\avoidvoid) [($copper$!$!$! string is blank)]{$spview} ($nnn will expand$vb$copper string is blank) % ($red\avoidvoid$stform*)[($copper$!$!$! string is empty)]{$spview} ($nnn will expand $spview) % ($red\avoidvoid) [($copper\errmessage{string must not be empty})]{some text} % ($nnn will expand$vb some text) % ($red\avoidvoid) [($copper\errmessage{macro is void$})]\macro % ($nnn will expand ($vb$copper\errmessage{...}) if ($vb\macro) is void) % \protected\def($dg\test){$spview} % \edef($copper\result){($red\avoidvoid$stform*)($dg\test)} % \meaning($copper\result) macro:->($dg\test) ($nnn1-expansion of ($dg\test) not empty) % \edef($copper\result){($red\avoidvoid)[other]($dg\test)} % \meaning($copper\result) macro:->other ($nnn1-expansion of ($dg\test) is blank) % \end{VerbLines} % % \cs{avoidvoid} is based on \cs{ifblank} test, either onto \prm{string} or, if \prm{string} is in fact a % control word (tested with \cmdref{ifiscs}) on the replacement text of this control word\footnote{if it is defined % as a macro. Well: the test occurs on the result of \cmdref{strip@meaning} onto the control-sequence!}. If for your % special purpose, you prefer to test if the \prm{string} (or the replacement text of \prm{cs-token}) is \textbfsf{really empty % and not only blank}, the \stform* star-form of \cs{avoidvoid} is made for you! % % \cs{avoidvoid} is purely expandable and uses \cmdref{FE@ifstar} and \cmdref{FE@testopt}: % if the mandatory argument is a \prm{string} equal to \CH{\stform[\blue]*$__{12}$} or \CH{\stform[\blue][$__{12}$}^^A] % there will be a problem (and most probably an error). Therefore, \textbfsf{when using \csbf{avoidvoid} you are encourage to % specify always an option, even if it is empty.} % % \cmditem-{avoidvoidcs} [ replacement code ]{ csname } \FEII* % \cmditem-{avoidvoidcs\stform*}[ replacement code ]{ csname } \FEII* % % \csbf{avoidvoidcs}\FEII will do the same as the former (\cs{avoidvoid}) but the mandatory argument \prm{csname} % is interpreted as a control sequence name. \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{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}{ 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]} \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{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[{Vectorized \texorpdfstring{\cs[\sfbf]{futurelet}}{\cs{futurelet}}}]{Vectorized \csbf{future{\blue let}}: \csbf{future{\spot def}}} % % \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{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{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} % \cmditem-{xgetlistindex}[result-index(counter or macro)]{item}{Listmacro} % \cmditem-{getlistindex*}[result-index(counter or macro)]{item}{list} % \cmditem-{xgetlistindex*}[result-index(counter or macro)]{item}{list} % % \end{ltxsyntax} % % Sometimes\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} % \cmditem-{xgetcsvlistindex}[result-index(counter or macro)]{item}{csvlistmacro} % \cmditem-{getcsvlistindex*}[result-index(counter or macro)]{item}{item,item,item,...} % \cmditem-{xgetcsvlistindex*}[result-index(counter or macro)]{item}{item,item,item,...} % \end{ltxsyntax} % % This\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} [2009/10/14 v3.1415 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@\if @\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 @% \if @\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} \newcommand*\noexpandcs[1]{\expandafter\noexpand\csname #1\endcsname} % \end{macrocode} % \end{Macro} % % \iffalse % %% noexpandafter % \fi % % \begin{Macro}{noexpandafter} % {\rmk \cmd{noexpandafter} only means \cmd{noexpand}\cmd{expandafter} and is shorter to type.} % \begin{macrocode} \newcommand*\noexpandafter{\noexpand\expandafter} % \end{macrocode} % % \end{Macro} % % \Subsection{Meaning of control sequences} % % \iffalse % %%% \thefontname % \fi % %\begin{Macro}{thefontname} % \begin{macrocode} \newcommand\thefontname{{\expandafter\ettl@thefontname\expandafter\strip@meaning\the\font}} \font\ettl@thefontname=ecrm1000 % \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 % %%% \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}{\if @\detokenize{#1#2}@first\else\ifx#1#2first\else second\fi\fi}//} {\if @\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 % %%% \ifOneToken{ token }{ true }{ false } % \fi % % \begin{Macro}{ifOneToken} % \cs{ifOneToken} test if its argument contains only one token (possibly a space token): % \begin{macrocode} \newcommand\ifOneToken[1]{\romannumeral\csname rmn@\ettl@firstspace{#1} {\ettl@nbk#1//{second}{\if @\detokenize{#1}@second\else first\fi}//} {\if @\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}{\if @\detokenize{#1#2}@first\else\ifx#1#2first\else second\fi\fi}//} {\if @\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}{\if @\detokenize{#1}@second\else first\fi}//} {\if @\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}} {\if @\detokenize{#1}@secondoftwo\ettl@csname\fi \ettl@firstspace{#2}{first}{second}}//}% {\ettl@nbk#1//% {\if @\detokenize{#2}@secondoftwo\ettl@csname\fi \ettl@firstspace{#1}{first}{second}} {\if @\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//% {\if @\expandafter\ettl@cdr\detokenize{#1}\@nil @secondoftwo\ettl@csname\fi \if @\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@\if @\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@\if @\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//% {\if @\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 @\if @\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 @\if @\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 @\if @\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 @\if @\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$ call to \cs{aftergroup} primitive.}:§§ % \begin{macrocode} \newrobustcmd\aftergroup@def[1]{% \let\etex@let@primitive\let \def\let{\global\etex@let@primitive}% \expandafter\LetLtxMacro\csname ettl@ftergroup@def\number\numexpr\the\ettl@fter+1\endcsname#1% \global\advance\ettl@fter\@ne \etex@let@primitive\let=\etex@let@primitive \aftergroup\LetLtxMacro \aftergroup#1% \expandafter\aftergroup\csname ettl@ftergroup@def\the\ettl@fter\endcsname \aftergroup\global \aftergroup\undef \expandafter\aftergroup\csname ettl@ftergroup@def\the\ettl@fter\endcsname} \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 % %%% \ettl@ifnextchar{ character token }{ true }{ false } % % \fi % %\begin{Macro}{ettl@ifnextchar} % \cs{ettl@ifnextchar} is based on the \cmdref={character-test} rather than the |\ifx|-test. See the example for % explanation on its behaviour.§ % \csbf{ettl@ifnextchar} is used in the definition of \cmdref*{aftergroup@def} and \cmdref*{@ifchar} (of course...).§ % We take advantage of delimited definitions to exits from |\if|...|\fi| conditionnals (even in the case where % the macro parameter may be |\else|, |\if| or |\fi|...): % \begin{macrocode} \newrobustcmd\ettl@ifnextchar[3]{\begingroup \edef\1##1/##2/##3{##1\endgroup\unexpanded{#2}##3}% \edef\2##1/##2/##3{##1\endgroup\unexpanded{#3}##3}% \ifOneToken{#1} {\csname ettl@\if @\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@\if @\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//% {\ifdefcount{#3}{#3=\csname ettl@#1of#2\endcsname} {\edef#3{\csname ettl@#1of#2\endcsname}}}% {\csname ettl@#1of#2\endcsname}//} % \end{macrocode} % \end{Macro} % \end{Macro*} % \end{Macro*} % \end{Macro*} % \end{Macro*} % \end{Macro*} % % \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} doeas the definitions: \cs{parser->start} initiates the loop (and add a separator % at the end of the list) and \cs{parser->loop} loops into the list, expanding the (optional, default |\do|) user code % for each item. % % In case the \CH{\ttbf+} form is used, the auxiliary macro \cs{ettl@doitemidx} overloads % the user-code. Otherwise (simple form without index): \cs{ettl@doitem} overloads the user-code. % \begin{macrocode} \protected\long\def\ettl@defcmdparser#1#2#3#4#5#6#7{%#1=global,#2=command,#3=sep,#4=start,#5=loop,#6=loop+ #1\long\def#4##1##2[##3]##4{% ##1=case, ##2=expandafter??? , ##3=do, ##4=list ##2{##4}% ifiscs or @thirdofthree {\expandafter\@swaparg\expandafter{##4}{#4{##1}\@thirdofthree[{##3}]}} {\ettl@nbk##4//% {\ifcase##1 \ettl@or\@swaplast{\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/{% \if @\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/{% \if @\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*\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} % \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} \begingroup\catcode`\|=3 \newrobustcmd\listdel[1][]{\ettl@RemoveInList{}\listdel|{#1}} \newrobustcmd\listgdel[1][]{\ettl@RemoveInList\global\listdel|{#1}} \newrobustcmd\listedel[1][]{\ettl@listedel{}\listdel|{#1}} \newrobustcmd\listxdel[1][]{\ettl@listedel\global\listdel|{#1}} \aftergroup@def\listdel \aftergroup@def\listgdel \aftergroup@def\listedel \aftergroup@def\listxdel \endgroup% \catcode group \newrobustcmd\ettl@listedel[6]{\begingroup\protected@edef#5{#6}\expandafter\endgroup \expandafter\@swaparg\expandafter{#5}{\ettl@RemoveInList#1#2{#3}{#4}#5}} % \end{macrocode} % \end{Macro} % \end{Macro*} % \end{Macro*} % \end{Macro*} % % \iffalse % %%% \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\def\ettl@getlistindex##1#4#6#4##2/End§List/{\endgroup \romannumeral-`\q\ettl@setresult 1of1>#1<{\ettl@nbk##2//{#3*!{##1}}{-1}//}% }#2\ettl@getlistindex#2#5#4#6#4/End§List/} \begingroup\catcode`\|=3% etb catcode \newrobustcmd\getlistindex[3][]{\@ifstar% {\ettl@getlistindex{}\listloop{|}{#1}{#2}{#3}} {\ifiscs{#1}{\ettl@getlistindex\expandafter\listloop|{#1}{#2}{#3}} {\ettl@getlistindex{}\listloop|{#1}{#2}{#3}}}} \aftergroup@def\getlistindex \endgroup%\catcode group % \end{macrocode} % \end{Macro} % % \iffalse % %%\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[3][]{\@ifstar% {\ettl@getlistindex{}\csvloop{,}{#1}{#2}} {\ifiscs{#1}{\ettl@getlistindex\expandafter\csvloop,{#1}{#2}} {\ettl@getlistindex{}\csvloop,{#1}{#2}}}} % \end{macrocode} % \end{Macro} % % \begin{macro}{\ettl@ifinlist} % \cs{ettl@ifinlist} will build a \cs{ifinlist} macro for list with a given separator. % \begin{macrocode} \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*{Revision history} % \addcontentsline{toc}{section}{\texorpdfstring\dr{}\hskip\dimexpr\cftsecnumwidth-4pt Revision history}^^A not in .cmd file % % \begin{changelog}\footnotesize % % \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}\\ % |\ifsinglechar| now works with |\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