summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/loops
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2012-11-06 22:35:43 +0000
committerKarl Berry <karl@freefriends.org>2012-11-06 22:35:43 +0000
commit705b4d8f092a56d9ae900940d265fb6f55b3033d (patch)
tree8299b4712f70eff6211da7326d99ebd33ba035cc /Master/texmf-dist/tex/latex/loops
parent2f6000f28f9662342c1cfe6e59abfdf345bd3a23 (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')
-rw-r--r--Master/texmf-dist/tex/latex/loops/loops.sty414
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