summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/texapi
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2010-06-18 15:55:40 +0000
committerKarl Berry <karl@freefriends.org>2010-06-18 15:55:40 +0000
commit6a610c4ffff82f7e5188bd0154b7859244e02447 (patch)
tree39e69457f4d5831b124063e76e5ad654679ae4ee /Master/texmf-dist/tex/generic/texapi
parent79527eba1a0ef70a5b911ebacf7fdc03a24615e9 (diff)
new generic package texapi (17jun10)
git-svn-id: svn://tug.org/texlive/trunk@19035 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/generic/texapi')
-rw-r--r--Master/texmf-dist/tex/generic/texapi/texapi.tex899
1 files changed, 899 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/texapi/texapi.tex b/Master/texmf-dist/tex/generic/texapi/texapi.tex
new file mode 100644
index 00000000000..11b31c9eadf
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/texapi/texapi.tex
@@ -0,0 +1,899 @@
+% This is the texapi package.
+% Relevant information can be found in texapi-doc.pdf
+%
+% Author: Paul Isambert.
+% E-mail: zappathustra AT free DOT fr
+% Comments and suggestions are welcome.
+% Date: June 2010.
+%
+\ifx\texapialreadyloaded\somethingtotallyundefined
+\else
+ \expandafter\endinput
+\fi
+\let\texapialreadyloaded\relax
+\ifx\eTeXversion\somethingtotallyundefined
+ \errmessage{texapi error: You need eTeX to run this. I quit}
+ \expandafter\endinput
+\fi
+%
+\expandafter\edef\csname pi@restorecatcodes\endcsname{%
+ \catcode`\noexpand\@=\the\catcode`@\relax
+ \catcode`\noexpand\_=\the\catcode`_\relax
+ }
+\catcode`\@=11 \catcode`\_=11
+%
+%
+%
+%
+%
+% ENGINES
+%
+\chardef\texenginenumber=0
+\ifdefined\XeTeXinterchartoks
+ \chardef\texenginenumber=1
+\else
+% LuaTeX doesn't have \pdfstrcmp anymore.
+ \ifdefined\directlua
+ \chardef\texenginenumber=3
+ \else
+ \ifdefined\pdfstrcmp
+ \chardef\texenginenumber=2
+ \fi
+ \fi
+\fi
+%
+%
+%
+%
+% FORMATS
+%
+% It'd be safer if \formatnumber was already
+% defined in a wrapper file for ConTeXt and LaTeX.
+%
+\unless\ifdefined\formatnumber
+ \chardef\formatnumber=0
+ \def\pi@temp{plain}
+ \ifx\fmtname\pi@temp
+ \chardef\formatnumber=1
+ \else
+ \def\pi@temp{eplain}
+ \ifx\fmtname\pi@temp
+ \chardef\formatnumber=2
+ \else
+ % I'm not sure what ConTeXt's doing with \fmtname,
+ % so I make do with this lovely control sequence.
+ \ifdefined\inspectnextoptionalcharacter
+ \chardef\formatnumber=3
+ \else
+ \def\fmtname{LaTeX2e}
+ \ifx\fmtname\pi@temp
+ \chardef\formatnumber=4
+ \ifdefined\ExplSyntaxOn
+ \chardef\formatnumber=5
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+\fi
+%
+% We need to get some primitives back.
+% More should be done, probably.
+%
+\ifnum\formatnumber=3
+ % ConTeXt
+ \let\priminput\normalinput
+ \let\primunexpanded\normalunexpanded
+ \def\loadmacrofile#1{\usemodule[#1]}
+ \def\senderror#1#2{%
+ \writestatus{#1 error}{#2}%
+ }
+\else
+ \ifnum\formatnumber=4
+ % LaTeX2e
+ \let\priminput\@@input
+ \let\primunexpanded\unexpanded
+ \let\loadmacrofile\RequirePackage
+ \def\senderror#1#2{%
+ \PackageError{#1}{#2}{}%
+ }
+ \else
+ \ifnum\formatnumber=5
+ % LaTeX3
+ % I don't know if this is of any good.
+ % LaTeX3 will either not rename those primitives,
+ % or turn all primitives to error messages (nightmare),
+ % as far as I can see.
+ \expandafter\let\expandafter\priminput\csname tex_input:D\endcsname
+ \expandafter\let\expandafter\primunexpanded\csname etex_unexpanded:D\endcsname
+ \let\loadmacrofile\RequirePackage
+ \def\senderror#1#2{%
+ \PackageError{#1}{#2}{}%
+ }
+ \else
+ % Plain and eplain, or an unknown format.
+ \let\priminput\input
+ \let\primunexpanded\unexpanded
+ \def\loadmacrofile#1{\priminput#1 }
+ \def\senderror#1#2{%
+ \errmessage{#1 error: #2}%
+ }
+ \fi
+ \fi
+\fi
+%
+%
+%
+%
+% INTERNAL UTILITIES
+%
+\def\pdef{\protected\def}
+\def\pi@terminator{\senderror{texapi}{This shouldn't be happening}}
+\long\def\pi@gobbletoterminator#1#2\pi@terminator{#1} % I generally want something to happen after a terminator.
+%
+%
+%
+%
+% ARGUMENTS MANIPULATION
+%
+\long\def\gobbleone#1{} \long\def\gobbletwo#1#2{} \long\def\gobblethree#1#2#3{}
+\long\def\gobblefour#1#2#3#4{} \long\def\gobblefive#1#2#3#4#5{} \long\def\gobblesix#1#2#3#4#5#6{}
+\long\def\gobbleseven#1#2#3#4#5#6#7{} \long\def\gobbleeight#1#2#3#4#5#6#7#8{} \long\def\gobblenine#1#2#3#4#5#6#7#8#9{}
+%
+\long\def\gobbleoneand#1#2{#1} \long\def\gobbletwoand#1#2#3{#1} \long\def\gobblethreeand#1#2#3#4{#1}
+\long\def\gobblefourand#1#2#3#4#5{#1} \long\def\gobblefiveand#1#2#3#4#5#6{#1} \long\def\gobblesixand#1#2#3#4#5#6#7{#1}
+\long\def\gobblesevenand#1#2#3#4#5#6#7#8{#1} \long\def\gobbleeightand#1#2#3#4#5#6#7#8#9{#1}
+\long\def\gobblenineand#1#2#3#4#5#6#7#8#9{\gobbleoneand{#1}}
+%
+\long\def\unbrace#1{#1} \long\def\firstoftwo#1#2{#1} \long\def\secondoftwo#1#2{#2}
+%
+\long\def\swapargs#1#2{#2#1} \long\def\swapbraced#1#2{{#2}{#1}}
+\long\def\swapleftbraced#1#2{{#2}#1} \long\def\swaprightbraced#1#2{#2{#1}}
+%
+\long\def\passexpanded#1#2{\expandafter\swaprightbraced\expandafter{#2}{#1}}
+\long\def\passexpandednobraces#1#2{\expandafter\swapargs\expandafter{#2}{#1}}
+%
+\def\emptycs{} \def\spacecs{ }
+\bgroup
+\def\:{\global\let\spacechar= }\: %
+\egroup
+%
+%
+%
+%
+% COMMAND DEFINITIONS
+%
+% All the \...cs stuff must be \long, because
+% even though \par is (generally) unexpandable
+% it can be \string'ed.
+\long\def\usecs#1{\csname#1\endcsname}
+\long\def\usecsafter#1{\expandafter\expandafter\csname#1\endcsname}
+\long\def\noexpandcs#1{\expandafter\noexpand\csname#1\endcsname}
+\long\def\unexpandedcs#1{\primunexpanded\expandafter\expandafter\expandafter{\csname#1\endcsname}}
+\long\def\passcs#1#2{\expandafter\swapargs\csname#2\endcsname{#1}}
+\long\def\passexpandedcs#1#2{\passcs{\passexpanded{#1}}{#2}}
+\long\def\commandtoname#1{\expandafter\gobbleone\string#1}
+%
+\long\pdef\defcs#1{\expandafter\def \csname#1\endcsname}
+\long\pdef\edefcs#1{\expandafter\edef \csname#1\endcsname}
+\long\pdef\gdefcs#1{\expandafter\gdef \csname#1\endcsname}
+\long\pdef\xdefcs#1{\expandafter\xdef \csname#1\endcsname}
+\long\pdef\letcs#1{\expandafter\let \csname#1\endcsname}
+% If \csname#2\endcsname is undefined,
+% we don't want to set it to \relax.
+\long\pdef\lettocs #1#2{\ifcs{#2}{\expandafter\let\expandafter#1\csname#2\endcsname}{\let#1\somethingtottallyundefined}}
+\long\pdef\letcstocs #1#2{%
+ \ifcs{#2}
+ {\expandafter\expandafter\expandafter\let\expandafter\expandafter\csname#1\endcsname\csname#2\endcsname}
+ {\expandafter\let\csname#1\endcsname\somethingtotallyundefined}%
+ }
+%
+\long\pdef\addleft#1#2{%
+ \edef#1{\primunexpanded{#2}\primunexpanded\expandafter{#1}}%
+ }
+\long\pdef\eaddleft#1#2{%
+ \edef#1{#2\primunexpanded\expandafter{#1}}%
+ }
+\long\pdef\addleftcs#1#2{%
+ \edefcs{#1}{\primunexpanded{#2}\unexpandedcs{#1}}%
+ }
+\long\pdef\eaddleftcs#1#2{%
+ \edefcs{#1}{#2\unexpandedcs{#1}}%
+ }
+\long\pdef\addright#1#2{%
+ \edef#1{\primunexpanded\expandafter{#1}\primunexpanded{#2}}%
+ }
+\long\pdef\eaddright#1#2{%
+ \edef#1{\primunexpanded\expandafter{#1}#2}%
+ }
+\long\pdef\addrightcs#1#2{%
+ \edefcs{#1}{\unexpandedcs{#1}\primunexpanded{#2}}%
+ }
+\long\pdef\eaddrightcs#1#2{%
+ \edefcs{#1}{\unexpandedcs{#1}#2}%
+ }
+%
+%
+%
+% COMMAND TESTING
+%
+%
+\def\reverse#1{%
+ \ifcs{pi@reverse_\commandtoname#1}
+ {\usecs{pi@reverse_\commandtoname#1}}
+ {\senderror{texapi}{You can't use `\string\reverse' before `\string#1'}#1}%
+ }
+%
+\def\pi@ifdef_simple#1#2{%
+ \long\def#1##1{%
+ #2%
+ \expandafter\firstoftwo
+ \else
+ \expandafter\secondoftwo
+ \fi
+ }%
+ \defcs{pi@reverse_\commandtoname#1}{\expandafter\unless#1}%
+ % \iff... version
+ \long\defcs{if\expandafter\gobbletwo\string#1}##1{%
+ #2%
+ \expandafter\unbrace
+ \else
+ \expandafter\gobbleone
+ \fi
+ }%
+ \defcs{pi@reverse_if\expandafter\gobbletwo\string#1}{\passcs{\expandafter\unless}{if\expandafter\gobbletwo\string#1}}%
+ }
+%
+\pi@ifdef_simple\ifcommand{\ifdefined#1}
+\pi@ifdef_simple\ifcs{\ifcsname#1\endcsname}
+\pi@ifdef_simple\ifemptycommand{\ifx#1\emptycs}
+%
+\def\pi@ifdef_onearg#1{%
+ \long\defcs{pi@reverse_\commandtoname#1}##1##2##3{#1{##1}{##3}{##2}}%
+ % This is the \iff... version
+ \long\defcs{if\expandafter\gobbletwo\string#1}##1##2{#1{##1}{##2}{}}%
+ \long\defcs{pi@reverse_if\expandafter\gobbletwo\string#1}##1##2{#1{##1}{}{##2}}%
+ % In many cases, \long is better, otherwise it does no real harm.
+ \long\def#1##1%
+ }
+\pi@ifdef_onearg\ifemptycs{%
+ \ifcs{#1}
+% No point using \ifxcs, that would run useless tests.
+ {\expandafter\ifx\csname#1\endcsname\emptycs
+ \expandafter\firstoftwo
+ \else
+ \expandafter\secondoftwo
+ \fi}
+ \secondoftwo
+ }
+\def\pi@ifdef_twoarg#1{%
+ \long\defcs{pi@reverse_\commandtoname#1}##1##2##3##4{#1{##1}{##2}{##4}{##3}}%
+ \long\defcs{if\expandafter\gobbletwo\string#1}##1##2##3{#1{##1}{##2}{##3}{}}%
+ \long\defcs{pi@reverse_if\expandafter\gobbletwo\string#1}##1##2##3{#1{##1}{##2}{}{##3}}%
+ \long\def#1##1##2%
+ }
+%
+\pi@ifdef_twoarg\ifxcs{%
+ \ifcs{#1}
+ {\expandafter\ifx\csname#1\endcsname#2%
+ \expandafter\firstoftwo
+ \else
+ \expandafter\secondoftwo
+ \fi}
+ {\ifcommand#2\secondoftwo\firstoftwo}
+ }
+%
+\pi@ifdef_twoarg\ifxcscs{%
+ \ifcs{#1}
+ {\ifcs{#2}
+ {\passcs{\expandafter\ifx\csname#1\endcsname}{#2}%
+ \expandafter\firstoftwo\else\expandafter\secondoftwo\fi}
+ {\secondoftwo}}
+ {\ifcs{#2}
+ {\secondoftwo}
+ {\firstoftwo}}
+ }
+%
+%
+%
+%
+% CUSTOM \IF'S
+%
+\pdef\newife#1{%
+ \expandafter\passexpandednobraces\expandafter\pi@newif_strip\expandafter{\expandafter\gobbleone\string#1\pi@terminator}
+ }
+\bgroup
+\uccode`2=`i \uccode`3=`f
+\uppercase{
+ \gdef\pi@newif_strip23#1\pi@terminator{%
+ \pi@newif_def{#1}%
+ }
+ }
+\egroup
+%
+\def\pi@newif_def#1{%
+ \letcs{if#1}\secondoftwo
+ \long\edefcs{pi@reverse_if#1}##1##2{\noexpandcs{if#1}{##2}{##1}}%
+ \edefcs{iff#1}{\noexpandcs{if#1}\noexpand\unbrace\noexpand\gobbleone}%
+ \edefcs{pi@reverse_iff#1}{\noexpandcs{if#1}\noexpand\gobbleone\noexpand\unbrace}%
+ \defcs{#1true}{%
+ \letcs{if#1}\firstoftwo
+ }%
+ \defcs{#1false}{%
+ \letcs{if#1}\secondoftwo
+ }%
+ }
+%
+\long\def\straightenif#1#2{%
+ \usecs{#1}#2%
+ \expandafter\firstoftwo
+ \else
+ \expandafter\secondoftwo
+ \fi
+ }
+\long\def\straighteniff#1#2{%
+ \usecs{#1}#2%
+ \expandafter\unbrace
+ \else
+ \expandafter\gobbleone
+ \fi
+ }
+\long\def\pi@reverse_straightenif#1#2{%
+ \usecs{#1}#2%
+ \expandafter\secondoftwo
+ \else
+ \expandafter\firstoftwo
+ \fi
+ }
+\long\def\pi@reverse_straighteniff#1#2{%
+ \usecs{#1}#2%
+ \expandafter\gobbleone
+ \else
+ \expandafter\unbrace
+ \fi
+ }
+%
+%
+%
+%
+% This is dangerous. But useful to get
+% material across a conditional.
+%
+\long\def\afterfi#1#2\fi{\fi#1}
+\long\def\afterdummyfi#1#2\fi{#1}
+%
+%
+%
+%
+% WHAT COMES NEXT
+%
+\newtoks\pi@temp_tokenA
+\newtoks\pi@temp_tokenB
+\long\pdef\nospace#1{%
+ \pi@temp_tokenA={#1}%
+ \def\pi@nospace_repeat{%
+ \expandafter\nospace\expandafter{\the\pi@temp_tokenA}%
+ }%
+ \futurelet\pi@temp\pi@nospace_check
+ }
+\def\pi@nospace_check{%
+ \ifx\pi@temp\spacechar
+ \afterfi{%
+ \afterassignment\pi@nospace_repeat
+ \let\pi@temp= }%
+ \else
+ \expandafter\the\expandafter\pi@temp_tokenA
+ \fi
+ }
+%
+\def\pi@ifdef_next#1#2#3{%
+ \pdef#1{\pi@ifnext_any#2}%
+ \protected\defcs{\commandtoname#1nospace}{\pi@ifnext_nospace#2}%
+ \protected\defcs{if\expandafter\gobbletwo\string#1}{\pi@iffnext_any#2}%
+ \protected\defcs{if\expandafter\gobbletwo\string#1nospace}{\pi@iffnext_nospace#2}%
+% \reverse version
+ \protected\defcs{pi@reverse_\commandtoname#1}{\pi@ifnext_any#3}%
+ \protected\defcs{pi@reverse_\commandtoname#1nospace}{\pi@ifnext_nospace#3}%
+ \protected\defcs{pi@reverse_if\expandafter\gobbletwo\string#1}{\pi@iffnext_any#3}%
+ \protected\defcs{pi@reverse_if\expandafter\gobbletwo\string#1nospace}{\pi@iffnext_nospace#3}%
+ }
+%
+\def\pi@unlessif{\unless\if}
+\pi@ifdef_next\ifnext\if\pi@unlessif
+\def\pi@unlessifcat{\unless\ifcat}
+\pi@ifdef_next\ifcatnext\ifcat\pi@unlessifcat
+\def\pi@unlessifx{\expandafter\unless\pi@ifx}
+\pi@ifdef_next\ifxnext\pi@ifx\pi@unlessifx
+% We remove the \noexpand's.
+\long\def\pi@ifx#1#2#3#4{\ifx#2#4}
+% Would the following be faster?
+% \long\def\pi@ifx\noexpand#1\noexpand#2{\ifx#1#2}
+% I wonder.
+\long\def\pi@ifnext_any#1#2#3#4{%
+ \let\pi@ifnext_test=#1%
+ \let\pi@ifnext_token= #2%
+ \pi@temp_tokenA={#3}%
+ \pi@temp_tokenB={#4}%
+ \futurelet\pi@temp\pi@ifnext_do
+ }
+\long\def\pi@ifnext_nospace#1#2#3#4{%
+ \nospace{\pi@ifnext_any#1#2{#3}{#4}}%
+ }
+\long\def\pi@iffnext_any#1#2#3{%
+ \pi@ifnext_any#1#2{#3}{}%
+ }
+\long\def\pi@iffnext_nospace#1#2#3{%
+ \nospace{\pi@ifnext_any#1#2{#3}{}}%
+ }
+\def\pi@ifnext_do{%
+ \pi@ifnext_test\noexpand\pi@temp\noexpand\pi@ifnext_token
+ \expandafter\the\expandafter\pi@temp_tokenA
+ \else
+ \expandafter\the\expandafter\pi@temp_tokenB
+ \fi
+ }
+%
+%
+%
+%
+% FOR LOOPS
+%
+\newcount\pi@dofor_count
+\newif\ifpi@dofor_noempty
+\pdef\dofor{%
+ \pi@dofor_noemptyfalse\pi@dofor_getlist
+ }
+\pdef\dofornoempty{%
+ \pi@dofor_noemptytrue\pi@dofor_getlist
+ }
+\long\def\pi@dofor_getlist#1{%
+ \nospace{\pi@dofor_getparameter{#1}}%
+ }
+\long\def\pi@dofor_getparameter#1#2#{%
+ \pi@dofor_dolist{#1}{#2}%
+ }
+\long\def\pi@dofor_dolist#1#2#3{%
+% We keep count so loops can be nested.
+ \global\advance\pi@dofor_count1
+ \ifpi@dofor_noempty
+ \long\defcs{pi@dofor_loop\the\pi@dofor_count}#2{%
+ \ifemptystring{##1}
+ {\pi@dofor_control}
+ {#3\pi@newfor_markloop{pi@dofor_control}}%
+ }%
+ \else
+ \long\defcs{pi@dofor_loop\the\pi@dofor_count}#2{#3\pi@newfor_markloop{pi@dofor_control}}%
+ \fi
+ \pi@dofor_control#1\pi@terminator
+ }
+\def\pi@dofor_control{%
+ \ifxnext\pi@terminator
+ {\global\advance\pi@dofor_count-1
+% Unbrace the fourth argument.
+ \pi@gobbletoterminator\unbrace}
+ {\usecs{pi@dofor_loop\the\pi@dofor_count}}%
+ }
+\let\pi@dofor_originalcontrol\pi@dofor_control
+\let\resumedofor\pi@dofor_control
+\long\pdef\breakdofor#1#2\pi@dofor_control#3\pi@terminator{%
+ \global\advance\pi@dofor_count-1
+ % Gobble the fourth argument (executed if the loop lives to its own natural end).
+ \gobbleoneand{#1}%
+ }
+\def\pi@dofor_retrieverest#1#2\pi@terminator{%
+ \global\advance\pi@dofor_count-1
+ \gobbleoneand{#1{#2}}%
+ }%
+\long\pdef\pausedofor#1#2\pi@dofor_control{#1}
+%
+%
+%
+%
+% CUSTOM FOR LOOPS
+% And here's the big one.
+%
+\pdef\newfor#1{%
+ \pi@dofor_noemptyfalse
+ \ifcatnext\bgroup{\pi@newfor_pass{#1}}
+ {\pi@newfor_pass{#1}{0}}%
+ }
+\pdef\newfornoempty#1{%
+ \pi@dofor_noemptytrue
+ \ifcatnext\bgroup{\nospace{\pi@newfor_pass{#1}}}
+ {\nospace{\pi@newfor_pass{#1}{0}}}%
+ }
+\long\def\pi@newfor_pass#1#2#3#{%
+ \pi@newfor_getcoda{#1}{#2}{#3}
+ }
+\long\def\pi@newfor_getcoda#1#2#3#4{%
+ \ifnextnospace[{\pi@newfor_create{#1}{#2}{#3}{#4}}
+ {\pi@newfor_create{#1}{#2}{#3}{#4}[]}%
+ }
+\let\pi@newfor_pi@nf_tm_\relax
+\let\pi@nf_tm\pi@terminator
+\let\pi@newfor_preloop\emptycs
+\long\def\pi@newfor_create#1#2#3#4[#5]{%
+ \def\pi@temp##1##2##3##4##5##6##7##8##9{#3}%
+ \pi@temp_tokenA={\pi@newfor_define#1{#3}{#4}{#5}}%
+ \ifcase#2\relax
+ \the\pi@temp_tokenA 1{}{}{\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm}\unbrace
+ \or \the\pi@temp_tokenA 2{##1}{{##1}}{{}\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm}\gobbleoneand
+ \or \the\pi@temp_tokenA 3{##1##2}{{##1}{##2}}{{}{}\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm}\gobbletwoand
+ \or \the\pi@temp_tokenA 4{##1##2##3}{{##1}{##2}{##3}}{{}{}{}\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm}\gobblethreeand
+ \or \the\pi@temp_tokenA 5{##1##2##3##4}{{##1}{##2}{##3}{##4}}{{}{}{}{}\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm}\gobblefourand
+ \or \the\pi@temp_tokenA 6{##1##2##3##4##5}{{##1}{##2}{##3}{##4}{##5}}{{}{}{}{}{}\pi@nf_tm\pi@nf_tm\pi@nf_tm\pi@nf_tm}\gobblefiveand
+ \or \the\pi@temp_tokenA 7{##1##2##3##4##5##6}{{##1}{##2}{##3}{##4}{##5}{##6}}{{}{}{}{}{}{}\pi@nf_tm\pi@nf_tm\pi@nf_tm}\gobblesixand
+ \or \the\pi@temp_tokenA 8{##1##2##3##4##5##6##7}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}}{{}{}{}{}{}{}{}\pi@nf_tm\pi@nf_tm}\gobblesevenand
+ \or \the\pi@temp_tokenA 9{##1##2##3##4##5##6##7##8}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}}{{}{}{}{}{}{}{}{}\pi@nf_tm}\gobbleeightand
+ \else \senderror{texapi}{You can't have more than 8 passed arguments. Definition aborted}%
+ \fi
+ }
+%
+% \newfor\foo{<n>}<parameters>{<definition>}{<coda>}
+% |#1 |#2 |#3 |#4
+% #5 = <n>+1
+% #6 = ##1##2...##n
+% #7 = {##1}{##2}...{##n}
+% #8 = <parameters> with terminators as arguments, to mark the end of the loop.
+% #9 = \gobble<n>and
+%
+% So, for instance, something like \edef#1#6###5 means
+% (without the double hashes):
+% \edef\foo#1#2...#n#<n+1>, e.g. with n=3
+% \edef\foo#1#2#3#4
+% hence \foo{<first>}{<second>}{<third>}{<list>}
+% |_________ passed _________|
+%
+% and this calls:
+% \pi@newfor_userdefined:foo#7###5
+% => \pi@newfor_userdefined:foo{#1}{#2}{#3}#4<terminators>
+% => \pi@newfor_userdefined:foo{<first>}{<second>}{<third>}<list><terminators>
+% and of course \pi@newfor_userdefined:foo sees only the head of <list>.
+%
+% The first argument of <list> is tested to check whether it's a terminator
+% (and whether it's empty in the noempty case) in which case the <coda>,
+% i.e. #4, is executed. Otherwise <definition>, i.e. #3, is launched.
+%
+% \pi@newfor_markloop is just \usecs; but it's also a delimiter for
+% \breakfor, \passarguments, etc., i.e. it delimits the code to be gobbled.
+% \pi@newdor_preloop is a dummy macro that expands to nothing but which
+% is useful in one special case: viz. \passarguments{<arg>} with only one
+% argument passed, and at the end of a loop so that there's no intervening
+% code; \passarguments calls \getargs@pi@newfor_userdefined:foo on its
+% arguments, which should be properly braced; but because TeX removes
+% braces around delimited arguments that fit exactly into the delimiters,
+% \passarguments as just described would pass an unbraced argument, hence kertwang.
+% \pi@newfor_preloop ensures that <arg> is never the sole properly fitted
+% and hence unbracing-prone argument. It is then used by \getargs@pi@newfor_userdefined:foo
+% to remove remaining code, if any.
+%
+%
+%
+% The definition is pretty ugly, but it works, and
+% you should've seen what it looked like when I started.
+%
+\long\def\pi@newfor_define#1#2#3#4#5#6#7#8#9{%
+ \long\edef#1#6###5{%
+ \noexpandcs{pi@newfor_userdefined:\commandtoname#1}%
+ #7###5\primunexpanded\expandafter{\pi@temp#8\pi@terminator}%
+ }%
+ \ifpi@dofor_noempty
+ \long\defcs{pi@newfor_userdefined:\commandtoname#1}#6#2{%
+ \ifcs{pi@newfor_\commandtoname###5_}
+ {\pi@gobbletoterminator{#4}}%
+ {\ifemptystring{###5}
+ {\usecs{pi@newfor_userdefined:\commandtoname#1}#7}
+ {#3\pi@newfor_preloop\pi@newfor_markloop{pi@newfor_userdefined:\commandtoname#1}#7}}%
+ }%
+ \else
+ \long\defcs{pi@newfor_userdefined:\commandtoname#1}#6#2{%
+ \ifcs{pi@newfor_\commandtoname###5_}
+ {\pi@gobbletoterminator{#4}}
+ {#3\pi@newfor_preloop\pi@newfor_markloop{pi@newfor_userdefined:\commandtoname#1}#7}%
+ }%
+ \fi
+ \long\defcs{getargs@pi@newfor_userdefined:\commandtoname#1}#6###5\pi@newfor_preloop{%
+ #9{\usecs{pi@newfor_userdefined:\commandtoname#1}#7}%
+ }%
+ \passexpandednobraces{\long\defcs{retrievefor@pi@newfor_userdefined:\commandtoname#1}##1##2}%
+ {\pi@temp#8\pi@terminator}%
+ {\passexpanded{##1}{#9{}##2}}%
+ }
+%
+\long\def\pi@newfor_markloop#1{\usecs{#1}}
+\long\def\passarguments#1\pi@newfor_markloop#2{%
+ \usecs{getargs@#2}#1%
+ }
+\long\def\breakfor#1#2\pi@newfor_markloop#3#4\pi@terminator{%
+ \ifstring{#3}{pi@dofor_control}%
+ {\gobbleoneand{#1}}
+ {#1}%
+ }
+\long\def\pausefor#1#2\pi@newfor_markloop#3{#1}
+\long\def\resumefor#1{%
+ \ifstring{#1}{\dofor}
+ {\pi@dofor_control}
+ {\usecs{pi@newfor_userdefined:\commandtoname#1}}%
+ }
+\long\def\retrieverest#1#2\pi@newfor_markloop#3{%
+ \ifstring{#3}{pi@dofor_control}%
+ {\pi@dofor_retrieverest{#1}}
+ {\usecs{retrievefor@#3}{#1}}%
+ }
+%
+%
+%
+%
+% WHILE LOOPS
+%
+\long\def\repeatuntil#1{%
+ \pi@repeatuntil_loop{\numexpr(0)}{#1}%
+ }
+\long\def\pi@repeatuntil_loop#1#2#3{%
+ \ifnum#2>#1\relax
+ \expandafter\unbrace
+ \else
+ \expandafter\gobbleone
+ \fi
+ {#3\pi@repeatuntil_loop{\numexpr(#1+1)}{#2}{#3}}%
+ }
+%
+\long\def\dowhile#1#2{%
+ #1{#2\dowhile{#1}{#2}}{}%
+ }
+%
+%
+%
+%
+% CUSTOM WHILE LOOPS
+%
+% \newdowhile\foo<nb of args><trarg_1>...<trarg_n><body>
+% where <trarg_1>...<trarg_n> are the transformations of <arg_1>...<arg_n>
+% from one iteration to the next.
+%
+% The \newhile is basically a simple version of \newfor.
+%
+\long\pdef\newwhile#1#2{%
+ \def\pi@temp{#1}%
+ \ifcase#2
+ \expandafter\pi@newwhile_getzero
+ \or\expandafter\pi@newwhile_getone
+ \or\expandafter\pi@newwhile_gettwo
+ \or\expandafter\pi@newwhile_getthree
+ \or\expandafter\pi@newwhile_getfour
+ \or\expandafter\pi@newwhile_getfive
+ \or\expandafter\pi@newwhile_getsix
+ \or\expandafter\pi@newwhile_getseven
+ \or\expandafter\pi@newwhile_geteight
+ \or\expandafter\pi@newwhile_getnine
+ \fi
+ }
+\long\def\pi@newwhile_getzero{%
+ \expandafter\pi@newwhile_create\pi@temp{}{}{}\unbrace}
+\long\def\pi@newwhile_getone#1{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1}{{##1}}{{#1}}\gobbleoneand}
+\long\def\pi@newwhile_gettwo#1#2{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1##2}{{##1}{##2}}{{#1}{#2}}\gobbletwoand}
+\long\def\pi@newwhile_getthree#1#2#3{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1##2##3}{{##1}{##2}{##3}}{{#1}{#2}{#3}}\gobblethreeand}
+\long\def\pi@newwhile_getfour#1#2#3#4{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1##2##3##4}{{##1}{##2}{##3}{##4}}{{#1}{#2}{#3}{#4}}\gobblefourand}
+\long\def\pi@newwhile_getfive#1#2#3#4#5{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1##2##3##4##5}{{##1}{##2}{##3}{##4}{##5}}{{#1}{#2}{#3}{#4}{#5}}\gobblefiveand}
+\long\def\pi@newwhile_getsix#1#2#3#4#5#6{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1##2##3##4##5##6}{{##1}{##2}{##3}{##4}{##5}{##6}}{{#1}{#2}{#3}{#4}{#5}{#6}}\gobblesixand}
+\long\def\pi@newwhile_getseven#1#2#3#4#5#6#7{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1##2##3##4##5##6##7}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}}{{#1}{#2}{#3}{#4}{#5}{#6}{#7}}\gobblesevenand}
+\long\def\pi@newwhile_geteight#1#2#3#4#5#6#7#8{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1##2##3##4##5##6##7##8}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}}{{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}}\gobbleeightand}
+\long\def\pi@newwhile_getnine#1#2#3#4#5#6#7#8#9{%
+ \expandafter\pi@newwhile_create
+ \pi@temp{##1##2##3##4##5##6##7##8##9}{{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}{##9}}{{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}\gobblenineand}
+%
+%
+% \newwhile\foo<n><trans_1><trans_2>...<trans_n><body>
+%
+% Below:
+% #1 = \foo
+% #2 = ##1##2...##n
+% #3 = {##1}{##2}...{##n}
+% #4 = <trans_1><trans_2>...<trans_n>
+% #5 = \gobble<n>and
+% #6 = <body>
+%
+% ... so that \foo (#1) takes <n> arguments (#2), executes <body> (#6),
+% and runs its internal version (...newhile_userdefined...) on these same arguments
+% properly braced (#3). This internal version takes of course <n> arguments
+% and returns \foo with the arguments transformed (#4).
+% ..._preloop and ..._markloop are just markers, although the is equivalent to \usecs
+% so as to launch the following macro.
+%
+\long\def\pi@newwhile_create#1#2#3#4#5#6{%
+ \long\def#1#2{%
+ #6\pi@newwhile_preloop\pi@newwhile_markloop{pi@newwhile_userdefined:\commandtoname#1}#3%
+ }%
+ \long\defcs{pi@newwhile_userdefined:\commandtoname#1}#2{#1#4}%
+ \long\defcs{changewhile@pi@newwhile_userdefined:\commandtoname#1}#2{\pi@gobbletoterminator{#5{#1#3}}}%
+ \letcs{breakwhile@pi@newwhile_userdefined:\commandtoname#1}#5%
+ }
+%
+\let\pi@newwhile_preloop\emptycs
+\let\pi@newwhile_markloop\usecs
+\long\def\changewhile#1\pi@newwhile_markloop#2{%
+ \usecs{changewhile@#2}#1\pi@terminator
+ }
+\long\def\breakwhile#1#2\pi@newwhile_markloop#3{%
+ \usecs{breakwhile@#3}{#1}%
+ }
+%
+%
+%
+%
+% CATCODE SETTINGS
+%
+\pdef\setcatcodes#1{%
+ \ifsuffix,{#1}{\pi@setcatcodes_loop{#1}}
+ {\pi@setcatcodes_loop{#1,}}%
+ }
+\def\restorecatcodes{%
+ \def\restorecatcodes{}%
+ }
+\def\pi@setcatcodes_loop#1{%
+ \dofor{#1}##1=##2,{%
+ \dofor{##1}####1{%
+ \ifemptycommand\restorecatcodes
+ {\def\restorecatcodes{\def\restorecatcodes{}}}%
+ {}%
+ \eaddright\restorecatcodes{%
+ \catcode`\noexpand####1=\the\catcode`####1\relax}%
+ \catcode`####1=##2\relax}{}}{}%
+ }
+%
+%
+%
+%
+% STRINGS
+%
+\let\pi@thisisjustanemptystring_donottouchit\relax
+\pi@ifdef_simple\ifemptystring{\ifcsname pi@thisisjustanemptystring_donottouchit\detokenize{#1}\endcsname}
+%
+\pi@ifdef_twoarg\ifstring{%
+ \passcs\gobbleone{pi@ifstring_string\detokenize{#1:#1}}%
+ \ifcs{pi@ifstring_string\detokenize{#1:#2}}
+ }
+%
+\long\pdef\newstring#1{%
+ \long\gdefcs{pi@strings_ifprefix:\detokenize{#1}}##1#1##2\pi@terminator{%
+ \ifemptystring{##1}\firstoftwo\secondoftwo}%
+ \long\gdefcs{pi@strings_removeprefix:\detokenize{#1}}#1##1\pi@terminator{##1}%
+ \long\gdefcs{pi@strings_removeprefixand:\detokenize{#1}}#1##1\pi@terminator##2{##2{##1}}%
+%
+ \long\gdefcs{pi@strings_ifsuffix:\detokenize{#1}}##1#1\pi@terminator##2\pi@terminator{%
+ \ifemptystring{##2}\secondoftwo{\pi@gobbletoterminator\firstoftwo}}%
+ \long\gdefcs{pi@strings_removesuffix:\detokenize{#1}}##1#1\pi@terminator{##1}%
+ \long\gdefcs{pi@strings_removesuffixand:\detokenize{#1}}##1#1\pi@terminator##2{##2{##1}}%
+%
+ \long\gdefcs{pi@strings_ifcontains:\detokenize{#1}}##1#1##2\pi@terminator{%
+ \ifemptystring{##2}\secondoftwo\firstoftwo}%
+ \long\gdefcs{pi@strings_splitstring:\detokenize{#1}}##1#1##2\pi@terminator##3{%
+ ##3{##1}{##2}}%
+ }
+%
+\pi@ifdef_twoarg\ifprefix{%
+ \ifemptystring{#1}\firstoftwo
+ {\ifcs{pi@strings_ifprefix:\detokenize{#1}}
+ {\usecs{pi@strings_ifprefix:\detokenize{#1}}#2#1\pi@terminator}
+ {\long\def\pi@temp##1#1##2\pi@terminator{\ifemptystring{##1}\firstoftwo\secondoftwo}%
+ \pi@temp#2#1\pi@terminator}}
+ }
+%
+\pi@ifdef_twoarg\ifsuffix{%
+ \ifemptystring{#1}\firstoftwo % An empty string is always a suffix. And it'd ruin the test.
+ {\ifcs{pi@strings_ifsuffix:\detokenize{#1}}
+ {\usecs{pi@strings_ifsuffix:\detokenize{#1}}#2\pi@terminator#1\pi@terminator\pi@terminator}
+ {\long\def\pi@temp##1#1\pi@terminator##2\pi@terminator{\ifemptystring{##2}\secondoftwo{\pi@gobbletoterminator\firstoftwo}}%
+ \pi@temp#2\pi@terminator#1\pi@terminator\pi@terminator}}
+ }
+%
+\pi@ifdef_twoarg\ifcontains{%
+ \ifemptystring{#1}\firstoftwo
+ {\ifcs{pi@strings_ifcontains:\detokenize{#1}}
+ {\usecs{pi@strings_ifcontains:\detokenize{#1}}#2#1\pi@terminator}
+ {\long\def\pi@temp##1#1##2\pi@terminator{\ifemptystring{##2}\secondoftwo\firstoftwo}%
+ \pi@temp#2#1\pi@terminator}}
+ }
+%
+\long\def\removeprefix#1#2{%
+ \ifcs{pi@strings_removeprefix:\detokenize{#1}}
+ {\usecs{pi@strings_removeprefix:\detokenize{#1}}#2\pi@terminator}
+ {\long\def\pi@temp#1##1\pi@terminator{##1}%
+ \pi@temp#2\pi@terminator}%
+ }
+\long\def\removeprefixand#1#2#3{%
+ \ifcs{pi@strings_removeprefixand:\detokenize{#1}}
+ {\usecs{pi@strings_removeprefixand:\detokenize{#1}}#2\pi@terminator{#3}}
+ {\long\def\pi@temp#1##1\pi@terminator{#3{##1}}%
+ \pi@temp#2\pi@terminator}%
+ }
+\long\pdef\removeprefixin#1#2#3{%
+ \long\def\pi@temp#1##1\pi@terminator{\def#3{##1}}%
+ \pi@temp#2\pi@terminator
+ }
+%
+\long\def\removesuffix#1#2{%
+ \ifcs{pi@strings_removesuffix:\detokenize{#1}}
+ {\usecs{pi@strings_removesuffix:\detokenize{#1}}#2\pi@terminator}
+ {\long\def\pi@temp##1#1\pi@terminator{##1}%
+ \pi@temp#2\pi@terminator}%
+ }
+\long\def\removesuffixand#1#2#3{%
+ \ifcs{pi@strings_removesuffixand:\detokenize{#1}}
+ {\usecs{pi@strings_removesuffixand:\detokenize{#1}}#2\pi@terminator{#3}}
+ {\long\def\pi@temp##1#1\pi@terminator{#3{##1}}%
+ \pi@temp#2\pi@terminator}%
+ }
+\long\pdef\removesuffixin#1#2#3{%
+ \long\def\pi@temp##1#1\pi@terminator{\def#3{##1}}%
+ \pi@temp#2\pi@terminator
+ }
+%
+\long\def\splitstring#1#2#3{%
+ \ifcs{pi@strings_splitstring:\detokenize{#1}}
+ {\usecs{pi@strings_splitstring:\detokenize{#1}}#2\pi@terminator{#3}}
+ {\long\def\pi@temp##1#1##2\pi@terminator{#3{##1}{##2}}%
+ \pi@temp#2\pi@terminator}%
+ }
+%
+%
+%
+%
+% TRIMMING
+% (adapted from Will Robertson's trimspace)
+%
+\long\def\passtrimleft#1#2{%
+ \expandafter\swaprightbraced\expandafter{\romannumeral-`\.\noexpand#1}{#2}%
+ }
+\def\trimleft#1{%
+ \passtrimleft{#1}\unbrace
+ }
+\bgroup
+\catcode`\Q=3
+\long\gdef\passtrimright#1{%
+ \pi@passtrimright_first#1Q Q%
+ }%
+\long\gdef\pi@passtrimright_first#1 Q{%
+ \pi@passtrimright_second#1Q%
+ }
+\long\gdef\pi@passtrimright_second#1Q#2#3{%
+ #3{#1}%
+ }
+\egroup
+\def\trimright#1{%
+ \passtrimright{#1}\unbrace
+ }
+\long\def\passtrim#1{%
+ \passtrimleft{#1}\passtrimright
+ }
+\def\trim#1{%
+ \passtrim{#1}\unbrace
+ }
+\long\pdef\deftrimleft#1#2{%
+ \passtrimleft{#2}{\def#1}
+ }
+\long\pdef\deftrimright#1#2{%
+ \passtrimright{#2}{\def#1}
+ }
+\long\pdef\deftrim#1#2{%
+ \passtrim{#2}{\def#1}%
+ }
+
+\pi@restorecatcodes
+\endinput \ No newline at end of file