diff options
author | Karl Berry <karl@freefriends.org> | 2012-11-06 22:35:43 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2012-11-06 22:35:43 +0000 |
commit | 705b4d8f092a56d9ae900940d265fb6f55b3033d (patch) | |
tree | 8299b4712f70eff6211da7326d99ebd33ba035cc /Master/texmf-dist/tex/latex/loops/loops.sty | |
parent | 2f6000f28f9662342c1cfe6e59abfdf345bd3a23 (diff) |
loops (6nov12)
git-svn-id: svn://tug.org/texlive/trunk@28196 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/loops/loops.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/loops/loops.sty | 414 |
1 files changed, 317 insertions, 97 deletions
diff --git a/Master/texmf-dist/tex/latex/loops/loops.sty b/Master/texmf-dist/tex/latex/loops/loops.sty index f05a61d6c10..351205fdd4e 100644 --- a/Master/texmf-dist/tex/latex/loops/loops.sty +++ b/Master/texmf-dist/tex/latex/loops/loops.sty @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'loops.sty', version 1.1, October 2012. % +% This is file 'loops.sty', version 1.1, 2012/10/16. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -53,7 +53,7 @@ \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)] +\ProvidesPackage{loops}[2012/10/16 v1.1 Loops and list processors (AM)] \NeedsTeXFormat{LaTeX2e}[2011/06/27] % This is the way to load 'skeyval-for-core' here, otherwise we @@ -64,6 +64,20 @@ \skvnewlet\ltxkernelfor\@for \skvnewlet\ltxkerneltfor\@tfor +\directkeys*{ + .every unknown option={ + \PackageWarning{loops}{Unknown option '\CurrentOption' ignored}% + }, + .prefix=SKV, + .family=loops, + .holder prefix=lps@, + .initialize keys after define, + .new options={ + .bool/verbose/true/\iflps@verbose\skv@verbosetrue\fi, + }, + .copy class options and process options, +} + % \skvusetwoprev{<parser>}{<list>}{<target.item>}{<do.on.target>} % % Example: @@ -71,7 +85,7 @@ % \skvusetwoprev{,}{a,b,c,d,e,f}{e}{} % \skvrobustdef*\skvusetwoprev#1#2#3#4{% - \skvifin{#1#3#1}{#1#2#1}{}{% + \skvifinTF{#1#3#1}{#1#2#1}{}{% \skv@err{There is not '\detokenize{#3}' in the list}\@ehd }% \let\firstprev\@empty @@ -93,11 +107,29 @@ \skv@do#2#1\skv@nnil#1% } -% A version of D.E. Knuth's \loop: +% Remove one element from a list. Only the first occurence of the +% element will be removed. This is fast. +% +% \lpsremovefromlist<parser>{<element to remove>}<listcmd> +% +% Eg, \def\x{1,2,3,4} \lpsremovefromlist{,}7\x +% +\skvrobustdef\lpsremovefromlist#1#2#3{% + \begingroup + \def\lps@remove@a##1\lps@nil{##1}% + \def\lps@remove@b##1\lps@nil{}% + \def\lps@remove@c##1#1#2##2\lps@nil##3\lps@nil##4\lps@nnil{% + \expandafter\endgroup##3\def#3{##1##2}\lps@nil + }% + \expandafter\lps@remove@c\expandafter#1#3\lps@nil + \lps@remove@a\lps@nil#1#2\lps@nil\lps@remove@b\lps@nil\lps@nnil +} + +% Expandable version of D.E. Knuth's \loop: % \skvnewdef\dekloop#1\repeat{\skv@dekloop{#1}} \skvnewdef\skv@dekloop#1{% - #1\relax + #1% \expandafter\skv@dekloop \else \expandafter\@gobble @@ -105,6 +137,11 @@ {#1}% } +\skvnewdef\lpswhilecondition#1\do#2{% + \csname @#1firstofone\else gobble\fi\endcsname + {#2\lpswhilecondition{#1}\do{#2}}% +} + % A version of D.E. Knuth's \loop that can be nested. % Credit: David P. Carlisle. % @@ -170,16 +207,16 @@ \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{% + \skvifntypeTF{#1}{% + \skvifxTF{#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@{% + \skvifstrcmpTF{#1}\repeat{% + \skvifnumTF\skv@aktercnt=\skvz@{% \expandafter\endgroup\the\skv@aktertoks\repeat }{% \skv@aktertoks\expandafter @@ -188,7 +225,7 @@ \skv@akterpush }% }{% - \skvifx\next\@sptoken{% + \skvifxTF\next\@sptoken{% \skv@aktertoks\expandafter {\the\expandafter\skv@aktertoks\@space#1}% }{% @@ -198,10 +235,10 @@ }% }% }{% - \skvifstrcmp{#1}{EOF}{% + \skvifstrcmpTF{#1}{EOF}{% \skv@err{'\string\repeat' not found: endless loop}\@ehd }{% - \skvifx\next\@sptoken{% + \skvifxTF\next\@sptoken{% \skv@aktertoks\expandafter {\the\expandafter\skv@aktertoks\space{#1}}% }{% @@ -230,10 +267,10 @@ % \skvnewdef\skvfor#1#2{\skv@for@a{#2}#1,\skv@for@nil,} \skvnewdef\skv@for@a#1#2,{% - \skvifblank{#2}{% + \skvifblankTF{#2}{% \skv@for@a{#1}% }{% - \skvifstrcmp{#2}\skv@for@nil{}{#1{#2}\skv@for@a{#1}}% + \skvifstrcmpTF{#2}\skv@for@nil{}{#1{#2}\skv@for@a{#1}}% }% } @@ -259,7 +296,7 @@ \skv@usetempst{#1}\skv@tempa \skvsavestate\ayeloop{\do\skv@ayeloop}\skv@csvdepth \def\skv@ayeloop##1{% - \skvifstrcmp{##1}\skv@tfor@nil{% + \skvifstrcmpTF{##1}\skv@tfor@nil{% \skvbreakloopfalse }{% #2\relax @@ -295,7 +332,7 @@ \expandafter\skvtsvnormalize\expandafter{\skv@sifakaarg}% }% \skvbreakloopfalse - \skvifempty\skv@sifakaarg{% + \skvifemptyTF\skv@sifakaarg{% \ifskvprocessempty\skv@user@do{}\fi }{% \expandafter\skv@sifakaparse@b\skv@sifakaarg\skv@tsvnil @@ -315,25 +352,25 @@ }% } \skvrobustdef*\skv@sifakaparse@c#1{% - \skvifx\skv@next\skv@orig@bgroup{% + \skvifxTF\skv@next\skv@orig@bgroup{% \endgroup \edef\skv@sifakaarg{{\unexpanded{#1}}}% }{% \endgroup \edef\skv@sifakaarg{\unexpanded{#1}}% }% - \skvifx\skv@sifakaarg\skv@tsvnil{% + \skvifxTF\skv@sifakaarg\skv@tsvnil{% \skvbreakloopfalse }{% - \skvifx\skv@sifakaarg\skv@listbreakertoks{% + \skvifxTF\skv@sifakaarg\skv@listbreakertoks{% \skvbreakloop }{% - \skvifempty\skv@sifakaarg{% + \skvifemptyTF\skv@sifakaarg{% \ifskvprocessempty\skv@user@do{}\fi }{% \expandafter\skv@user@do\expandafter{\skv@sifakaarg}\relax }% - \skvifdefbool{skvbreakloop}{% + \skvifdefboolTF{skvbreakloop}{% \skvbreakloopfalse \begingroup \def\skv@prova##1\skv@tsvnil{% @@ -389,15 +426,11 @@ % 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}{% +\quickkeys.define{loops/foxloop}{% 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 @@ -409,11 +442,11 @@ 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} + \edef\skv@foreach@normalizelist{0\skvifstrcmpTF{#1}{true}01} /true,false ; use empty,use empty items/true/ - \edef\skv@foreach@useempty{0\skvifstrcmp{#1}{true}01} + \edef\skv@foreach@useempty{0\skvifstrcmpTF{#1}{true}01} /true,false ; .exec/ @@ -449,7 +482,7 @@ \skv@err{Value required for key 'grow'}\@ehd \else \skvcsedef{skv@foreach@grow#1}{00}% - \edef\skv@prova{\skvifstrcmp{#1}{left}{right}{left}}% + \edef\skv@prova{\skvifstrcmpTF{#1}{left}{right}{left}}% \skvcsedef{skv@foreach@grow\skv@prova}{01}% \fi \fi @@ -461,38 +494,51 @@ ; grow left/true/ \ifskvindef\else - \edef\skv@foreach@growleft{0\skvifstrcmp{true}{#1}01}% - \edef\skv@foreach@growright{0\skvifstrcmp{true}{#1}10}% + \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}01}% + \edef\skv@foreach@growright{0\skvifstrcmpTF{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}% + \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}01}% + \edef\skv@foreach@growleft{0\skvifstrcmpTF{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}% + \edef\skv@foreach@keepdecimals{0\skvifstrcmpTF{true}{#1}01}% /true,false ; keep high decimals,keep only high decimals/true/ - \edef\skv@foreach@keephighdecimals{0\skvifstrcmp{true}{#1}01}% + \edef\skv@foreach@keephighdecimals{0\skvifstrcmpTF{true}{#1}01}% + /true,false + ; + expand before fill,expand list before fill/true/ + \edef\skv@foreach@expandlistbeforefill{0\skvifstrcmpTF{true}{#1}01}% /true,false ; - expand before fill/true/ - \edef\skv@foreach@expandbeforefill{0\skvifstrcmp{true}{#1}01}% + expand list once,*,list is a macro,macro list/true/ + \edef\skv@foreach@expandlistonce{0\skvifstrcmpTF{true}{#1}01}% + /true,false + ; + expand list twice/true/ + \edef\skv@foreach@expandlisttwice{0\skvifstrcmpTF{true}{#1}01}% + /true,false + ; + % Don't use 'expand' for the key 'expand list': + expand list,fully expand list,expand list fully/true/ + \edef\skv@foreach@expandlistfully{0\skvifstrcmpTF{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. + % call to \skv@foxloop@parseevaluate until the arguments are known. evaluate/\@nil/ \skv@foreach@ifacceptkv{#1}{% - \skv@fox@parseevaluate{#1}% + \skv@foxloop@parseevaluate{#1}% }% ; % Eg, @@ -500,25 +546,24 @@ % 'count in = \p all #1 satisfying \ifnum#1>4\fi' count in,count/\@nil/ \skv@foreach@ifacceptkv{#1}{% - \skv@fox@parsecountin{#1}% + \skv@foxloop@parsecountin{#1}% }% ; % Eg, remember=#1 as \y initially A remember/\@nil/ \skv@foreach@ifacceptkv{#1}{% - \skv@fox@parseremember{#1}% + \skv@foxloop@parseremember{#1}% }% ; - reverse list,reverse/true/ - \edef\skv@foreach@reverselist{0\skvifstrcmp{true}{#1}01}% + reverse list,reverse,reflect/true/ + \edef\skv@foreach@reverselist{0\skvifstrcmpTF{true}{#1}01}% /true,false ; } % Set up \foxloop defaults: -\quickkeys.set{skvfoxloop}{% +\quickkeys.set{loops/foxloop}{% parser={,}, - list is a macro=false, list type=csv, arg=#1, list breaker=\listbreaker, @@ -529,19 +574,22 @@ keep high decimals=false, expand before fill=false, reverse list=false, + expand list once=false, + expand list twice=false, + expand list fully=false, } % Parser for 'evaluate' key: % % Eg, 'evaluate = #1 as \x using \numexpr#1*2'. % -% \skv@fox@parseevaluate differs from \skv@foreach@parseevaluate +% \skv@foxloop@parseevaluate differs from \skv@foreach@parseevaluate % because #1 here is likely to be a non-macro. % -\skvrobustdef*\skv@fox@parseevaluate#1{% +\skvrobustdef*\skv@foxloop@parseevaluate#1{% \begingroup \def\skv@tempxifin##1##2{% - \skvxifin{\detokenize{##1}}{\detokenize{##2}}% + \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% }% \def\skv@tempd{}% % <formula> #3 can be empty. So we don't test for its emptiness here. @@ -557,7 +605,7 @@ \skv@err{Value of key 'evaluate' has no receiving macro, \MessageBreak i.e., after 'as'}\@ehd \else - \expandafter\skvifescaped\expandafter{\skv@provb}{}{% + \expandafter\skvifescapedTF\expandafter{\skv@provb}{}{% \skv@err{Value of key 'evaluate': receiving macro \MessageBreak \skvoxdetok\skv@provb not escaped}\@ehd }% @@ -664,10 +712,10 @@ % % \iflastfox\typeout{Processing last entry of the list} \fi % -\skvrobustdef*\skv@fox@parsecountin#1{% +\skvrobustdef*\skv@foxloop@parsecountin#1{% \begingroup \def\skv@tempxifin##1##2{% - \skvxifin{\detokenize{##1}}{\detokenize{##2}}% + \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% }% \def\skv@tempa##1\skv@nil{% \skv@tempxifin{initially}{##1}{% @@ -684,7 +732,7 @@ \ifx\skv@prova\@empty \skv@err{Value of key 'count' has no counter macro}\@ehd \else - \expandafter\skvifescaped\expandafter{\skv@prova}{}{% + \expandafter\skvifescapedTF\expandafter{\skv@prova}{}{% \skv@err{Value of key 'count':\MessageBreak counter macro \skvoxdetok\skv@prova not escaped}\@ehd }% @@ -692,7 +740,7 @@ \ifx\skv@provd\@empty \expandafter\def\skv@prova{0}% \else - \skvifinteger\skv@provd{% + \skvifintegerTF\skv@provd{% \expandafter\let\skv@prova\skv@provd }{% \skv@err{Value of key 'count':\MessageBreak @@ -730,7 +778,7 @@ \ifx\@nnil#1\@nnil \skv@err{Value of key 'count': no counter macro}\@ehd \else - \skvifntype{#1}{% + \skvifntypeTF{#1}{% \skv@tempa#1all satisfying\skv@nil }{% \skv@err{Value of key 'count in': more than 1 @@ -761,10 +809,10 @@ % remember=<holder.macro> as <child.macro> initially <value> % -\skvrobustdef*\skv@fox@parseremember#1{% +\skvrobustdef*\skv@foxloop@parseremember#1{% \begingroup \def\skv@tempxifin##1##2{% - \skvxifin{\detokenize{##1}}{\detokenize{##2}}% + \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% }% \skv@tempxifin{(}{#1}{% \skv@err{Value of key 'remember': '(' found. @@ -783,7 +831,7 @@ \skv@err{Value of key 'remember' has no child macro; \MessageBreak i.e., no macro after 'as'}\@ehd \else - \expandafter\skvifescaped\expandafter{\skv@provb}{% + \expandafter\skvifescapedTF\expandafter{\skv@provb}{% \skv@foreach@swatrue }{% \skv@err{Value of key 'remember': @@ -839,12 +887,12 @@ \skvnewdef*\skv@foxloop@kvlist{} % \setupfoxloop{<kvlist>} \skvrobustdef*\setupfoxloop#1{% - \skvifblank{#1}{}{% + \skvifblankTF{#1}{}{% \skvaddtolist\skv@foxloop@kvlist{#1}% }% } \skvrobustdef*\skv@foxloop@setkeys#1{% - \def\reserved@a{\quickkeys.set{skvfoxloop}}% + \def\reserved@a{\quickkeys.set{loops/foxloop}}% \expandafter\reserved@a\expandafter{\skv@foxloop@kvlist,#1}% } @@ -856,31 +904,52 @@ \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 + \edef\skv@foreach@seenstar{0\ifskv@tempst0\else1\fi}% \skv@foreach@pushstate \skv@foreach@latehookerr \def\foreachitemcount{0}% \def\skv@foreach@callback{}% + \def\skv@foreach@afterprecallback{}% \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 + \if\skv@foreach@seenstar + \def\skv@foreach@expandlistonce{00}% + \fi + \ifcase0% + \if\skv@foreach@expandlistonce\else + \if\skv@foreach@expandlisttwice\else + \if\skv@foreach@expandlistfully\else 1\fi\fi\fi\relax + \def\skv@foreach@listisamacro{00}% + \else + \def\skv@foreach@listisamacro{01}% + \skvifmacroFT{#2}{}{% + \ifskv@verbose + \skv@warn{One-item list '\detokenize{#2}' is a macro. + \MessageBreak If your list is indeed a macro, you can + \MessageBreak either put star (*) after + \detokenize{\foxloop or \foreachfox} + \MessageBreak or use the key 'expand list once' + \MessageBreak or 'expand list twice' or 'list is a macro', etc}% + \fi + }% \fi \edef\skv@foreach@userlist{% - \if\skv@foreach@st + \if\skv@foreach@expandlistonce \expandafter\skvexpandonce \else - \expandafter\unexpanded + \if\skv@foreach@expandlisttwice + \expandafter\expandafter\expandafter\skvexpandtwice + \else + \if\skv@foreach@expandlistfully + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\@iden + \else + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\unexpanded + \fi + \fi \fi {#2}% }% @@ -901,7 +970,7 @@ \skv@foreach@paramlist\noexpand\foreacheov }% \expandafter\reserved@b\expandafter{\reserved@a}% - \skvxifstrcmp\skv@foreach@listtype{csv}{% + \skvxifstrcmpTF\skv@foreach@listtype{csv}{% \def\skv@foreach@lookahead@a##1{% \def\skv@foreach@continue{##1.}% \futurelet\skv@foreach@next\skv@foreach@lookahead@b @@ -917,10 +986,10 @@ \def\skv@foreach@lookahead@d(##1){\skv@foreach@continue{(##1)}}% }% \def\skv@foreach@lookahead@b{% - \skvifx\skv@foreach@next[{% + \skvifxTF\skv@foreach@next[{% \skv@foreach@parenthtrue\skv@foreach@lookahead@c }{% - \skvifx\skv@foreach@next({% + \skvifxTF\skv@foreach@next({% \skv@foreach@parenthtrue\skv@foreach@lookahead@d }{% \skv@foreach@parenthfalse\skv@foreach@continue @@ -930,7 +999,7 @@ \skvbreakloopfalse\lastfoxfalse \def\reserved@a##1{% \skv@setupgetnextfox{##1}% - \skvxifstrcmp\skv@foreach@listtype{csv}{% + \skvxifstrcmpTF\skv@foreach@listtype{csv}{% \if\skv@foreach@normalizelist \skv@foreach@normalize[##1]\skv@foreach@userlist \fi @@ -938,7 +1007,7 @@ \edef\currentfox{\skvexpandonce{\@gobble####1}}% \skv@foxloop@a{##1}{####2}{csv}% }% - \skvifempty\skv@foreach@userlist{}{% + \skvifemptyTF\skv@foreach@userlist{}{% \expandafter\skv@foreach@filllist\expandafter {\skv@foreach@parser}\skv@foreach@userlist \if\skv@foreach@reverselist\skvafterfi @@ -965,7 +1034,7 @@ \ifskv@foreach@parenth \edef\currentfox{\unexpanded{####1}}% \else - \skvifx\skv@foreach@next\bgroup{% + \skvifxTF\skv@foreach@next\bgroup{% \edef\currentfox{{\unexpanded{####1}}}% }{% \edef\currentfox{\unexpanded{####1}}% @@ -983,7 +1052,7 @@ } % \skv@setupgetnextfox<parser> \skvrobustdef*\skv@setupgetnextfox#1{% - \skvxifstrcmp\skv@foreach@listtype{csv}{% + \skvxifstrcmpTF\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. @@ -999,7 +1068,7 @@ \ifskv@foreach@parenth \edef\nextfox{\unexpanded{##1}}% \else - \skvifx\skv@foreach@next\bgroup{% + \skvifxTF\skv@foreach@next\bgroup{% \edef\nextfox{{\unexpanded{##1}}}% }{% \edef\nextfox{\unexpanded{##1}}% @@ -1010,18 +1079,18 @@ } % \skv@foxloop@a<parser><remainder><list.type> \skvrobustdef*\skv@foxloop@a#1#2#3{% - \skvifx\currentfox\skv@foxloop@nnil{% + \skvifxTF\currentfox\skv@foxloop@nnil{% \skvbreakloopfalse\lastfoxfalse }{% - \skvifx\currentfox\skv@listbreakertoks{% + \skvifxTF\currentfox\skv@listbreakertoks{% \skv@foxloop@getrm{#1}{#2}% }{% - \skvifx\currentfox\skv@listpausertoks{% + \skvifxTF\currentfox\skv@listpausertoks{% \message{^^J! List pause: ^^JType x or X to quit, or <RETURN> to proceed^^J}% \bgroup\endlinechar\m@ne\global\read-1 to\@gtempa\egroup \skvexpandarg\lowercase{\def\noexpand\@gtempa{\@gtempa}}% - \skvxifstrcmp\@gtempa{x}{% + \skvxifstrcmpTF\@gtempa{x}{% \skv@foxloop@getrm{#1}{#2}% }{% \skv@foxloop@b{#1}{#2}{#3}% @@ -1045,15 +1114,15 @@ \ifx\skv@foreach@itemcounter\@nnil-1\else+0\fi\relax\relax \expandafter\let\skv@foreach@itemcounter\foreachitemcount \fi - \skvifempty\currentfox{% + \skvifemptyTF\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{% + \skvifxTF\currentfox\skv@listpausertoks{}{% + \skvifxTF\skv@foreach@paramlist\skv@simplearg{% \expandafter\skv@foreach@callback\expandafter {\currentfox}\foreacheov }{% @@ -1062,7 +1131,7 @@ }% }% \skv@foreach@exittester{\skvbreakloop}{}% - \skvifdefbool{skvbreakloop}{% + \skvifdefboolTF{skvbreakloop}{% \skvbreakloopfalse\lastfoxfalse \skv@foxloop@getrm{#1}{#2}% }{% @@ -1146,17 +1215,17 @@ \chardef\cicadacount\skvz@ \def\skv@cicada@do##1#1##2\skv@cicada@stop{% \edef\currentcicada{\skvexpandonce{\@gobble##1}}% - \skvifx\currentcicada\skv@cicada@nnil{% + \skvifxTF\currentcicada\skv@cicada@nnil{% \skvbreakloopfalse\lastcicadafalse }{% - \skvifx\currentcicada\skv@listbreakertoks{% + \skvifxTF\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}{% + \skvifcondFT#3\fi{}\skvbreakloop + \skvifdefboolTF{skvbreakloop}{% \skvbreakloopfalse\lastcicadafalse \begingroup \def\skv@prova####1\skv@cicada@nil#1{% @@ -1189,7 +1258,7 @@ \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{% + \skvifxTF\skv@cicada@userlist\@empty{% \ifskvprocessempty\skv@cicada@callback{}\fi }{% \skvexpandnext{\skv@cicada@lookahead\skv@cicada@do}% @@ -1214,16 +1283,18 @@ [#1]{#2}#3\fi } -% \lpchangelistseparator +% Change the list separator of a given list. +% +% \lpschangelistseparator % {<original.parser>}{<orig.listcmd>}{<new.parser>}{<new.listcmd>} % % Example: % \def\alist{{a/1,a/2};b;c} -% \lpchangelistseparator{;}\alist{,}\blist +% \lpschangelistseparator{;}\alist{,}\blist % -\skvrobustdef*\lpchangelistseparator#1#2#3#4{% +\skvrobustdef*\lpschangelistseparator#1#2#3#4{% \def#4{}% - \cicadaloop*[#1]{#2}\if01\fi{}{}{% + \cicadaloop*[#1]{#2}\if01\fi{% \edef#4{% \skvexpandonce#4{\unexpanded{##1}}% \iflastcicada\else#3\fi @@ -1231,5 +1302,154 @@ }% } +% Declare a list normalizer command for an arbitrary parser. +% +% \lpsdeclarelistnormalizer<normalizer.cmd>{<parser>} +% +% Eg, +% +% \lpsdeclarelistnormalizer\lpscommanormalize{,} +% +% \lpscommanormalize is defined later. +% +\skvrobustdef*\lpsdeclarelistnormalizer#1#2{% + \skvifescapedTF{#1}{}{% + \skv@err{Token \detokenize{#1} isn't escaped}\@ehd + }% + \def\reserved@a{\lps@declarelistnormalizer{#1}}% + \expandafter\reserved@a\expandafter{\string#2}% +} +\skvrobustdef*\lps@declarelistnormalizer#1#2{% + \begingroup + \lccode`\~=`#2 % + \lowercase{\endgroup + \skvnewdef#1##1{% + \unexpanded\expandafter{\romannumeral-`\q + \skvcsuse{\skvremovescape#1@activeparser}#2##1#2~\normal@nil}% + }% + \long\skvcsdef{\skvremovescape#1@activeparser}##1~##2\normal@nil{% + \skvifblankTF{##2} + {\skvcsuse{\skvremovescape#1@spaceparser}##1 #2\normal@nil} + {\skvcsuse{\skvremovescape#1@activeparser}##1#2##2\normal@nil}% + }% + }% + \long\skvcsdef{\skvremovescape#1@spaceparser}##1 #2##2\normal@nil{% + \skvifblankTF{##2} + {\skvcsuse{\skvremovescape#1@parserspace}##1#2 \normal@nil} + {\skvcsuse{\skvremovescape#1@spaceparser}##1#2##2\normal@nil}% + }% + \long\skvcsdef{\skvremovescape#1@parserspace}##1#2 ##2\normal@nil{% + \skvifblankTF{##2} + {\skvcsuse{\skvremovescape#1@doubleparser}##1#2#2\normal@nil} + {\skvcsuse{\skvremovescape#1@parserspace}##1#2##2\normal@nil}% + }% + \long\skvcsdef{\skvremovescape#1@doubleparser}##1#2#2##2\normal@nil{% + \skvifblankTF{##2} + {\skvifblankTF{##1}{}{\expandafter\expandafter\expandafter + \space\expandafter\noexpand\@gobble##1}}% + {\skvcsuse{\skvremovescape#1@doubleparser}##1#2##2\normal@nil}% + }% +} + +\lpsdeclarelistnormalizer\lpscommanormalize{,} +\lpsdeclarelistnormalizer\lpsslashnormalize{/} + +% Declare an expandable csv list parser. No premature stopping of the loop +% is possible by this scheme. To use, first do +% +% \lpsdeclareexpandablelistparser<processor.cmd><processor.func>{<parser>} +% \def<processor.function>{<1-parameter callback>} +% +% and then call +% +% <processor.cmd><list> or <processor.cmd>*<listcmd>. +% +% Example: +% +% \lpsdeclareexpandablelistparser\myloop\do{,} +% +% \def\x{a,\if,b} +% \def\do#1{\unexpanded{{#1}}} +% \edef\x{\myloop*\x} +% +\skvrobustdef*\lpsdeclareexpandablelistparser#1#2#3{% + % No need to save the processor.cmd and processor.function in a list. + \skvaftercs\lpsdeclarelistnormalizer{\skvremovescape#1@normalizer}{#3}% + \begingroup + \let\x\skvnoexpandcs + \skvexpanded{\endgroup + \skvnewdef*\noexpand#1{% + \noexpand\skvxifnextchar*% + {\x{lps@parse@\skvremovescape#1@a}{\noexpand\@firstoftwo}} + {\x{lps@parse@\skvremovescape#1@a}{\noexpand\@secondoftwo}}% + }% + \def\x{lps@parse@\skvremovescape#1@a}####1####2{% + \noexpand\expandafter\x{lps@parse@\skvremovescape#1@b}% + \unexpanded{\romannumeral-`\q}####1{% + \noexpand\expandafter\x{\skvremovescape#1@normalizer}% + \noexpand\expandafter{####2}% + }{% + \x{\skvremovescape#1@normalizer}{####2}% + }% + #3\noexpand#1#3% + }% + \def\x{lps@parse@\skvremovescape#1@b}####1#3{% + \noexpand\skvifxTF{\noexpand#1}{####1}% + {}{\noexpand#2{####1}\x{lps@parse@\skvremovescape#1@b}}% + }% + }% +} + +\skvrobustdef*\lpsAtBeginEnvironment#1{% + \skvaftercs\skvappendtomacro{lps@atbegin@#1@hook}% +} +\skvrobustdef*\lpsAtEndEnvironment#1{% + \skvaftercs\skvappendtomacro{lps@atend@#1@hook}% +} + +\skvpatchcmd\begin + {\csname#1\endcsname} + {\skvcsuse{lps@atbegin@#1@hook}\csname#1\endcsname} + {} + {\skv@err{Patching '\string\begin' failed!\MessageBreak + '\string\lpsAtBeginEnvironment' will not work\@gobble}\@ehd + } + +\skvpatchcmd\end + {\csname end#1\endcsname} + {\skvcsuse{lps@atend@#1@hook}\csname end#1\endcsname} + {} + {\skv@err{Patching '\string\end' failed!\MessageBreak + '\string\lpsAtEndEnvironment' will not work\@gobble}\@ehd + } + +% Without the following patch, drawing intructions like +% +% \draw[blue] (p) \newforeach \p in {1,...,8}{...}; +% +% will not work, because of the way tikZ hardwires \foreach +% for this type of task. +% +\lpsAtBeginEnvironment{tikzpicture}{% + \def\tikz@handle@more{% + \ifx\@let@token a\let\@next=\tikz@arcA\else + \ifx\@let@token e\let\@next=\tikz@e@char\else + \ifx\@let@token g\let\@next=\tikz@g@char\else + \ifx\@let@token s\let\@next=\tikz@schar\else + \ifx\@let@token |\let\@next=\tikz@vh@lineto\else + \ifx\@let@token p\let\@next=\tikz@pchar\pgfsetmovetofirstplotpoint + \else\ifx\@let@token t\let\@next=\tikz@to\else + \ifx\@let@token\pgfextra\let\@next=\tikz@extra\else + \ifx\@let@token\foreach\let\@next=\tikz@foreach\else + \ifx\@let@token\newforeach\let\@next=\tikz@foreach\else + \ifx\@let@token\pgf@stop\let\@next=\relax\else + \ifx\@let@token\par\let\@next=\tikz@scan@next@command\else + \ifx\@let@token d\let\@next=\tikz@decoration\else + \ifx\@let@token l\let\@next=\tikz@l@char\else + \let\@next=\tikz@expand\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \fi\fi\fi\fi\@next + }% +} + \loops@restorecodes \endinput |