%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% % This is file 'loops.sty', version 1.1, October 2012. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % % either version 1.3 of this license or any later version. The latest % % version of this license is in http://www.latex-project.org/lppl.txt % % and version 1.3 or later is part of all distributions of LaTeX % % version 2005/12/01 or later. % % % % The LPPL maintenance status of this software is 'author-maintained'. % % % % This software is provided 'as it is', without warranty of any kind, % % either expressed or implied, including, but not limited to, the % % implied warranties of merchantability and fitness for a particular % % purpose. % % % % Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup \catcode035 06 % # \catcode064 11 % @ \catcode123 01 % { \catcode125 02 % } \catcode044 12 % , \def\skv@prova{\endgroup \def\do##1,{% \ifx\do##1\else \catcode##1\string=\the\catcode##1\relax \expandafter\do \fi }% \edef\loops@restorecodes{\do035,064,123,125,061,059,\do,}% } \skv@prova \catcode035 06 % # \catcode064 11 % @ \catcode123 01 % { \catcode125 02 % } \catcode061 12 % = \catcode044 12 % , \def\do#1=#2,{% \ifx#1\do\else \edef\loops@restorecodes{% \loops@restorecodes \catcode#1=\the\catcode#1\relax }% \catcode#1=#2\relax \expandafter\do \fi } \do 032=10,033=12,036=03,038=04,040=12,041=12,042=12,043=12,% 059=12,045=12,047=12,058=12,063=12,091=12,093=12,126=13,\do=,% \ProvidesPackage{loops}[2012/10/14 v1.1 Loops and list processors (AM)] \NeedsTeXFormat{LaTeX2e}[2011/06/27] % This is the way to load 'skeyval-for-core' here, otherwise we % can't access some of the needed commands from 'skeyval-core': \@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}} \skvnewlet\ltxkernelfor\@for \skvnewlet\ltxkerneltfor\@tfor % \skvusetwoprev{}{}{}{} % % Example: % % \skvusetwoprev{,}{a,b,c,d,e,f}{e}{} % \skvrobustdef*\skvusetwoprev#1#2#3#4{% \skvifin{#1#3#1}{#1#2#1}{}{% \skv@err{There is not '\detokenize{#3}' in the list}\@ehd }% \let\firstprev\@empty \let\secondprev\@empty \def\skv@tempa{#3}% \def\skv@do##1#1{% \ifx\skv@nnil##1\else \def\current{##1}% \ifx\current\skv@tempa #4\relax \def\skv@do####1\skv@nnil#1{}% \else \let\secondprev\firstprev \let\firstprev\current \fi \expandafter\skv@do \fi }% \skv@do#2#1\skv@nnil#1% } % A version of D.E. Knuth's \loop: % \skvnewdef\dekloop#1\repeat{\skv@dekloop{#1}} \skvnewdef\skv@dekloop#1{% #1\relax \expandafter\skv@dekloop \else \expandafter\@gobble \fi {#1}% } % A version of D.E. Knuth's \loop that can be nested. % Credit: David P. Carlisle. % % \carlisleloop\a % \carlisleloop\b % ... % \if... % \repeat\b % ... % \if... % \repeat\a % \let\repeat\fi \skvrobustdef*\carlisleloop#1{% \long\def\skv@carlisleloop##1##2\repeat#1{% \long\def##1{##2\relax\expandafter##1\fi}% ##1\let##1\relax }% \expandafter\skv@carlisleloop \csname skv@carlisleloop@\string#1\endcsname } % A version of D.E.Knuth's \loop that can be nested naturally. % % 1. As a design constraint, this doesn't accept \par. % % 2. ak=Wilhelm Ackermann, ter=Rózsa Péter; in honour of these % mathematicians. % % \akterloop % \akterloop % ... % \if... % \repeat % ... % \if... % \repeat % \skvnewregister\toks\skv@aktertoks \skvnewdef*\skv@aktercnt{0} \skvrobustdef*\skv@akter@defloop{% \def\skv@tempa##1##2##3{% \def\skv@tempa{##1}% \def\skv@tempb{##2}% \let##2\fi \gdef##1####1##2{% \def##3{####1\relax\expandafter##3\fi}% ##3\let##3\relax }% }% \def\x##1{% \skvnoexpandcs{skv@akter@##1@\skvrom\skv@aktercnt}% }% \edef\x{\x{loop}\x{repeat}\x{iterate}}% \expandafter\skv@tempa\x } \skvrobustdef*\akterloop{% \begingroup \everyeof{EOF}\def\skv@aktercnt{0}% \skv@aktertoks{\dekloop}% \skv@akterpush } \skvrobustdef*\skv@akterpush{\futurelet\next\skv@akterpush@a} % Use star variant of \skvrobustdef here, to catch \par: \skvrobustdef*\skv@akterpush@a#1{% \skvifntype{#1}{% \skvifx{#1}\akterloop{% \skvadvanceno\skv@aktercnt\@ne \skv@akter@defloop \skv@aktertoks\expandafter {\the\expandafter\skv@aktertoks\skv@tempa}% \skv@akterpush }{% \skvifstrcmp{#1}\repeat{% \skvifnum\skv@aktercnt=\skvz@{% \expandafter\endgroup\the\skv@aktertoks\repeat }{% \skv@aktertoks\expandafter {\the\expandafter\skv@aktertoks\skv@tempb}% \skvadvanceno\skv@aktercnt\m@ne \skv@akterpush }% }{% \skvifx\next\@sptoken{% \skv@aktertoks\expandafter {\the\expandafter\skv@aktertoks\@space#1}% }{% \skv@aktertoks\expandafter{\the\skv@aktertoks#1}% }% \skv@akterpush }% }% }{% \skvifstrcmp{#1}{EOF}{% \skv@err{'\string\repeat' not found: endless loop}\@ehd }{% \skvifx\next\@sptoken{% \skv@aktertoks\expandafter {\the\expandafter\skv@aktertoks\space{#1}}% }{% \skv@aktertoks\expandafter{\the\skv@aktertoks{#1}}% }% \skv@akterpush }% }% } % Expandable comma loop. List is not normalized prior to parsing, and % it is not possible to terminate the loop prematurely. % % \skvfor{} % % Example: % % \skvnewregister\count\nr\nr=\tw@ % \def\do#1{% % \let\noexpand#1% % \expandafter\noexpand\csname\skvremovescape{#1}@% % \romannumeral\nr\endcsname % } % \edef\x{\skvfor{\cmda,\cmdb}\do} % \show\x -> \let\cmda\cmda@ii \let\cmdb\cmdb@ii % \skvnewdef\skvfor#1#2{\skv@for@a{#2}#1,\skv@for@nil,} \skvnewdef\skv@for@a#1#2,{% \skvifblank{#2}{% \skv@for@a{#1}% }{% \skvifstrcmp{#2}\skv@for@nil{}{#1{#2}\skv@for@a{#1}}% }% } % Process non-separated (token-wise) list: % % \ayeloop{}\do{<1.parameter.callback>} % \ayeloop*{}\do{<1.parameter.callback>} % % \ayeloop abcd\do{% % \def\nr{0}% % \ayeloop 12345\do{% % \typeout{Doing #1--##1}% % \skvpushnumber\nr % \ifnum\nr>3\relax\skvbreakloop\fi % }% % }% % % \ayeloop is like \skvtfor but uses parameter characters directly, % instead of a holder macro. % \skvrobustdef*\ayeloop{\skv@testst\skv@ayeloop} \skvrobustdef*\skv@ayeloop#1\do#2{% \skv@usetempst{#1}\skv@tempa \skvsavestate\ayeloop{\do\skv@ayeloop}\skv@csvdepth \def\skv@ayeloop##1{% \skvifstrcmp{##1}\skv@tfor@nil{% \skvbreakloopfalse }{% #2\relax \ifskvbreakloop \skvbreakloopfalse \begingroup \def\skv@ayeloop####1\skv@tfor@nil{% \endgroup \edef\skvremainder{\unexpanded{####1}}% }% \fi \skv@ayeloop }% }% \skvbreakloopfalse \expandafter\skv@ayeloop\skv@tempa\skv@tfor@nil \skvrestorestate\ayeloop\skv@csvdepth } % Robust, outer-brace-preserving, multi-level, general-purpose % non-separated values list (nsv) processor. % % \sifakaloop{}{<1.parameter.callback>} % \sifakaloop*{}{<1.parameter.callback>} % \skvnewdef*\skv@tsvnil{\skv@tsvnil} \skvrobustdef*\sifakaloop{\skv@testst\skv@sifakaparse@a} \skvrobustdef*\skv@sifakaparse@a#1#2{% \skv@usetempst{#1}\skv@sifakaarg \skvsavestate\sifakaloop{\do\skv@user@do}\skv@csvdepth \def\skv@user@do##1{#2}% \edef\skv@sifakaarg{% \expandafter\skvtsvnormalize\expandafter{\skv@sifakaarg}% }% \skvbreakloopfalse \skvifempty\skv@sifakaarg{% \ifskvprocessempty\skv@user@do{}\fi }{% \expandafter\skv@sifakaparse@b\skv@sifakaarg\skv@tsvnil }% \skvrestorestate\sifakaloop\skv@csvdepth \ifnum\skv@csvdepth=\skvz@\skvundef\skv@user@do\fi } \skvrobustdef*\skv@sifakaparse@b{% \begingroup \let\bgroup\relax \skvifnextchar\skv@orig@bgroup{% \let\skv@next\skv@orig@bgroup \skv@sifakaparse@c }{% \let\skv@next\relax \skv@sifakaparse@c }% } \skvrobustdef*\skv@sifakaparse@c#1{% \skvifx\skv@next\skv@orig@bgroup{% \endgroup \edef\skv@sifakaarg{{\unexpanded{#1}}}% }{% \endgroup \edef\skv@sifakaarg{\unexpanded{#1}}% }% \skvifx\skv@sifakaarg\skv@tsvnil{% \skvbreakloopfalse }{% \skvifx\skv@sifakaarg\skv@listbreakertoks{% \skvbreakloop }{% \skvifempty\skv@sifakaarg{% \ifskvprocessempty\skv@user@do{}\fi }{% \expandafter\skv@user@do\expandafter{\skv@sifakaarg}\relax }% \skvifdefbool{skvbreakloop}{% \skvbreakloopfalse \begingroup \def\skv@prova##1\skv@tsvnil{% \endgroup \edef\skvremainder{\unexpanded{##1}}% }% \skv@prova }{% \skv@sifakaparse@b }% }% }% } % Processing both csv and tsv/nsv lists with \foxloop. % % \foxloop[]{}{} % \foxloop*[]{}{} % % 1. The is at least a one-parameter token list. % % 2. \breakfoxloop can be used to break out of the loop. % % 3. When the argument is more than one (say, #1#2), the last one % must be delimited by the user-suggested . % % 4. To permit nesting we use a stack involving the counter \foreachdepth, % with alias \foxloopdepth. % % 5. \subcallback is meant for callbacks with hash characters that may be % confused with the parameters of the main . It can be defined % outside and called within . % % 6. Outer braces around the list items are preserved in the parsing. % % 7. 'fox' is used here to represent an item. Eg, \currentfox, \nextfox, % \foxcount. % \skvnewdef*\skv@foxloop@nnil{\skv@foxloop@nil} \skvnewbools{lastfox} \skvnewlet\breakfoxloop\skvbreaklooptrue \skvnewdef*\foxloopdepth{\foreachdepth} \skvnewdef*\foxcount{\foreachitemcount} \skvnewdef*\currentfox{\foreachcurrentitem} \skvnewdef*\nextfox{\foreachnextitem} \skvnewdef*\previousfox{\foreachprevitem} \skvnewdef*\foxlistremainder{\foreachlistremainder} \skvnewdef*\prependtobeginfoxloop{\prependtobeginforeach} \skvnewdef*\appendtobeginfoxloop{\appendtobeginforeach} \skvnewdef*\prependtoendfoxloop{\prependtoendforeach} \skvnewdef*\appendtoendfoxloop{\appendtoendforeach} % Define \foxloop keys. Name all the macros with 'foreach' prefix so % that we can avoid new command names and use the list auto-completion % scheme of \newforeach. \quickkeys.define{skvfoxloop}{% parser/{,}/ \def\skv@foreach@parser{#1} \skvstripouterbraces{2}\skv@foreach@parser ; list is a macro,macro list/true/ \edef\skv@foreach@listismacro{0\skvifstrcmp{#1}{true}01} /true,false ; list type/csv/ \def\skv@foreach@listtype{#1} /csv,kv,tsv,nsv ; arg,args,arg pattern/##1/ \edef\skv@foreach@paramlist{\unexpanded{#1}} \skvstripouterbraces{1}\skv@foreach@paramlist ; list breaker/\listbreaker/\def\skv@listbreakertoks{#1}; list pauser/\listpauser/\def\skv@listpausertoks{#1}; normalize list/true/ \edef\skv@foreach@normalizelist{0\skvifstrcmp{#1}{true}01} /true,false ; use empty,use empty items/true/ \edef\skv@foreach@useempty{0\skvifstrcmp{#1}{true}01} /true,false ; .exec/ \let\skv@foreach@exittester\@secondoftwo ; loop stopper,exit when/\if01\fi/ \ifskvindef\else \edef\skv@tempa{\unexpanded{#1}} \skvstripouterbraces{2}\skv@tempa \expandafter\skv@foreach@maketester\expandafter {\skv@tempa}\skv@foreach@exittester \fi ; item counter,counter/\@nil/ \def\skv@foreach@itemcounter{#1} ; % This default value of 'link' is required by \skv@foreach@filllist: .exec/\def\skv@foreach@link{\@nil}; link/\@nil/ \ifskvindef\else \edef\skv@foreach@link{\unexpanded{#1}} \skvstripouterbraces{2}\skv@foreach@link \ifnum0>\numexpr0\ifx\skv@foreach@link\@empty-1\else \ifx\skv@foreach@link\@nnil-1\else+0\fi\fi\relax\relax \skv@err{The key 'link' doesn't accept empty/blank values}\@ehd \fi \fi ; grow/\@nil/ \ifskvindef\else \edef\skv@prova{\unexpanded{#1}}% \ifx\skv@prova\@nnil \skv@err{Value required for key 'grow'}\@ehd \else \skvcsedef{skv@foreach@grow#1}{00}% \edef\skv@prova{\skvifstrcmp{#1}{left}{right}{left}}% \skvcsedef{skv@foreach@grow\skv@prova}{01}% \fi \fi /left,right ; .exec/ \def\skv@foreach@growleft{01}% \def\skv@foreach@growright{01}% ; grow left/true/ \ifskvindef\else \edef\skv@foreach@growleft{0\skvifstrcmp{true}{#1}01}% \edef\skv@foreach@growright{0\skvifstrcmp{true}{#1}10}% \fi /true,false ; grow right/true/ \ifskvindef\else \edef\skv@foreach@growright{0\skvifstrcmp{true}{#1}01}% \edef\skv@foreach@growleft{0\skvifstrcmp{true}{#1}10}% \fi /true,false ; % Keep the decimals in rounded numbers or dimensions when list is % auto-completed. The value value of this key is 'true'. keep decimals/true/ \edef\skv@foreach@keepdecimals{0\skvifstrcmp{true}{#1}01}% /true,false ; keep high decimals,keep only high decimals/true/ \edef\skv@foreach@keephighdecimals{0\skvifstrcmp{true}{#1}01}% /true,false ; expand before fill/true/ \edef\skv@foreach@expandbeforefill{0\skvifstrcmp{true}{#1}01}% /true,false ; % Eg, 'evaluate = #1 as \x using \numexpr#1*2'. % Since the parameters haven't assumed arguments, we defer the % call to \skv@fox@parseevaluate until the arguments are known. evaluate/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@fox@parseevaluate{#1}% }% ; % Eg, % 'count in = \p all #1 satisfying \ifnum#1>4\fi initially 2' % 'count in = \p all #1 satisfying \ifnum#1>4\fi' count in,count/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@fox@parsecountin{#1}% }% ; % Eg, remember=#1 as \y initially A remember/\@nil/ \skv@foreach@ifacceptkv{#1}{% \skv@fox@parseremember{#1}% }% ; reverse list,reverse/true/ \edef\skv@foreach@reverselist{0\skvifstrcmp{true}{#1}01}% /true,false ; } % Set up \foxloop defaults: \quickkeys.set{skvfoxloop}{% parser={,}, list is a macro=false, list type=csv, arg=#1, list breaker=\listbreaker, list pauser=\listpauser, normalize list=true, use empty=false, keep decimals=true, keep high decimals=false, expand before fill=false, reverse list=false, } % Parser for 'evaluate' key: % % Eg, 'evaluate = #1 as \x using \numexpr#1*2'. % % \skv@fox@parseevaluate differs from \skv@foreach@parseevaluate % because #1 here is likely to be a non-macro. % \skvrobustdef*\skv@fox@parseevaluate#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifin{\detokenize{##1}}{\detokenize{##2}}% }% \def\skv@tempd{}% % #3 can be empty. So we don't test for its emptiness here. \def\skv@tempa##1as##2using##3\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% \edef\skv@provb{\skvtrimspace{##2}}% \edef\skv@provc{\skvtrimspace{##3}}% \ifx\skv@prova\@empty \skv@err{Value of key 'evaluate': \MessageBreak no quantity to evaluate}\@ehd \fi \ifx\skv@provb\@empty \skv@err{Value of key 'evaluate' has no receiving macro, \MessageBreak i.e., after 'as'}\@ehd \else \expandafter\skvifescaped\expandafter{\skv@provb}{}{% \skv@err{Value of key 'evaluate': receiving macro \MessageBreak \skvoxdetok\skv@provb not escaped}\@ehd }% \fi \ifx\skv@provc\@empty \skv@err{Value of key 'evaluate' has no formula}\@ehd \fi \skv@tempxifin{\pgfmathparse}{##3}{% \def\skv@tempc####1\pgfmathparse####2\skv@nil{% \ifx\@nnil####1\@nnil \ifdefined\pgfmathparse \skv@foreach@swatrue \else \skv@err{\noexpand\pgfmathparse isn't defined; \MessageBreak maybe 'pgfmath' isn't loaded}\@ehd \fi \else \skv@err{Invalid token \detokenize{####1} \MessageBreak before \string\pgfmathparse}\@ehd \fi }% \expandafter\skv@tempc\skv@provc\skv@nil }{% \skv@foreach@swafalse \skv@tempxifin{\numexpr}{##3}{% \def\skv@tempd{\relax}% }{% \skv@tempxifin{\dimexpr}{##3}{% \def\skv@tempd{\relax}% }{% \def\skv@tempd{}% }% }% }% }% \skv@tempxifin{using}{#1}{% \skv@tempxifin{as}{#1}{% % 'as' and 'using' are present: there is a formula. \skv@foreach@swbtrue \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'evaluate': \MessageBreak there is 'using', but no 'as'}\@ehd }% }{% % No formula given: \skv@foreach@swbfalse \skv@tempxifin{as}{#1}{% \def\skv@tempb##1as##2##3\skv@nil{% \ifx\@nnil##1\@nnil \skv@err{Value of key 'evaluate' has no \MessageBreak quantity to evaluate}\@ehd \else \ifx\@nnil##2% \skv@err{Value of key 'evaluate' has no receiving macro}\@ehd \else \skv@tempa##1as##2using##1\skv@nil \fi \fi }% \skv@tempb#1{\@nnil}\skv@nil }{% % No 'as' or 'using'. In \foxloop, #1 is not guaranteed % to be a macro. Hence raise error here: \skv@err{Value of key 'evaluate' has no 'as'}\@ehd }% }% \skv@foreach@addtocallback{pre}{% \ifskv@foreach@swa % Here, may have the syntax \pgfmathresult{}. \skvexpandonce\skv@provc \let\skvexpandonce\skv@provb\noexpand\pgfmathresult \else % Here, may have the syntax \numexpr\x*2 or \dimexpr\x*2. \edef\skvexpandonce\skv@provb{% \ifskv@foreach@swb\noexpand\the\fi \skvexpandonce\skv@provc\skvexpandonce\skv@tempd }% \fi }% \skvaftergroupdef\skv@foreach@precallback\endgroup } % Eg, 'count in \y all #1 satisfying \ifnum#1>2\fi initially 0'. % % 1. must be a balanced and valid TeX or LaTeX (2-fork) % conditional, like % % \ifnum\x>2\fi, \ifx\x\@empty\fi % % 2. The aim is to allow general conditions (not only those involving % numerals) to be submitted. % % 3. PGF's \foreach doesn't have this feature; it has only a general % counter, eg, % % '\foreach \x [count=\xi from 2] in {a,...,e}'. % % Generic counting is available in \foxloop by default, without % user request. The macros \currentfox, \foxcount, \nextfox are % always available on each nesting level. The boolean \iflastfox % is also always available, to indicate when the last item of % the list has been reached: % % \iflastfox\typeout{Processing last entry of the list} \fi % \skvrobustdef*\skv@fox@parsecountin#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifin{\detokenize{##1}}{\detokenize{##2}}% }% \def\skv@tempa##1\skv@nil{% \skv@tempxifin{initially}{##1}{% \skv@tempb##1\skv@nil }{% \skv@tempb##1initially\skv@nil }% }% \def\skv@tempb##1all##2satisfying##3initially##4\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% \edef\skv@provb{\skvtrimspace{##2}}% \edef\skv@provc{\skvtrimspace{##3}}% \edef\skv@provd{\skvtrimspace{##4}}% \ifx\skv@prova\@empty \skv@err{Value of key 'count' has no counter macro}\@ehd \else \expandafter\skvifescaped\expandafter{\skv@prova}{}{% \skv@err{Value of key 'count':\MessageBreak counter macro \skvoxdetok\skv@prova not escaped}\@ehd }% \fi \ifx\skv@provd\@empty \expandafter\def\skv@prova{0}% \else \skvifinteger\skv@provd{% \expandafter\let\skv@prova\skv@provd }{% \skv@err{Value of key 'count':\MessageBreak initial \skvoxdetok\skv@provd not an integer}\@ehd }% \fi \skv@foreach@swafalse \ifx\skv@provc\@empty % No tester but there may be a quantity to test. The quantity, % on its own, isn't sufficient to conduct a test: \let\skv@foreach@itemcounter\skv@prova \else % If there isn't a quantity to test, then no test is possible: \ifx\skv@provb\@empty\else \skv@foreach@swatrue % \skv@tester is the second argument of \skv@foreach@maketester, % which is used below: \skvexpbracenext\skv@foreach@maketester\skv@provc\skv@tester \fi \fi }% \skv@tempxifin{satisfying}{#1}{% \skv@tempxifin{all}{#1}{% % 'all' and 'satisfying' are present: \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'count': \MessageBreak there is 'satisfying', but no 'all'}\@ehd }% }{% \skv@tempxifin{all}{#1}{% \skv@tempa#1satisfying\skv@nil }{% % No 'all' and 'satisfying': #1 should be only the counter macro: \ifx\@nnil#1\@nnil \skv@err{Value of key 'count': no counter macro}\@ehd \else \skvifntype{#1}{% \skv@tempa#1all satisfying\skv@nil }{% \skv@err{Value of key 'count in': more than 1 \MessageBreak token '\detokenize{#1}'. \MessageBreak I can't find counter macro}\@ehd }% \fi }% }% \ifskv@foreach@swa \skv@foreach@addtocallback{pre}{% \noexpand\ifnum\noexpand\foreachitemcount=\@ne \def\skvexpandonce\skv@prova{\number\skv@prova}% \noexpand\fi \skvexpandonce\skv@tester{% \noexpand\skvpushnumber\skvexpandonce\skv@prova }{}% }% \fi \skvexpanded{\endgroup \ifskv@foreach@swa \skvcmdexit\skv@foreach@precallback \else \skvcmdexit\skv@foreach@itemcounter \fi }% } % remember= as initially % \skvrobustdef*\skv@fox@parseremember#1{% \begingroup \def\skv@tempxifin##1##2{% \skvxifin{\detokenize{##1}}{\detokenize{##2}}% }% \skv@tempxifin{(}{#1}{% \skv@err{Value of key 'remember': '(' found. \MessageBreak I don't accept this PGF format. \MessageBreak remove the parenthesis '()'}\@ehd }{}% \def\skv@tempa##1as##2initially##3\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% \edef\skv@provb{\skvtrimspace{##2}}% \edef\skv@provc{\skvtrimspace{##3}}% \skv@foreach@swafalse \ifx\skv@prova\@empty \skv@err{Value of key 'remember' has no value to remember}\@ehd \fi \ifx\skv@provb\@empty \skv@err{Value of key 'remember' has no child macro; \MessageBreak i.e., no macro after 'as'}\@ehd \else \expandafter\skvifescaped\expandafter{\skv@provb}{% \skv@foreach@swatrue }{% \skv@err{Value of key 'remember': \MessageBreak child \skvoxdetok\skv@provb not escaped}\@ehd }% \fi }% \skv@tempxifin{initially}{#1}{% \skv@tempxifin{as}{#1}{% \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'remember': \MessageBreak there is 'initially', but no 'as'}\@ehd }% }{% \skv@tempxifin{as}{#1}{% \skv@tempa#1initially\skv@nil }{% % No 'as' and 'initially': \ifx\@nnil#1\@nnil\else % Unlike in \newforeach, we can't create an automatic retainer % macro here, since \foxloop uses parameters instead of % holder macros. \skv@err{Value of key 'remember' is incomplete: no 'as'}\@ehd \fi }% }% \ifskv@foreach@swa % Initially: \skv@foreach@addtocallback{pre}{% % Don't remove this \ifnum, otherwise the initial assignment % will be overwritten on subsequent returns: \noexpand\ifnum\noexpand\foreachitemcount=\@ne \edef\skvexpandonce\skv@provb{% \noexpand\unexpanded{\skvexpandonce\skv@provc}% }% \noexpand\fi }% \skv@foreach@addtocallback{post}{% \edef\skvexpandonce\skv@provb{% \noexpand\unexpanded{\skvexpandonce\skv@prova}% }% }% \fi \skvexpanded{\endgroup \ifskv@foreach@swa \skvcmdexit\skv@foreach@precallback \skvcmdexit\skv@foreach@postcallback \fi }% } \skvnewdef*\skv@foxloop@kvlist{} % \setupfoxloop{} \skvrobustdef*\setupfoxloop#1{% \skvifblank{#1}{}{% \skvaddtolist\skv@foxloop@kvlist{#1}% }% } \skvrobustdef*\skv@foxloop@setkeys#1{% \def\reserved@a{\quickkeys.set{skvfoxloop}}% \expandafter\reserved@a\expandafter{\skv@foxloop@kvlist,#1}% } % \atbeginfoxloop[]{} \skvnewlet\atbeginfoxloop\atbeginforeach % \atendfoxloop[]{} \skvnewlet\atendfoxloop\atendforeach \skvrobustdef*\foxloop{\skv@teststopt\skv@foxloop{}} \skvnewlet\foreachfox\foxloop \skvrobustdef*\skv@foxloop[#1]#2#3{% \ifskv@tempst \def\skv@foreach@st{00}% \else \def\skv@foreach@st{01}% \fi \skv@foreach@pushstate \skv@foreach@latehookerr \def\foreachitemcount{0}% \def\skv@foreach@callback{}% \def\skv@foreach@precallback{}% \def\skv@foreach@postcallback{}% \def\skv@foreach@onlyinitially{}% \skv@foxloop@setkeys{#1}% \if\skv@foreach@st\else \if\skv@foreach@listismacro \def\skv@foreach@st{00}% \else \def\skv@foreach@st{01}% \fi \fi \edef\skv@foreach@userlist{% \if\skv@foreach@st \expandafter\skvexpandonce \else \expandafter\unexpanded \fi {#2}% }% \skvcsuse{skv@foreach@atbeginhook@\skvrom\foreachdepth}% \edef\reserved@a{% \skvexpandonce\skv@foreach@precallback \ifx\skv@foreach@onlyinitially\@empty\else \noexpand\ifnum\noexpand\foreachitemcount=\@ne \skvexpandonce\skv@foreach@onlyinitially \noexpand\fi \fi \unexpanded{#3}% \skvexpandonce\skv@foreach@postcallback }% % Define the user callback: \edef\reserved@b{% \def\noexpand\skv@foreach@callback\skvexpandonce \skv@foreach@paramlist\noexpand\foreacheov }% \expandafter\reserved@b\expandafter{\reserved@a}% \skvxifstrcmp\skv@foreach@listtype{csv}{% \def\skv@foreach@lookahead@a##1{% \def\skv@foreach@continue{##1.}% \futurelet\skv@foreach@next\skv@foreach@lookahead@b }% \def\skv@foreach@lookahead@c[##1]{\skv@foreach@continue[{##1}]}% \def\skv@foreach@lookahead@d(##1){\skv@foreach@continue({##1})}% }{% \def\skv@foreach@lookahead@a##1{% \let\skv@foreach@continue##1% \futurelet\skv@foreach@next\skv@foreach@lookahead@b }% \def\skv@foreach@lookahead@c[##1]{\skv@foreach@continue{[##1]}}% \def\skv@foreach@lookahead@d(##1){\skv@foreach@continue{(##1)}}% }% \def\skv@foreach@lookahead@b{% \skvifx\skv@foreach@next[{% \skv@foreach@parenthtrue\skv@foreach@lookahead@c }{% \skvifx\skv@foreach@next({% \skv@foreach@parenthtrue\skv@foreach@lookahead@d }{% \skv@foreach@parenthfalse\skv@foreach@continue }% }% }% \skvbreakloopfalse\lastfoxfalse \def\reserved@a##1{% \skv@setupgetnextfox{##1}% \skvxifstrcmp\skv@foreach@listtype{csv}{% \if\skv@foreach@normalizelist \skv@foreach@normalize[##1]\skv@foreach@userlist \fi \def\skv@foreach@do####1##1####2\skv@foxloop@stop{% \edef\currentfox{\skvexpandonce{\@gobble####1}}% \skv@foxloop@a{##1}{####2}{csv}% }% \skvifempty\skv@foreach@userlist{}{% \expandafter\skv@foreach@filllist\expandafter {\skv@foreach@parser}\skv@foreach@userlist \if\skv@foreach@reverselist\skvafterfi \expandafter\skv@foreach@doreverselist\expandafter {\skv@foreach@parser}\skv@foreach@userlist \fi }% % If \skv@foreach@userlist is empty, \currentfox in % \skv@foxloop@b will terminate the loop. \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do \skv@foreach@userlist##1\skv@foxloop@nil##1\skv@foxloop@stop }{% \if\skv@foreach@normalizelist \edef\skv@foreach@userlist{% \skvexpbracenext\skvtsvnormalize\skv@foreach@userlist }% \fi \def\skv@foreach@do{% \let\bgroup\relax \futurelet\skv@foreach@next\skv@foreach@do@a }% \def\skv@foreach@do@a####1####2\skv@foxloop@stop{% \let\bgroup\skv@orig@bgroup \ifskv@foreach@parenth \edef\currentfox{\unexpanded{####1}}% \else \skvifx\skv@foreach@next\bgroup{% \edef\currentfox{{\unexpanded{####1}}}% }{% \edef\currentfox{\unexpanded{####1}}% }% \fi \skv@foxloop@a{}{####2}{tsv}% }% \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do \skv@foreach@userlist\skv@foxloop@nil\skv@foxloop@stop }% }% \expandafter\reserved@a\expandafter{\skv@foreach@parser}% \skvcsuse{skv@foreach@atendhook@\romannumeral\foreachdepth}% \skv@foreach@popstate } % \skv@setupgetnextfox \skvrobustdef*\skv@setupgetnextfox#1{% \skvxifstrcmp\skv@foreach@listtype{csv}{% \def\skv@foreach@getnext##1#1##2\skv@foxloop@stop{% \edef\nextfox{\skvexpandonce{\@gobble##1}}% % See \skv@foxloop@b for \lastfoxtrue. }% }{% \def\skv@foreach@getnext{% \begingroup \let\bgroup\relax \futurelet\skv@foreach@next\skv@foreach@g@tnext }% \def\skv@foreach@g@tnext##1##2\skv@foxloop@stop{% \let\bgroup\skv@orig@bgroup \ifskv@foreach@parenth \edef\nextfox{\unexpanded{##1}}% \else \skvifx\skv@foreach@next\bgroup{% \edef\nextfox{{\unexpanded{##1}}}% }{% \edef\nextfox{\unexpanded{##1}}% }% \fi }% }% } % \skv@foxloop@a \skvrobustdef*\skv@foxloop@a#1#2#3{% \skvifx\currentfox\skv@foxloop@nnil{% \skvbreakloopfalse\lastfoxfalse }{% \skvifx\currentfox\skv@listbreakertoks{% \skv@foxloop@getrm{#1}{#2}% }{% \skvifx\currentfox\skv@listpausertoks{% \message{^^J! List pause: ^^JType x or X to quit, or to proceed^^J}% \bgroup\endlinechar\m@ne\global\read-1 to\@gtempa\egroup \skvexpandarg\lowercase{\def\noexpand\@gtempa{\@gtempa}}% \skvxifstrcmp\@gtempa{x}{% \skv@foxloop@getrm{#1}{#2}% }{% \skv@foxloop@b{#1}{#2}{#3}% }% }{% \skv@foxloop@b{#1}{#2}{#3}% }% }% }% } % \skv@foxloop@b \skvrobustdef*\skv@foxloop@b#1#2#3{% \skv@foreach@lookahead@a\skv@foreach@getnext#2\skv@foxloop@stop \ifx\nextfox\skv@foxloop@nnil \lastfoxtrue\def\nextfox{}% \fi \edef\foreachitemcount{\the\numexpr\foreachitemcount+1}% \ifnum0=\numexpr \ifx\skv@foreach@itemcounter\@undefined-1\else+0\fi \ifx\skv@foreach@itemcounter\@empty-1\else+0\fi \ifx\skv@foreach@itemcounter\@nnil-1\else+0\fi\relax\relax \expandafter\let\skv@foreach@itemcounter\foreachitemcount \fi \skvifempty\currentfox{% \if\skv@foreach@useempty \expandafter\skv@foreach@callback\expandafter\foreacheov \fi }{% % Tes for \listpauser, in case the user decides to continue % after \listpauser has been picked: \skvifx\currentfox\skv@listpausertoks{}{% \skvifx\skv@foreach@paramlist\skv@simplearg{% \expandafter\skv@foreach@callback\expandafter {\currentfox}\foreacheov }{% \expandafter\skv@foreach@callback\currentfox\foreacheov }% }% }% \skv@foreach@exittester{\skvbreakloop}{}% \skvifdefbool{skvbreakloop}{% \skvbreakloopfalse\lastfoxfalse \skv@foxloop@getrm{#1}{#2}% }{% \skv@foreach@lookahead@a\skv@foreach@do#2\skv@foxloop@stop }% } % \skv@foxloop@getrm \skvrobustdef*\skv@foxloop@getrm#1#2{% \begingroup \def\reserved@a##1\skv@foxloop@nil#1{% \endgroup \edef\foxlistremainder{\unexpanded{##1}}% }% \reserved@a#2% } % \cicadaloop[]{}<\if...>\fi{<1.parameter.code>} % \cicadaloop*[]{}<\if...>\fi{<1.parameter.code>} % % 1. When the conditional <\if...> isn't true, the regular code % will be executed for every member of the list. % 3. \ifskvbreakloop may be used as the conditional in <\if...>. % 5. The boolean \iflastcicada is available for accessing the last item % of the list. There are also the macros \currentcicada, \lastcicada, % \cicadacount, and the counter \cicadaloopdepth. % 6. \cicadaloop can be nested. % % Example: % % \let\romn\romannumeral % \@tempcnta\z@ % \def\blist{{X};{Y};Z;\fi} % \def\stack{} % \cicadaloop{{a},{b},c,\if}\if01\fi{% % \advance\@tempcnta\@ne % \@tempcntb\z@ % \@tempswafalse % \cicadaloop*[;]\blist\if@tempswa\fi{% % \advance\@tempcntb\@ne % \typeout{Doing \romn\@tempcnta,\romn\@tempcntb: \detokenize{#1,##1}}% % \edef\stack{% % \unexpanded\expandafter{\stack}\noexpand\do % {\romn\@tempcnta,\romn\@tempcntb}{\unexpanded{#1;##1}}% % }% % \ifnum\@tempcntb>\@ne % \@tempswatrue % \skvcsedef{cmd@\romn\cicadaloopdepth}{\lastcicada,\cicadacount}% % \fi % }% % } % \show\stack % \skvnewregisters\bool{\iflastcicada} \skvbuildmacrostack\skv@cicada@state{% \do\skv@cicada@do\do\skv@cicada@userlist\do\currentcicada \do\nextcicada\do\cicadacount\do\lastcicada\do\skv@cicada@callback \do\skv@cicada@getnext\do\ifskvprocessempty }\skv@stackdepthlimit \skvnewnumbers{cicadaloopdepth} \skvnewlet\skv@cicada@nil\relax \skvnewdef*\skv@cicada@nnil{\skv@cicada@nil} \skvnewlet\breakcicada\skvbreakloop \skvrobustdef*\cicadaloop{\skv@teststopt\skv@cicadaloop,} \skvrobustdef*\skv@cicadaloop[#1]#2#3\fi#4{% \let\if@cicada@st\ifskv@tempst \skvpushstate\skv@cicada@state\cicadaloopdepth \let\ifskv@tempst\if@cicada@st \skv@usetempst{#2}\skv@cicada@userlist \skv@foreach@normalize[#1]\skv@cicada@userlist \def\skv@cicada@callback##1{#4}% \def\lastcicada{}% \def\skv@cicada@getnext##1#1##2\skv@cicada@stop{% \edef\nextcicada{\skvexpandonce{\@gobble##1}}% \ifx\nextcicada\skv@cicada@nnil \lastcicadatrue \def\nextcicada{}% \fi }% \chardef\cicadacount\skvz@ \def\skv@cicada@do##1#1##2\skv@cicada@stop{% \edef\currentcicada{\skvexpandonce{\@gobble##1}}% \skvifx\currentcicada\skv@cicada@nnil{% \skvbreakloopfalse\lastcicadafalse }{% \skvifx\currentcicada\skv@listbreakertoks{% \skvbreakloopfalse\lastcicadafalse }{% \edef\cicadacount{\the\numexpr\cicadacount+1}% \skv@cicada@lookahead\skv@cicada@getnext##2\skv@cicada@stop \skvexpandbracenext\skv@cicada@callback\currentcicada\relax \skvifnotcond#3\fi{}\skvbreakloop \skvifdefbool{skvbreakloop}{% \skvbreakloopfalse\lastcicadafalse \begingroup \def\skv@prova####1\skv@cicada@nil#1{% \endgroup \edef\skvremainder{\unexpanded{####1}}% }% \skv@prova##2% }{% \let\lastcicada\currentcicada \skv@cicada@lookahead\skv@cicada@do##2\skv@cicada@stop }% }% }% }% \def\skv@cicada@lookahead##1{% \def\skv@cicada@continue{##1.}% \futurelet\skv@next\skv@cicada@lookahead@a }% \def\skv@cicada@lookahead@a{% \ifx\skv@next[% \expandafter\skv@cicada@lookahead@b \else \ifx\skv@next(% \expandafter\expandafter\expandafter\skv@cicada@lookahead@c \else \expandafter\expandafter\expandafter\skv@cicada@continue \fi \fi }% \def\skv@cicada@lookahead@b[##1]{\skv@cicada@continue[{##1}]}% \def\skv@cicada@lookahead@c(##1){\skv@cicada@continue({##1})}% \skvbreakloopfalse\lastcicadafalse \skvifx\skv@cicada@userlist\@empty{% \ifskvprocessempty\skv@cicada@callback{}\fi }{% \skvexpandnext{\skv@cicada@lookahead\skv@cicada@do}% \skv@cicada@userlist#1\skv@cicada@nil#1\skv@cicada@stop }% \skvpopstate\skv@cicada@state\cicadaloopdepth } % \cicadiloop[]{}<\if...>\fi{}{<1.parameter.code>} % \cicadiloop*[]{}<\if...>\fi{}{<1.parameter.code>} % % It is easy to forget to turn conditional #3 off before commencing % the loop, especially if it is a boolean. The conditional might have % been set true before calling \cicadaloop, and this may invalidate % later tests to terminate the loop prematurely. #4 can be used to turn % the condtional off before commencing the loop. % \skvrobustdef*\cicadiloop{\skv@teststopt\skv@cicadiloop,} \skvrobustdef*\skv@cicadiloop[#1]#2#3\fi#4{% \skvexpandsecond {#4\relax\skv@cicadiloop}{\ifskv@tempst*\fi}% [#1]{#2}#3\fi } % \lpchangelistseparator % {}{}{}{} % % Example: % \def\alist{{a/1,a/2};b;c} % \lpchangelistseparator{;}\alist{,}\blist % \skvrobustdef*\lpchangelistseparator#1#2#3#4{% \def#4{}% \cicadaloop*[#1]{#2}\if01\fi{}{}{% \edef#4{% \skvexpandonce#4{\unexpanded{##1}}% \iflastcicada\else#3\fi }% }% } \loops@restorecodes \endinput