diff options
author | Karl Berry <karl@freefriends.org> | 2012-10-17 22:50:05 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2012-10-17 22:50:05 +0000 |
commit | df2ce83ed9a6a3beca08c07cc656611e26d220d7 (patch) | |
tree | 086e2f15b6585eb8151e83f7852eb858db2f4b80 /Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex | |
parent | 468e15f0c59bbedcccfaa606c1f72d3b6d3a8f9a (diff) |
skeyval
git-svn-id: svn://tug.org/texlive/trunk@28005 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex')
-rw-r--r-- | Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex | 2583 |
1 files changed, 2583 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex b/Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex new file mode 100644 index 00000000000..b02ed4f91ed --- /dev/null +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex @@ -0,0 +1,2583 @@ +%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% +% This is file 'skeyval-for', 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. % +% % +% The following files constitute the skeyval bundle and must be % +% distributed as a whole: % +% % +% readme, skeyval.sty, skeyval-core.tex, skeyval-for.tex, % +% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, % +% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % +% and skeyval-testpkg.sty. % +% % +% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% + +\csname skeyval-for-loaded\endcsname +\expandafter\let\csname skeyval-for-loaded\endcsname\endinput + +\edef\skv@for@restorecatcodes{% + \catcode`\noexpand\@\the\catcode`\@\relax + \let\noexpand\skv@for@restorecatcodes\relax +} +\catcode`\@=11\relax + +\ifx\ProvidesFile\@undefined + \message{File 'skeyval-for.tex' 2012/10/15 v1.1 + Loops for skeyval package (AM)} +\else + \ProvidesFile{skeyval-for.tex} + [2012/10/15 v1.1 Loops for skeyval package (AM)] + \@addtofilelist{skeyval-for.tex} +\fi + +\skvrobustdef*\skv@nostackerr{\skv@err{You've called empty stack}\@ehd} +% \skvsavestate<base-fn>{<fn-list>}<counter> +\skvrobustdef*\skvsavestate#1#2#3{% + \skvgadvanceno#3\@ne + \begingroup + \let\s\string\escapechar\m@ne + \def\skv@prova##1{\s##1@skv@\romannumeral#3}% + \def\do##1{\let\noexpand##1\skvnoexpandcs{\skv@prova{##1}}}% + \skvifcsdef{\s#1@skv@stack}{}{\skvcsdef{\s#1@skv@stack}{\nostack}}% + \skvcsxdef{\s#1@skv@stack}{#2{\skvexpandcsonce{\s#1@skv@stack}}}% + \def\do##1{\let\skvnoexpandcs{\skv@prova{##1}}\noexpand##1}% + \edef\reserved@a{\endgroup#2}\reserved@a +} +% \skvrestorestate<base-fn><counter> +\skvrobustdef*\skvrestorestate#1#2{% + \begingroup + \let\nostack\skv@nostackerr + \edef\skv@elt{\skvnoexpandcs{\skvremovescape#1@skv@stack}}% + \expandafter\ifx\skv@elt\relax + \skv@err{Stack of '\noexpand#1' is undefined}\@ehd + \fi + \edef\skv@prova{\skvexpandtwice\skv@elt}% + \edef\skv@provb##1##{\endgroup##1\gdef\skvexpandonce\skv@elt}% + \expandafter\skv@provb\skv@prova + \skvgadvanceno#2\m@ne +} + +\skvnewregisters\bool{\ifskvbreakloop\ifforeachlastitem + \ifskvprocessempty\ifskv@tempst\ifskv@foreach@swa + \ifskv@foreach@swb\ifskv@foreach@parenth +} +\skvnewnumbers[skv@]{csvdepth,dolistcnt} + +\skvrobustdef*\skv@usetempst#1#2{% + \edef#2{\skvifdefbool{skv@tempst}\skvexpandonce\unexpanded{#1}}% +} +% +% \skvdolist{<parser>}{<list>}<holdercmd>{<callback>} +% \skvdolist*{<parser>}{<listcmd>}<holdercmd>{<callback>} +% +% 1. This can be nested to any depth, with different parsers on each +% level. +% 2. This will not process an empty list; see \skvecommaloop. +% 3. For comma lists, \skvcommaloop and \skvcommaparse are faster. +% See later. +% 4. For processing kv lists, use \skvkvparse. +% +\skvrobustdef*\skvdolist{\skv@testst\skv@dolist} +\skvrobustdef*\skv@dolist#1#2#3#4{% + \skvgadvanceno\skv@dolistcnt\@ne + \skv@usetempst{#2}#3% + \def\skv@dolist@a{skv@dolist@\skvrom\skv@dolistcnt}% + \skvcsdef{\skv@dolist@a}##1##2##3#1{% + \skvifstrcmp{##3}{\skv@dolist@nil}{% + % To allow nesting of loop: + \skvbreakloopfalse + }{% + \edef##1{\unexpanded{##3}}% + ##2\relax + \ifskvbreakloop + \skvbreakloopfalse + \begingroup + \skvcsdef{\skv@dolist@a}####1\skv@dolist@nil#1{\endgroup}% + \fi + \@nameuse{\skv@dolist@a}##1{##2}% + }% + }% + \skvifempty#3{}{% + \edef\reserved@a{\unexpanded{\@nameuse{\skv@dolist@a}#3{#4}}}% + \expandafter\reserved@a#3#1\skv@dolist@nil#1% + }% + \skvgadvanceno\skv@dolistcnt\m@ne +} + +% First normalize the list before parsing. +% +% \skvparselist{<parser>}{<list>}<holdercmd>{<callback>} +% \skvparselist*{<parser>}{<listcmd>}<holdercmd>{<callback>} +% +\skvrobustdef*\skvparselist{\skv@testst\skv@parselist} +\skvrobustdef*\skv@parselist#1#2#3{% + \skv@usetempst{#2}#3% + \skvcsvnormalize[#1]#3% + \skv@tempsttrue + \skv@dolist{#1}#3#3% +} + +\skvifdefinable\listbreaker{\let\listbreaker\relax} +\skvifdefinable\listpauser{\let\listpauser\relax} +\skvnewdef*\skv@listbreakertoks{\listbreaker} +\skvnewdef*\skv@listpausertoks{\listpauser} + +\skvnewlet\skvprocessempty\skvprocessemptytrue +\skvletmanytocmd{\skvbreakloop\interruptloop\skvbreakforeach + \interruptforeach}\skvbreaklooptrue + +% Reversing tokens: +\skvnewdef*\skvreverse#1{\skv@reverse#1\skv@reverse@stop} +\skvnewdef*\skv@reverse#1#2\skv@reverse@stop{% + \if\relax\detokenize{#2}\relax\skv@reverse@stop\fi + \skv@reverse#2\skv@reverse@stop\skvreversedo{#1}% +} +\skvnewdef*\skv@reverse@stop#1\skv@reverse@stop{\fi} +\let\skvreversedo\@iden + +\skvrobustdef*\skv@removetrailingparser#1#2{% + \skvxifin{\detokenize{#1}\relax}{\skvoxdetok#2\relax}{% + \def\skv@prova##1#1\skv@trim@nil{\unexpanded{##1}}% + \edef#2{\expandafter\skv@prova#2\skv@trim@nil}% + }{}% +} + +% \skvrecurse<body>\while<\if...>\fi +% +% On entry, the condition is checked before the body is executed. +% +% \@tempcnta\z@ +% \skvrecurse{ +% \advance\@tempcnta\@ne +% \@tempcntb\z@ +% \skvrecurse +% \advance\@tempcntb\@ne +% \typeout{Doing \the\@tempcnta,\the\@tempcntb} +% \while +% \ifnum\@tempcntb<3 +% \fi +% } +% \while +% \ifnum\@tempcnta<4 +% \fi +% +\skvrobustdef\skvrecurse#1\while#2\fi{% + \@expandtwoargs\skv@dobody{\skvtrimspace{#2}}{\skvtrimspace{#1}}% +} +\skvrobustdef\skv@dobody#1#2{% + #1\relax\expandafter\@iden\else\expandafter\@gobble\fi + {#2\relax\skv@dobody{#1}{#2}}% +} + +% A version of LaTeX's \@tfor that can parse undoubled parameter +% characters. +% +% \skvtfor<holder.cmd>{<list>}\do{<callback>} +% \skvtfor*<holder.cmd>{<listcmd>}\do{<callback>} +% +% Example: +% +% \skvnewregister\count\nr +% \skvtfor\x:=a \ifx {\def\x#1{#1}} \fi\do{% +% \nr\z@ +% \skvtfor\y:=12345\do{% +% \typeout{Doing: \detokenize\expandafter{\x}--\y}% +% \advance\nr\@ne +% \ifnum\nr>\tw@\skvbreakloop\fi +% } +% } +% +\skvnewdef*\skv@tfor@nil{\skv@tfor@nil} +\skvrobustdef*\skvtfor{\skv@testst\skv@tfor} +\skvrobustdef*\skv@tfor#1:={\skv@tf@r#1 } +\skvrobustdef\skv@tf@r#1#2\do#3{% + \edef#1{\skvtrimspace{#2}}% + \edef#1{\skvifbool{skv@tempst}\skvexpandtwice\skvexpandonce{#1}}% + \skvifempty#1{}{% + \skvbreakloopfalse + \expandafter\skv@tforloop#1\skv@tfor@nil\skv@tfor#1{#3}% + }% +} +\skvrobustdef\skv@tforloop#1#2\skv@tfor#3#4{% + \edef#3{\unexpanded{#1}}% + \skvifx#3\skv@tfor@nil{% + \skvbreakloopfalse + }{% + #4\relax + \ifskvbreakloop + \skvbreakloopfalse + \begingroup + \def\skv@tforloop##1\skv@tfor@nil\skv@tfor##2##3{% + \endgroup + \edef\skvremainder{\unexpanded{##1}}% + }% + \fi + \skv@tforloop#2\skv@tfor#3{#4}% + }% +} + +% Non-expandable comma loops +% +% 1. These follow from \skvdolist and \skvparselist, but they are +% specialized for comma lists and they are faster. +% 2. They can be nested. +% 3. \skvecommaloop needs \skv@c@mmaloop. +% +% \skvcommaloop{<list>}<holder-cmd>{<callback>} +% \skvcommaloop*{<listcmd>}<holder-cmd>{<callback>} +% +\skvrobustdef*\skvcommaloop{\skv@testst\skv@commaloop} +\skvrobustdef\skv@commaloop#1#2#3{% + \skv@usetempst{#1}#2% + % Don't put \skvcsvnormalize#2 here. Use \skvcommaparse instead. + % Some callers of \skvcommaloop already have their lists normalized. + \skvifx#2\@empty{}{% + \skvexpandnext{\skv@c@mmaloop#2{#3}}#2,\skv@commaloop@nil,% + }% +} +\skvrobustdef\skv@c@mmaloop#1#2#3,{% + \skvifstrcmp{#3}{\skv@commaloop@nil}{% + \skvbreakloopfalse + }{% + \edef#1{\unexpanded{#3}}% + #2\relax + \ifskvbreakloop + \skvbreakloopfalse + \begingroup + \long\def\skv@c@mmaloop##1\skv@commaloop@nil,{\endgroup}% + \fi + \skv@c@mmaloop#1{#2}% + }% +} +% +% \skvecommaloop{<list>}<cmd>{<callback>} +% \skvecommaloop*{<listcmd>}<cmd>{<callback>} +% +% \skvecommaloop is as \skvcommaloop but will execute <callback> +% once when <list> is empty. This is needed for processing empty +% families. +% +\skvrobustdef\skvecommaloop{\skv@testst\skv@ecommaloop} +\skvrobustdef\skv@ecommaloop#1#2#3{% + \edef#2{\unexpanded{\skv@c@mmaloop#2{#3}}}% + \ifskv@tempst\expandafter\expandafter\fi#2#1,\skv@commaloop@nil,% +} +% +% \skvcommaparse{<list>}<cmd>{<callback>} +% \skvcommaparse*{<listcmd>}<cmd>{<callback>} +% +% \skvcommaparse is as \skvcommaloop but will first normalize <list> +% using \skvcsvnormalize. +% +\skvrobustdef*\skvcommaparse{\skv@testst\skv@commaparse} +\skvrobustdef\skv@commaparse#1#2#3{% + \skv@usetempst{#1}#2% + \skvcsvnormalize#2% + \skvcommaloop*#2#2{#3}% +} +% +% \skvkvparse{<list>}<cmd>{<callback>} +% \skvkvparse*{<listcmd>}<cmd>{<callback>} +% +% \skvkvparse is as \skvcommaloop but will first normalize <list> using +% \skvkvnormalize. +% +\skvrobustdef*\skvkvparse{\skv@testst\skv@kvparse} +\skvnewlet\skvparsekeyvals\skvkvparse +\skvrobustdef\skv@kvparse#1#2#3{% + \skv@usetempst{#1}#2% + \skvkvnormalize#2% + \skvcommaloop*#2#2{#3}% +} +% + +% \skv@foreach@normalize[<parser>]<listcmd> +\skvrobustdef*\skv@foreach@normalize{\skv@testopt\skv@foreach@norm@lize,} +\skvrobustdef*\skv@foreach@norm@lize[#1]#2{% + \skvxifntype{\detokenize{#1}}\skvcsvnormalize\skvmacnormalize[#1]#2% +} + +% \newforeach[<options>] <holders> {<list>} {<callback>} +% \newforeach*[<options>] <holders> {<listcmd>} {<callback>} +% \newforeach[<options>] <holders> in {<list>} do {<callback>} +% \newforeach*[<options>] <holders> in {<listcmd>} do {<callback>} +% \newforeach[<options>] <holders> in {<list>} <callback> ; +% \newforeach*[<options>] <holders> in {<listcmd>} <callback> ; +% +% 1. <callback> is the code that will be executed for each element +% of the list. It will refer to the holder macros <holders>. +% +% 3. Elements of the form (a,b) and [a,b] are grabbed together. +% +% 4. Use \interruptforeach to break out of the loop prematurely. +% +% 5. \newforeach can be nested. + +% \skv@foreach@sisterdepth must be different from \foreachdepth, +% to avoid confusing two different stacks. +\skvnewnumbers{foreachdepth,skv@foreach@sisterdepth,skv@foreach@nra,% + skv@warnsubparser} +\skvnewdef*\skv@foreach@onlyinitially{} +\skvrobustdef*\skv@foreach@assignonce#1{% + \edef\skv@foreach@onlyinitially{% + \skvexpandonce\skv@foreach@onlyinitially + \unexpanded{#1}% + }% +} +% \skv@foreach@addtocallback{<pre.or.post>}{<code.to.add>} +\skvrobustdef*\skv@foreach@addtocallback#1#2{% + \skvcsedef{skv@foreach@#1callback}{% + \skvifcsundef{skv@foreach@#1callback}{}{% + \skvexpandcsonce{skv@foreach@#1callback}% + }% + % No \unexpanded for #2 here, since #2 is to be expanded: + #2% + }% +} + +\skvnewlet\skv@foreach@codemark\relax +\skvrobustdef*\skv@foreach@addtohook#1#2#3{% + \begingroup + \skvifdef#2{}{\def#2{}}% + \edef\x{\detokenize{\skv@foreach@codemark#3\skv@foreach@codemark}}% + \skvxifin\x{\skvoxdetok#2}{}{% + \edef#2{% + \skvifstrcmp{#1}{pre}{% + \skv@foreach@codemark\unexpanded{#3}\skv@foreach@codemark + \skvexpandonce{#2}% + }{% + \skvexpandonce{#2}% + \skv@foreach@codemark\unexpanded{#3}\skv@foreach@codemark + }% + }% + }% + \skvaftergroupdef#2\endgroup +} + +% \prependtobeginforeach[<depths>]{<code>} +\skvrobustdef*\prependtobeginforeach{% + \skv@testopt{\skv@atbeginforeach{pre}}{}% +} +% \appendtobeginforeach[<depths>]{<code>} +\skvrobustdef*\appendtobeginforeach{% + \skv@testopt{\skv@atbeginforeach{app}}{}% +} +\skvnewlet\atbeginforeach\appendtobeginforeach +\skvrobustdef*\skv@atbeginforeach#1[#2]#3{% + \skvifblank{#2}{% + \skvaftercsname{\skv@foreach@addtohook{#1}}% + {skv@foreach@atbeginhook@\skvrom\@ne}{#3}% + }{% + \skvcommaloop{#2}\skv@tempa{% + \skvaftercsname{\skv@foreach@addtohook{#1}}% + {skv@foreach@atbeginhook@\skvrom\number\skv@tempa}{#3}% + }% + }% +} +% \prependtoendforeach[<depths>]{<code>} +\skvrobustdef*\prependtoendforeach{% + \skv@testopt{\skv@atendforeach{pre}}{}% +} +% \appendtoendforeach[<depths>]{<code>} +\skvrobustdef*\appendtoendforeach{% + \skv@testopt{\skv@atendforeach{app}}{}% +} +\skvnewlet\atendforeach\appendtoendforeach +\skvrobustdef*\skv@atendforeach#1[#2]#3{% + \skvifblank{#2}{% + \skvaftercsname{\skv@foreach@addtohook{#1}}% + {skv@foreach@atendhook@\skvrom\@ne}{#3}% + }{% + \skvcommaloop{#2}\skv@tempa{% + \skvaftercsname{\skv@foreach@addtohook{#1}}% + {skv@foreach@atendhook@\skvrom\number\skv@tempa}{#3}% + }% + }% +} +% \atbeginforeachondepth{<depths>}{<code>} +\skvrobustdef*\atbeginforeachondepth#1#2{% + \appendtobeginforeach[#1]{#2}% +} +% \atendforeachondepth{<depths>}{<code>} +\skvrobustdef*\atendforeachondepth#1#2{% + \appendtoendforeach[#1]{#2}% +} + +% \skv@foreach@fi must use \detokenize. Don't change to \string! +\skvnewedef*\skv@foreach@fi{\detokenize{\fi}} +\skvnewedef*\skv@foreach@if{\string\if} + +% \skv@foreach@ifacceptkv and \skv@foreach@maketester must come +% before the initialization of keys: +\skvrobustdef*\skv@foreach@ifacceptkv#1#2{% + \def\next{}% + \ifskvindef\else + \edef\skv@prova{\unexpanded{#1}}% + \ifnum0>\numexpr0\ifx\skv@prova\@empty-1\else + \ifx\skv@prova\@nnil-1\else+0\fi\fi\relax\relax + \skv@err{Invalid syntax '\detokenize{#1}'}\@ehd + \else + \edef\next{\unexpanded{#2}}% + \fi + \fi + \next +} +\skvrobustdef*\skv@foreach@ifholderisonecmd#1#2#3{% + \skvifntype{#2}{% + \skvifescaped{#2}{% + #3% + }{% + \skv@err{Value of key '#1' must + \MessageBreak be escaped: the holder macro + \MessageBreak to be evaluated}\@ehd + }% + }{% + \skv@err{Value of key '#1' must + \MessageBreak be only one token: the holder + \MessageBreak macro to be evaluated}\@ehd + }% +} +% \skv@foreach@maketester{<cond>}<cond.tester.cmd>{<flag>} +% +% 1. Only balanced conditionals beginning with \if...\fi are allowed. +% Restricting the type of allowed conditionals is necessary for +% auto syntax checking. +% 2. <flag> is either 0 or 1, signifying whether or not the condition +% should be entered in postcallback. +% +% Examples: \ifnum\x>10\fi, \ifx\x\cmd\fi. +% +\skvrobustdef*\skv@foreach@maketester#1#2#3{% + % Make '#1' innocent in a macro, in case it contains parameter + % characters. \skv@prova will appear only in the error message. + \begingroup + \edef\skv@prova{\detokenize{#1}}% + \skvifblank{#1}{% + \skv@err{A blank conditional given in \string\newforeach}\@ehd + }{% + \skvxifin{\skv@foreach@fi\relax}{\detokenize{#1}\relax}{% + \skvxifin{\relax\skv@foreach@if}{\relax\detokenize{#1}}{% + \edef#2{\noexpand\skvifcondition\unexpanded{#1}}% + \ifnum#3=\@ne + \skv@foreach@addtocallback{post}{% + \unexpanded{\skvifcondition#1}{\noexpand\skvbreakloop}{\relax}% + }% + \fi + }{% + \skv@err{Illegal conditional '\skv@prova'} + {Invalid, possibly unbalanced, conditional '\skv@prova'}% + }% + }{% + \skv@err{Illegal conditional '\skv@prova'}\@ehd + }% + }% + \skvexpanded{\endgroup + \skvcmdexit#2% + \ifnum#3=\@ne + \skvcmdexit\skv@foreach@postcallback + \fi + }% +} + +\begingroup +\catcode`P=12 \lccode`P=112 +\catcode`T=12 \lccode`T=116 +\lowercase{\endgroup + \def\skv@foreach@strippoint#1#2{% + \def\reserved@a##1#1\relax{\def#2{##1}}% + \def\do##1.##2PT#1{% + \ifx\do##1\else##1% + \if\skv@foreach@keephighdecimals + \ifdim.##2pt>.5pt\relax##2\fi + \else + \if\skv@foreach@keepdecimals + \ifnum##2>\skvz@.##2\fi + \fi + \fi + \unexpanded{#1}% + \expandafter\do + \fi + }% + \edef#2{\expandafter\do#2#1\do.PT#1}% + \expandafter\reserved@a#2\relax + } +} + +\quickkeys.define{skvforeach}{% + .exec/ + \def\skv@foreach@parser{,} + \def\skv@foreach@subparser{/} + ; + parser/{,}/ + \ifskvindef\else + \edef\skv@foreach@parser{\unexpanded{#1}} + \skvstripouterbraces{2}\skv@foreach@parser + \skvxifntype{\detokenize{#1}}{% + \begingroup + % It is assumed that every n-type parser and subparser + % must have catcode 12: + \skvexpandnext{\catcode`}\skv@foreach@parser=12\relax + \skv@rescan\skv@foreach@parser + \skvaftergroupdef\skv@foreach@parser\endgroup + }{} + \fi + ; + subparser/{/}/ + \ifskvindef\else + \edef\skv@foreach@subparser{\unexpanded{#1}} + \skvstripouterbraces{2}\skv@foreach@subparser + \skvxifntype{\detokenize{#1}}{ + \begingroup + \skvexpandnext{\catcode`}\skv@foreach@subparser=12\relax + \skv@rescan\skv@foreach@subparser + \skvaftergroupdef\skv@foreach@subparser\endgroup + }{} + \fi + ; + terminator,callback terminator/{;}/ + \edef\skv@foreach@terminator{\unexpanded{#1}}% + \skvstripouterbraces{2}\skv@foreach@terminator + ; + list is a macro,macro list/true/ + \edef\skv@foreach@listismacro{0\skvifstrcmp{true}{#1}01}% + /true,false + ; + % process up to = <nr> + % Maximum number of items to process: + process up to,process up to number/\@nil/ + \ifskvindef\else + \def\skv@foreach@processupto{#1}% + \ifx\skv@foreach@processupto\@nnil\else + \skv@ensureinteger{process up to}{#1}% + \fi + \fi + ; + process empty list/true/ + \edef\skv@foreach@processempty{0\skvifstrcmp{true}{#1}01}% + /true,false + ; + % Eg, exit when=\ifnum\x=20\fi + .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\@ne + \fi + ; + % Eg, 'evaluate = \x as \z using \numexpr\x*2'. 'as' and 'using', and the + % tokens after them, can be missing, but the formula must be complete. + evaluate/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreach@parseevaluate{#1}% + }% + ; + % The evaluator \numexpr will invariably be used internally for this key. + % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'. + evaluate num,evaluate number/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreach@ifholderisonecmd{evaluate number}{#1}{% + \skv@foreach@parseevaluate{#1as#1using\numexpr#1}% + }% + }% + ; + % The evaluator \dimexpr will invariably be used internally for this key. + % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'. + evaluate dim,evaluate dimension/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreach@ifholderisonecmd{evaluate dimension}{#1}{% + \skv@foreach@parseevaluate{#1as#1using\dimexpr#1}% + }% + }% + ; + % Eg, 'expand=\x'. + % Fully expand holder macro. This is equivalent to, eg, edef\x{\x}. + % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'. + expand,expanded/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreach@ifholderisonecmd{expand}{#1}{% + \skv@foreach@parseevaluate{#1as#1using#1}% + }% + }% + ; + % Eg, 'pgf parse = \x as \xe using \x*3'. 'as' and 'using', and the + % tokens after them, can be present or missing. + % \pgfmathparse is always used for this key. + pgf evaluate,pgf parse,pgfmath parse/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreach@parsepgfmathparse{#1}% + }% + ; + % count in = \y all \x satisfying <condition> initially <value> + % Eg, + % count in = \p all \x satisfying \ifnum\x>4\fi, or + % count in = \p all \x satisfying \skvifnum\x>4 + % The counting is not additive, meaning that the counter is initialized + % to zero on each depth. + count in,count/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreach@parsecountin{#1}% + }% + ; + % Eg, 'remember=\x as \y initially A': + remember/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreach@parseremember{#1}% + }% + ; + % Eg, 'recall=\x initially A'. + % 'recall' is as 'remember', but will save the value of the holder macro + % in \<foreachlast><holder>. 'as' is invalid/illegal here, since a + % retainer macro is built internally: + retain,recall,call up/\@nil/ + \skv@foreach@ifacceptkv{#1}{% + \skv@foreach@parserecall{#1}% + }% + ; + item counter,counter/\@nil/ + \ifskvindef\else + \edef\skv@prova{\unexpanded{#1}}% + \ifx\skv@prova\@nnil + \skv@err{Invalid empty value for key 'item counter'}\@ehd + \else + \skvifescaped{#1}{% + \let\skv@foreach@itemcounter\skv@prova + }{% + \skv@err{Non-escaped value '\detokenize{#1}' + \MessageBreak for key 'item counter'}\@ehd + }% + \fi + \fi + ; + list breaker/\listbreaker/ + \ifskvindef\else + \edef\skv@prova{\unexpanded{#1}}% + \ifx\skv@prova\@empty + \skv@err{Invalid empty value for key 'list breaker'}\@ehd + \else + \let\skv@listbreakertoks\skv@prova + \fi + \fi + ; + list pauser/\listpauser/ + \ifskvindef\else + \edef\skv@prova{\unexpanded{#1}}% + \ifx\skv@prova\@empty + \skv@err{Invalid empty value for key 'list pauser'}\@ehd + \else + \let\skv@listpausertoks\skv@prova + \fi + \fi + ; + % Remember outside the loop the holder values. Of course, this + % means remembering only the latest values. + recover holder values,recover holder values after loop/true/ + \edef\skv@foreach@recoverholders{0\skvifstrcmp{true}{#1}01}% + /true,false + ; + % 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 + ; + % This key means that, eg, for \x/\y, do \let\y=\x if \y has no + % user value, ie, if the user gives as an item 'a' instead of + % 'a/b' or 'a/a'. + inherit/true/ + \edef\skv@foreach@inherit{0\skvifstrcmp{true}{#1}01} + /true,false + ; + expand before fill/true/ + \edef\skv@foreach@expandbeforefill{0\skvifstrcmp{true}{#1}01} + /true,false + ; +} + +% The following keys don't need a default value: +% +% link,evaluate,*evaluate,evaluate num,*evaluate num, +% evaluate dim,*evaluate dim,expand,*expand,count in,*count in, +% loop stopper,process up to,grow +% +\skvinitializeqkeys{skvforeach}{% + parser, + subparser, + callback terminator, + list is a macro=false, + process up to, + process empty list=false, + item counter, + list breaker, + list pauser, + recover holder values=false, + grow left=false, + grow right=false, + keep decimals=true, + keep high decimals=false, + inherit=false, + expand before fill=false, +} + +\skvnewdef*\skv@foreach@kvlist{} +% \setupforeach{<kvlist>} +\skvrobustdef*\setupforeach#1{% + \skvifblank{#1}{}{% + \skvaddtolist\skv@foreach@kvlist{#1}% + }% +} +\skvrobustdef*\skv@foreach@setkeys#1{% + \def\reserved@a{\quickkeys.set{skvforeach}}% + \expandafter\reserved@a\expandafter{\skv@foreach@kvlist,#1}% +} + +% evaluate=<holder.macro> as <child.macro> using <formula> +% +% 1. Evaluation is done with \edef unless \pgfmathparse is present +% in <formula>. +% +% 2. <formula> must be a valid formula, eg, +% +% \pgfmathparse\x*2 +% \pgfmathparse{exp(50)*\x*2+sin(.5*pi)*60} +% \numexpr\x*2 +% \skvexpandonce\x +% +% or simply +% +% 'evaluate \x as \x using <empty>' +% +% The latter is equivalent to asking for full expansion. See also +% the keys 'evaluate num', 'evaluate dim', and 'expand'. +% +% 3. This allows <formula> to be generic. +% +\skvrobustdef*\skv@foreach@parseevaluate#1{% + \begingroup + \def\skv@tempxifin##1##2{% + \skvxifin{\detokenize{##1}}{\detokenize{##2}}% + }% + \skv@foreach@swafalse + \def\skv@tempd{}% + \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' has no holder macro}\@ehd + \else + \expandafter\skvifescaped\expandafter{\skv@prova}{% + \expandafter\skvifntype\expandafter{\skv@prova}{}{% + \skv@err{Value of key 'evaluate': more than 1 + \MessageBreak token \skvoxdetok\skv@prova. + \MessageBreak I can't find holder macro}\@ehd + }% + }{% + \skv@err{Value of key 'evaluate': + \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\@ehd + }% + \fi + \ifx\skv@provb\@empty + \skv@err{Value of key 'evaluate' has no child macro}\@ehd + \else + \expandafter\skvifescaped\expandafter{\skv@provb}{% + \expandafter\skvifntype\expandafter{\skv@provb}{}{% + \skv@err{Value of key 'evaluate': more than 1 + \MessageBreak token \skvoxdetok\skv@provb. + \MessageBreak I can't find child macro}\@ehd + }% + }{% + \skv@err{Value of key 'evaluate': + \MessageBreak child \skvoxdetok\skv@provb not escaped}\@ehd + }% + \fi + \ifx\skv@provc\@empty + \skv@err{Value of key 'evaluate' has no formula or + \MessageBreak holder macro to be expanded}\@ehd + \fi + \skv@tempxifin{\pgfmathparse}{##3}{% + \def\skv@tempc####1\pgfmathparse####2\skv@nil{% + \ifx\@nnil####1\@nnil + \skv@foreach@swatrue + \else + \skv@err{Invalid token \detokenize{####1} + \MessageBreak before \string\pgfmathparse}\@ehd + \fi + }% + \skv@tempc##3\skv@nil + }{% + \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: maybe 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. Maybe the key is 'expand' or still 'evaluate' + % but without formula. + \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 holder macro}\@ehd + \else + \ifx\@nnil##2% + \skv@err{Value of key 'evaluate' has no child macro}\@ehd + \else + \skv@tempa##1as##2using##1\skv@nil + \fi + \fi + }% + \skv@tempb#1{\@nnil}\skv@nil + }{% + % No 'as' or 'using': #1 should be only the holder macro: + \ifx\@nnil#1\@nnil + \skv@err{Value of key 'evaluate' has no holder macro}\@ehd + \else + \skvifntype{#1}{% + % Expand the holder macro: + \skv@tempa#1as#1using#1\skv@nil + }{% + \skv@err{Value of key 'evaluate': more than 1 + \MessageBreak token '\detokenize{#1}'. + \MessageBreak I can't find holder macro}\@ehd + }% + \fi + }% + }% + \skv@foreach@addtocallback{afterpre}{% + \ifskv@foreach@swa + % <formula> has the syntax \pgfmathparse{\x}. + \skvexpandonce\skv@provc + \let\skvexpandonce\skv@provb\noexpand\pgfmathresult + \else + % <formula> has the syntax \numexpr\x*2 or \dimexpr\x*2. + % \ifskv@foreach@swb is true when a formula has been given. + \edef\skvexpandonce\skv@provb{% + \ifskv@foreach@swb\noexpand\the\fi + \skvexpandonce\skv@provc\skv@tempd + }% + \fi + }% + \skvaftergroupdef\skv@foreach@afterprecallback\endgroup +} + +% pgfmath parse=<holder.macro> as <child.macro> using <formula> +% +% 1. Evaluation is always done with \pgfmathparse. +% +% 2. <formula> must be \pgfmathparse-able. +% +\skvrobustdef*\skv@foreach@parsepgfmathparse#1{% + \begingroup + \ifdefined\pgfmathparse\else + \skv@err{No \string\pgfmathparse; 'pgfmath' module not loaded}\@ehd + \fi + \def\skv@tempxifin##1##2{% + \skvxifin{\detokenize{##1}}{\detokenize{##2}}% + }% + \skv@foreach@swafalse + \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 'pgfmath parse' has no holder macro}\@ehd + \else + \expandafter\skvifescaped\expandafter{\skv@prova}{% + \expandafter\skvifntype\expandafter{\skv@prova}{}{% + \skv@err{Value of key 'pgfmath parse': more than 1 + \MessageBreak token \skvoxdetok\skv@prova. + \MessageBreak I can't find holder macro}\@ehd + }% + }{% + \skv@err{Value of key 'pgfmath parse': + \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\@ehd + }% + \fi + \ifx\skv@provb\@empty + \skv@err{Value of key 'pgfmath parse' has no child macro}\@ehd + \else + \expandafter\skvifescaped\expandafter{\skv@provb}{% + \expandafter\skvifntype\expandafter{\skv@provb}{}{% + \skv@err{Value of key 'pgfmath parse': more than 1 + \MessageBreak token \skvoxdetok\skv@provb. + \MessageBreak I can't find child macro}\@ehd + }% + }{% + \skv@err{Value of key 'pgfmath parse': + \MessageBreak child \skvoxdetok\skv@provb not escaped}\@ehd + }% + \fi + \ifx\skv@provc\@empty + \skv@err{Value of key 'pgfmath parse' has no formula or + \MessageBreak holder macro to be expanded}\@ehd + \fi + \skv@tempxifin{\pgfmathparse}{##3}{% + \def\skv@tempc####1\pgfmathparse####2\skv@nil{% + \ifx\@nnil####1\@nnil + \skv@foreach@swatrue + \else + \skv@err{Invalid token \detokenize{####1} + \MessageBreak before \string\pgfmathparse}\@ehd + \fi + }% + \expandafter\skv@tempc\skv@provc\skv@nil + }{% + \skv@tempxifin{\numexpr}{##3}{% + \skv@err{Value of key 'pgfmath parse': + \MessageBreak\noexpand\numexpr not allowed}\@ehd + }{% + \skv@tempxifin{\dimexpr}{##3}{% + \skv@err{Value of key 'pgfmath parse': + \MessageBreak\noexpand\dimexpr not allowed}\@ehd + }{% + \skv@foreach@swatrue + \edef\skv@provc{\noexpand\pgfmathparse{\skvexpandonce\skv@provc}}% + }% + }% + }% + }% + \skv@tempxifin{using}{#1}{% + \skv@tempxifin{as}{#1}{% + % 'as' and 'using' are present: maybe there is a formula. + \skv@tempa#1\skv@nil + }{% + \skv@err{Value of key 'pgfmath parse': + \MessageBreak there is 'using', but no 'as'}\@ehd + }% + }{% + \skv@tempxifin{as}{#1}{% + \def\skv@tempb##1as##2##3\skv@nil{% + \ifx\@nnil##1\@nnil + \skv@err{Value of key 'pgfmath parse' has no holder macro}\@ehd + \else + \ifx\@nnil##2% + \skv@err{Value of key 'pgfmath parse' has no child macro}\@ehd + \else + \skv@tempa##1as##2using##1\skv@nil + \fi + \fi + }% + \skv@tempb#1{\@nnil}\skv@nil + }{% + % No 'as' or 'using': #1 should be only the holder macro: + \ifx\@nnil#1\@nnil + \skv@err{Value of key 'pgfmath parse' has no holder macro}\@ehd + \else + \skvifntype{#1}{% + % Evaluate the holder macro: + \skv@tempa#1as#1using#1\skv@nil + }{% + \skv@err{Value of key 'pgfmath parse': more than 1 + \MessageBreak token '\detokenize{#1}'. + \MessageBreak I can't find holder macro}\@ehd + }% + \fi + }% + }% + \skv@foreach@addtocallback{afterpre}{% + \ifskv@foreach@swa + \skvexpandonce\skv@provc + \let\skvexpandonce\skv@provb\noexpand\pgfmathresult + \fi + }% + \skvaftergroupdef\skv@foreach@afterprecallback\endgroup +} + +% count in = \y all \x satisfying <condition> initially <value> +% +% 1. <condition> must be a balanced and valid TeX 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] in {a,...,e}'. +% +% Generic counting is available in \newforeach by default, without +% user request. The macros \foreachcurrentitem, \foreachitemcount, +% \foreachnextitem are always available on each nesting level. The +% boolean \ifforeachlastitem is also always available, to indicate when +% the last item of the list has been reached: +% +% \ifforeachlastitem \typeout{Processing last entry of the list} \fi +% +% 4. Counting is done from 1 (zero) unless <value> is given after +% 'initially'. +% +\skvrobustdef*\skv@foreach@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}{% + \expandafter\skvifntype\expandafter{\skv@prova}{}{% + \skv@err{Value of key 'count in': more than 1 + \MessageBreak token \skvoxdetok\skv@prova. + \MessageBreak I can't find counter macro}\@ehd + }% + }{% + \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 holder macro to test. The holder + % macro, on its own, isn't sufficient to conduct a test: + \let\skv@foreach@itemcounter\skv@prova + \else + \ifx\skv@provb\@empty\else + % If there isn't a holder macro or quantity to test, then no + % test is possible: + \expandafter\skvifescaped\expandafter{\skv@provb}{% + \expandafter\skvifntype\expandafter{\skv@provb}{}{% + \skv@err{Value of key 'count in': more than 1 + \MessageBreak token \skvoxdetok\skv@provb. + \MessageBreak I can't find holder macro}\@ehd + }% + }{% + \skv@err{Value of key 'count':\MessageBreak + holder macro \skvoxdetok\skv@provb not escaped}\@ehd + }% + \skv@foreach@swatrue + % \skv@tester is the second argument of \skv@foreach@maketester. + % \skv@tester is used in pushing the item counter: + \skvexpbracenext\skv@foreach@maketester\skv@provc\skv@tester\skvz@ + \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' or 'satisfying': #1 should be only the counter macro: + \ifx\@nnil#1\@nnil + \skv@err{Value of key 'count' has 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{afterpre}{% + \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@afterprecallback + \else + \skvcmdexit\skv@foreach@itemcounter + \fi + }% +} + +% remember=<holder.macro> as <child.macro> initially <value> +% +\skvrobustdef*\skv@foreach@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 holder macro: + \MessageBreak i.e., no macro that holds input}\@ehd + \else + \expandafter\skvifescaped\expandafter{\skv@prova}{}{% + \skv@err{Value of key 'remember': + \MessageBreak Holder macro \skvoxdetok\skv@prova not escaped}\@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': + \edef\skv@prova{\skvtrimspace{#1}}% + \ifx\skv@prova\@empty\else + \skv@tempa#1as initially\skv@nil + \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}{% + \let\skvexpandonce\skv@provb\skvexpandonce\skv@prova + }% + \fi + \skvexpanded{\endgroup + \ifskv@foreach@swa + \skvcmdexit\skv@foreach@precallback + \skvcmdexit\skv@foreach@postcallback + \fi + }% +} + +% recall=<holder.macro> initially <value>. +% +% This builds a retainer macro of the form \<foreachlast><holder.name>. +% +% 'as' is invalid/illegal here, since a retainer macro is built internally. +% +\skvrobustdef*\skv@foreach@parserecall#1{% + \begingroup + \def\skv@tempxifin##1##2{% + \skvxifin{\detokenize{##1}}{\detokenize{##2}}% + }% + \skv@tempxifin{(}{#1}{% + \skv@err{Value of key 'recall': '(' found. + \MessageBreak I don't accept this PGF format. + \MessageBreak remove the parenthesis '()'}\@ehd + }{}% + \skv@foreach@swafalse + \def\skv@tempa##1initially##2\skv@nil{% + \edef\skv@prova{\skvtrimspace{##1}}% + \edef\skv@provb{\skvtrimspace{##2}}% + \ifx\skv@prova\@empty + \skv@err{Value of key 'recall' has no holder macro: + \MessageBreak i.e., no macro that holds input}\@ehd + \else + \expandafter\skvifntype\expandafter{\skv@prova}{% + \expandafter\skvifescaped\expandafter{\skv@prova}{% + \edef\skv@elt{\expandafter\skvremovescape\skv@prova}% + \skv@foreach@swatrue + % 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 + \skvcsedef{foreachlast\skv@elt}{% + \noexpand\unexpanded{\skvexpandonce\skv@provb}% + }% + \noexpand\fi + }% + \skv@foreach@addtocallback{post}{% + \skvcslet{foreachlast\skv@elt}\skvexpandonce\skv@prova + }% + }{% + \skv@err{Value of key 'recall': + \MessageBreak \detokenize{#1} is not escaped}\@ehd + }% + }{% + \skv@err{Value of key 'recall': + \MessageBreak \detokenize{#1} is not one token}\@ehd + }% + \fi + }% + \skv@tempxifin{as}{#1}{% + \skv@err{Value of key 'recall': invalid 'as' found. + \MessageBreak This key doesn't expect 'as' since + \MessageBreak it automatically builds a retainer macro + \MessageBreak of the form \<foreachlast><holder.name>}\@ehd + }{% + \skv@tempxifin{initially}{#1}{% + \skv@tempa#1\skv@nil + }{% + \ifx\@nnil#1\@nnil\else + \skv@tempa#1initially\skv@nil + \fi + }% + }% + \skvexpanded{\endgroup + \ifskv@foreach@swa + \skvcmdexit\skv@foreach@precallback + \skvcmdexit\skv@foreach@postcallback + \fi + }% +} + +% Eg, \skv@dots@in<value>\skv@nil...\skv@nnil\skv@stop +\skvnewdef*\skv@dots@in#1...#2#3\skv@stop{% + \ifx\skv@nnil#2\in@false\else\in@true\fi +} + +\skvrobustdef*\skv@foreach@latehookerr{% + \def\skv@foreach@latehook{% + \begingroup + \let\s\string + \skv@err{A \noexpand\newforeach hook (\s\prependtobeginforeach, + \MessageBreak\s\appendtobeginforeach, \s\atbeginforeach, + \MessageBreak\s\prependtoendforeach, \s\appendtoendforeach, + \MessageBreak or \s\atendforeach) has been illegally + \MessageBreak issued within \s\newforeach} + {\s\newforeach\space hook command shouldn't be issued + within \s\newforeach.}% + \endgroup + }% + \skvletmanytocmd{% + \prependtobeginforeach\appendtobeginforeach\atbeginforeach + \prependtoendforeach\appendtoendforeach\atendforeach + }\skv@foreach@latehook +} + +\skvrobustdef*\skv@foreach@pushstate{% + \skvsavestate\skv@foreach@stack{% + \do\skv@foreach@parser\do\skv@foreach@subparser + \do\skv@foreach@listismacro + \do\skv@foreach@processupto\do\skv@foreach@processempty + \do\skv@foreach@exittester + \do\skv@foreach@grow\do\skv@foreach@growleft + \do\skv@foreach@growright + \do\skv@foreach@terminator\do\skv@foreach@recoverholders + \do\skv@foreach@callback + \do\skv@foreach@auxcallback + \do\skv@foreach@precallback + \do\skv@foreach@afterprecallback + \do\skv@foreach@postcallback + \do\skv@foreach@onlyinitially + \do\foreachlistremainder\do\skv@foreach@mainloop + \do\skv@foreach@getnext\do\skv@foreach@getrm + \do\skv@foreach@do@a\do\skv@foreach@do@b + \do\skv@foreach@holderlist + \do\skv@foreach@userlist + \do\skv@foreach@inherit + \do\skv@foreach@keepdecimals + \do\skv@foreach@keephighdecimals + \do\skv@foreach@itemcounter + \do\skv@foreach@link\do\skv@foreach@expandbeforefill + \do\skv@listbreakertoks\do\skv@listpausertoks + \do\foreachcurrentitem + \do\foreachnextitem + \do\foreachitemcount + \do\foreachprevitem + % The following commands are disabled on entry into the loop. + % Hence they need to be stacked: + \do\prependtobeginforeach + \do\appendtobeginforeach + \do\atbeginforeach + \do\prependtoendforeach + \do\appendtoendforeach + \do\atendforeach + }\foreachdepth +} +\skvrobustdef*\skv@foreach@popstate{% + \skvrestorestate\skv@foreach@stack\foreachdepth +} +\skvnewdef*\foreachnestdepth{\foreachdepth} +\skvnewlet\skv@foreach@nil\relax +\skvnewdef*\skv@foreach@nnil{\skv@foreach@nil} +\skvrobustdef*\newforeach{\skv@testst\skv@newforeach@beginprescan} +\skvrobustdef*\skv@newforeach@beginprescan{% + \edef\skv@foreach@st{0\ifskv@tempst0\else1\fi}% + \begingroup + \def\skv@tempa{% + \skvexpanded{\endgroup + \noexpand\skv@foreach@endprescan{\skvexpandonce\skv@tempb}% + }% + }% + \def\skv@tempb{}% + \let\bgroup\relax + \skvifnextchar[{% + \endgroup + \skv@foreach@scanarg + }{% + \skvifnextchar i{% + \endgroup + \skv@err{\string\newforeach: no holder macro seen}\@ehd + }{% + \skvifnextchar\skv@orig@bgroup{% + \endgroup + \skv@err{\string\newforeach: no holder macro seen}\@ehd + }{% + \skv@foreach@collectholders + }% + }% + }% +} +\skvrobustdef*\skv@foreach@collectholders#1{% + \edef\skv@tempb{% + \skvexpandonce\skv@tempb\skvtrimspace{#1}% + }% + \skvifnextchar[{% + \skv@tempa + }{% + \skvifnextchar i{% + \skv@tempa[]% + }{% + \skvifnextchar\skv@orig@bgroup{% + \skv@tempa[]% + }{% + \skv@foreach@collectholders + }% + }% + }% +} +\skvrobustdef*\skv@foreach@endprescan#1[#2]{% + \skvifblank{#1}{% + \skv@err{\string\newforeach: no holder macros seen}\@ehd + }{% + \skv@foreach@scanarg[#2]#1% + }% +} +\skvrobustdef*\skv@foreach@scanarg{\skv@testopt\skv@foreach@a{}} +\skvrobustdef*\skv@foreach@a[#1]{% + \skv@foreach@pushstate + \skv@foreach@latehookerr + % \foreachitemcount must be a macro, not a counter, because it is stacked: + \def\foreachitemcount{0}% + % Don't confuse item counters of various depths: + \skvundef\skv@foreach@itemcounter + \skvundef\skv@foreach@processupto + \def\skv@foreach@callback{}% + \def\skv@foreach@auxcallback{}% + \def\skv@foreach@precallback{}% + \def\skv@foreach@afterprecallback{}% + \def\skv@foreach@postcallback{}% + \def\skv@foreach@onlyinitially{}% + % The keys have to be set here, to determine if the list is a macro, etc. + % Since \skv@foreach@precallback are initialized in each nest, the + % keys have to be reset here. + \skv@foreach@setkeys{#1}% + \begingroup + % Collect item holders. Don't confuse explicit \bgroup for left brace: + \skv@cnta\skvz@ + \def\skv@tempb{}% + \let\bgroup\relax + \skvifnextchar i\skv@foreach@c{% + \skvifnextchar\skv@orig@bgroup\skv@foreach@d\skv@foreach@b + }% +} +% #1: one holer macro or subparser. +\skvrobustdef*\skv@foreach@b#1{% + \ifnum\skv@cnta=\skvz@ + \skvifescaped{#1}{}{% + \skv@err{Token '\noexpand#1' is not escaped + \MessageBreak and can't be a holder macro}\@ehd + }% + \else + \ifnum\skv@cnta=\@ne + \skvifescaped{#1}{% + \skv@err{Token '\noexpand#1' cannot be a subparser; + \MessageBreak it seems to be a holder macro. + \MessageBreak I expected the subparser to be the + \MessageBreak second token here.}\@ehd + }{% + \edef\skv@prova{\skvtrimspace{#1}}% + \let\elt\skvexpandonce + \def\skv@elt{\elt\skv@foreach@subparser}% + \if\elt\skv@prova\skv@elt\else + % Don't stack \skv@warnsubparser: + \ifnum\skv@warnsubparser=\skvz@ + \skvgadvanceno\skv@warnsubparser\@ne + \skv@warn{Scanned subparser '\elt\skv@prova' is different from + \MessageBreak the default or user-supplied subparser '\skv@elt'. + \MessageBreak I have used '\elt\skv@prova', but please submit + \MessageBreak '\elt\skv@prova' as the value of the key + 'subparser' + }% + \fi + \let\skv@foreach@subparser\skv@prova + \fi + }% + \fi + \fi + \advance\skv@cnta\@ne + \edef\skv@tempb{\skvexpandonce\skv@tempb\skvtrimspace{#1}}% + \skvifnextchar i\skv@foreach@c{% + \skvifnextchar\skv@orig@bgroup\skv@foreach@d\skv@foreach@b + }% +} +\skvrobustdef*\skv@foreach@c#1#2{% + \skvifstrcmp{#1#2}{in}{% + \skv@foreach@d + }{% + \skv@err{I have seen 'i' but no expected 'in'}\@ehd + }% +} +\skvrobustdef*\skv@foreach@d{% + \ifx\skv@tempb\@empty + \skv@err{No item holder macros before 'in' + \MessageBreak or before left brace}\@ehd + \fi + \skvifnextchar\skv@orig@bgroup{% + \skv@foreach@e + }{% + \if\skv@foreach@listismacro + \expandafter\skv@foreach@e + \else + \if\skv@foreach@st + \expandafter\expandafter\expandafter\skv@foreach@e + \else + \def\reserved@a##1{% + \skvifmacro{##1}{% + \def\skv@ehd{Maybe a star (*) suffix or key 'list is + a macro' is missing.}% + }{% + \let\skv@ehd\@ehd + }% + \skv@err{I expected a left brace for beginning of list, + \MessageBreak since you haven't told me that your + \MessageBreak list is a macro. Instead I found '\detokenize{##1}'. + \MessageBreak If your list is indeed a macro, you can + \MessageBreak either put star (*) after \noexpand\newforeach + \MessageBreak or use the key 'list is a macro'% + }{% + \skv@ehd + }% + }% + \expandafter\expandafter\expandafter\reserved@a + \fi + \fi + }% +} +% #1: <list> or <listcmd> +\skvrobustdef*\skv@foreach@e#1{% + \edef\skv@tempc{\unexpanded{#1}}% + \skvifnextchar\skv@orig@bgroup\skv@foreach@h{% + \skvifnextchar d\skv@foreach@f\skv@foreach@g + }% +} +\skvrobustdef*\skv@foreach@f#1#2{% + \skvifstrcmp{#1#2}{do}{% + \skvifnextchar\skv@orig@bgroup\skv@foreach@h\skv@foreach@g + }{% + \skv@err{I have seen 'd' but no the expected 'do'}\@ehd + }% +} +% We've exhausted all options for grabbing the callback, so now +% look for terminator (default ;). If there is no terminator ahead, +% the use of \skv@prova will trigger 'the use of ... does not match +% its definition' or 'runaway argument ...'. +\skvrobustdef*\skv@foreach@g{% + \def\skv@prova##1{% + \def\skv@prova####1##1{% + % Look out for a case like 'parser=<parser>'. + % Eg, \newforeach[parser=;]. In this case, the value ';' of + % key 'parser' will mistakenly be assumed to be the callback + % terminator. It should be enclosed in braces. + \skvxifin{\detokenize{parser=}\relax}{\detokenize{####1}\relax}{% + \skvxifin{[}{\detokenize{####1}}{% + \skv@err{Put '##1' in braces for key 'parser=##1'. + \MessageBreak Try [parser={##1}]} + {Maybe parser '##1' is the value of a key/option of + \noexpand\newforeach and needs to be enclosed in braces. + The '##1' I have just encountered doesn't seem to be the + one ending a TikZ object. Maybe you need to do [parser={##1}].}% + }{% + % Otherwise, let's try continue: + \skvexpanded{\noexpand\skv@foreach@h{\skvtrimspace{####1}##1}}% + }% + }{% + \skvexpanded{\noexpand\skv@foreach@h{\skvtrimspace{####1}##1}}% + }% + }% + \skv@prova + }% + % In case callback terminator is currently active: + \skv@rescan\skv@foreach@terminator + \expandafter\skv@prova\expandafter{\skv@foreach@terminator}% +} +% #1: callback +\skvrobustdef*\skv@foreach@h#1{% + \skvexpanded{\endgroup + % The subparser may have changed along the way (see \skv@foreach@b): + \skvcmdexit\skv@foreach@subparser + \skv@foreach@i{\skvexpandonce\skv@tempb}{\skvexpandonce\skv@tempc}% + }{#1}% +} +% #1: holder macros +% #2: List or list command +% #3: Callback +\skvrobustdef*\skv@foreach@i#1#2#3{% + \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}% + }% + % Initial code, if any: + \skvcsuse{skv@foreach@atbeginhook@\skvrom\foreachdepth}% + \skvifdef\foreachprevitem{}{\def\foreachprevitem{}}% + \expandafter\skv@foreach@normalize\expandafter + [\skv@foreach@parser]\skv@foreach@userlist + \expandafter\skv@foreach@normalize\expandafter + [\skv@foreach@subparser]\skv@foreach@userlist + \skvbreakloopfalse + \foreachlastitemfalse + \def\skv@foreach@lookahead@a##1{% + \def\skv@foreach@continue{##1.}% + \futurelet\skv@foreach@next\skv@foreach@lookahead@b + }% + \def\skv@foreach@lookahead@b{% + \ifx\skv@foreach@next[% + \expandafter\skv@foreach@lookahead@c + \else + \ifx\skv@foreach@next(% + \expandafter\expandafter\expandafter\skv@foreach@lookahead@d + \else + \expandafter\expandafter\expandafter\skv@foreach@continue + \fi + \fi + }% + \def\skv@foreach@lookahead@c[##1]{\skv@foreach@continue[{##1}]}% + \def\skv@foreach@lookahead@d(##1){\skv@foreach@continue({##1})}% + \def\skv@foreach@mainloop##1{% + \def\skv@foreach@getnext####1##1####2\skv@foreach@stop{% + \edef\foreachnextitem{\skvexpandonce{\@gobble####1}}% + \ifx\foreachnextitem\skv@foreach@nnil + \foreachlastitemtrue + \def\foreachnextitem{}% + \fi + }% + \def\skv@foreach@do@a####1##1####2\skv@foreach@stop{% + \edef\foreachcurrentitem{\skvexpandonce{\@gobble####1}}% + \skvifx\foreachcurrentitem\skv@foreach@nnil{% + \skvbreakloopfalse + \foreachlastitemfalse + }{% + \skvifx\foreachcurrentitem\skv@listbreakertoks{% + \skv@foreach@getrm{####2}% + }{% + \skvifx\foreachcurrentitem\skv@listpausertoks{% + \message{^^J! List pause: + ^^JType x or X to quit, or <RETURN> to proceed^^J}% + \begingroup + \endlinechar\m@ne\global\read-1 to\@gtempa + \endgroup + \skvexpandarg\lowercase{\def\noexpand\@gtempa{\@gtempa}}% + \skvxifstrcmp\@gtempa{x}{% + \skv@foreach@getrm{####2}% + }{% + \skv@foreach@do@b{####2}% + }% + }{% + \skv@foreach@do@b{####2}% + }% + }% + }% + }% + \def\skv@foreach@do@b####1{% + \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 + \skv@foreach@lookahead@a\skv@foreach@getnext####1\skv@foreach@stop + % In case the user decides to continue after \listpauser: + \skvifx\foreachcurrentitem\skv@listpausertoks{}{% + \expandafter\skv@foreach@callback\expandafter{\foreachcurrentitem}% + }% + \let\foreachprevitem\foreachcurrentitem + \ifx\skv@foreach@processupto\@undefined\else + \ifx\skv@foreach@processupto\@nnil\else + \ifnum\foreachitemcount<\skv@foreach@processupto\relax\else + \skvbreakloop + \fi + \fi + \fi + \skvifdefbool{skvbreakloop}{% + \skv@foreach@getrm{####1}% + }{% + \skv@foreach@lookahead@a\skv@foreach@do@a####1\skv@foreach@stop + }% + }% + \def\skv@foreach@getrm####1{% + \skvbreakloopfalse + \foreachlastitemfalse + \def\skv@prova########1\skv@foreach@nil##1{% + \edef\foreachlistremainder{\unexpanded{########1}}% + \skv@removetrailingparser{##1}\foreachlistremainder + }% + \skv@prova####1% + }% + \skvifx\skv@foreach@userlist\@empty{% + \if\skv@foreach@processempty\skv@foreach@callback{}\fi + }{% + \expandafter\skv@foreach@filllist\expandafter + {\skv@foreach@parser}\skv@foreach@userlist + \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do@a + \skv@foreach@userlist##1\skv@foreach@nil##1\skv@foreach@stop + }% + }% + \skv@foreach@makeprecode{#1}% + \if\skv@foreach@recoverholders\else + \expandafter\skvsavestate\expandafter\skv@foreach@holderstate + \expandafter{\skv@foreach@holderlist}\skv@foreach@sisterdepth + \fi + \skv@foreach@makeauxcallback{#3}% + \skvexpandbracenext\skv@foreach@mainloop\skv@foreach@parser + \skvcsuse{skv@foreach@atendhook@\skvrom\foreachdepth}% + \if\skv@foreach@recoverholders\else + \skvrestorestate\skv@foreach@holderstate\skv@foreach@sisterdepth + \fi + \skv@foreach@popstate +} + +% \skv@foreach@makeprecode{<holder.list>} +% +% 'Holder macro' here means, eg, \x and \y in +% +% \newforeach \x/\y in {1/a,2/b,3/c}{<code>} +% +\skvrobustdef*\skv@foreach@makeprecode#1{% + \begingroup + \skv@cnta\skvz@ + \def\skv@foreach@holderlist{}% + \def\skv@foreach@paramlist{}% + \def\skv@prevholder{}% + \def\skv@tempa{#1}% + \expandafter\skv@foreach@normalize\expandafter + [\skv@foreach@subparser]\skv@tempa + \skvtfor*\skv@prova:=\skv@tempa\do{% + \ifx\skv@prova\skv@foreach@subparser + \ifnum\skv@cnta=\skvz@ + \skv@err{Subparser '\skvoxdetok\skv@foreach@subparser' can't come + first in the list\MessageBreak of holder macros}\@ehd + \else + % Eg, if subparser is slash (/), \skv@foreach@paramlist will have + % the syntax: ##1/##2/...: + \edef\skv@foreach@paramlist{% + \skvexpandonce\skv@foreach@paramlist\skvexpandonce\skv@prova + }% + \fi + \else + \advance\skv@cnta\@ne + \edef\skv@elt{\expandafter\skvremovescape\skv@prova}% + \edef\skv@foreach@precallback{% + \skvexpandonce\skv@foreach@precallback + % Each given item-holder macro is now defined in terms of + % parameters of skv@foreach@auxcallback: + \edef\skvexpandonce\skv@prova{% + \noexpand\unexpanded{####\number\skv@cnta}% + }% + % If the current holder has no value, use the value of last holder: + \ifnum\skv@cnta>\@ne + \if\skv@foreach@inherit + \noexpand\ifx\skvexpandonce\skv@prova\noexpand\@empty + \let\skvexpandonce\skv@prova\skvexpandonce\skv@prevholder + \noexpand\fi + \fi + \fi + }% + \edef\skv@foreach@holderlist{% + \skvexpandonce\skv@foreach@holderlist + % The \do is for the individual entries of the stack of + % \skv@foreach@holderlist. It is required for stacking the + % holder list: + \noexpand\do\skvexpandonce\skv@prova + }% + \edef\skv@foreach@paramlist{% + \skvexpandonce\skv@foreach@paramlist########\number\skv@cnta + }% + \let\skv@prevholder\skv@prova + \fi + }% + % Add one extra parameter character to absorb extra subparsers that are + % added for incomplete list items: + \edef\skv@foreach@paramlist{% + \skvexpandonce\skv@foreach@paramlist + \skvexpandonce\skv@foreach@subparser + ########\number\numexpr\skv@cnta+1\relax + }% + \skvexpanded{\endgroup + \skvcmdexit\skv@foreach@holderlist + \skvcmdexit\skv@foreach@paramlist + \skvcmdexit\skv@foreach@precallback + }% +} + +% #1: callback +\skvrobustdef*\skv@foreach@makeauxcallback#1{% + \begingroup + \def\skv@generatesubparser##1{% + \ifnum##1<10\skvexpandonce\skv@foreach@subparser + \expandafter\skv@generatesubparser + \expandafter{\number\numexpr##1+1\expandafter}% + \fi + }% + % Add extra subparsers in case some items aren't subparser-complete: + \edef\skv@tempa{\skv@generatesubparser{1}}% + \let\foreacheov\relax + \skvexpanded{\endgroup + % Define auxiliary callback: + \def\noexpand\skv@foreach@auxcallback\skv@foreach@paramlist\foreacheov{% + % Holder macro assignments: + \skvexpandonce\skv@foreach@precallback + % User tests/tasks, eg, if requested from 'evaluate' key: + \skvexpandonce\skv@foreach@afterprecallback + \noexpand\ifnum\noexpand\foreachitemcount=\@ne + \noexpand\skv@foreach@onlyinitially + \noexpand\fi + \unexpanded{#1}% + % User tests/tasks, eg, if requested from the keys 'remember', + % 'exit when', etc: + \skvexpandonce\skv@foreach@postcallback + }% + % Define the real callback: + \def\noexpand\skv@foreach@callback####1{% + \noexpand\skv@foreach@auxcallback####1\skv@tempa\foreacheov + }% + }% +} +\skvnewdef*\skv@ucalpha#1{% + \ifcase#1\or A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or + K\or L\or M\or N\or O\or P\or Q\or R\or S\or T\or U\or V\or W\or + X\or Y\or Z\else?\fi +} +\skvnewdef*\skv@lcalpha#1{% + \ifcase#1\or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or + k\or l\or m\or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or + x\or y\or z\else?\fi +} +\skvnewdef*\skv@alphamap{% + {A}{a}{1}{B}{b}{2}{C}{c}{3}{D}{d}{4}{E}{e}{5}{F}{f}{6}{G}{g}{7}{H}{h}{8}% + {I}{i}{9}{J}{j}{10}{K}{k}{11}{L}{l}{12}{M}{m}{13}{N}{n}{14}{O}{o}{15}% + {P}{p}{16}{Q}{q}{17}{R}{r}{18}{S}{s}{19}{T}{t}{20}{U}{u}{21}{V}{v}{22}% + {W}{w}{23}{X}{x}{24}{Y}{y}{25}{Z}{z}{26}% +} +% \skv@foreach@addtolist<parser><add.new><listcmd> +\skvrobustdef*\skv@foreach@addtolist#1#2#3{% + \edef#3{\skvexpandonce#3\ifx#3\@empty\else\unexpanded{#1}\fi#2}% +} +\skvrobustdef*\skv@reverselumap#1{% + \def\skv@prova##1##2##3##4\skv@nil{% + \ifx\@nnil##1% + \expandafter\@gobble + \else + \expandafter\@iden + \fi + {\skv@prova##4\skv@nil{##1}{##2}{##3}}% + }% + \edef#1{\expandafter\skv@prova\skv@alphamap\@nnil{}{}\skv@nil} +} + +\skvnewdef*\skv@foreach@ifloweralpha#1{% + \skvifblank{#1}{% + \@secondoftwo + }{% + \skvifntype{#1}{% + \skvifnum`#1>96{% + \skvifnum`#1<123{% + \@firstoftwo + }{% + \@secondoftwo + }% + }{% + \@secondoftwo + }% + }{% + \@secondoftwo + }% + }% +} +\skvnewdef*\skv@foreach@ifupperalpha#1{% + \skvifblank{#1}{% + \@secondoftwo + }{% + \skvifntype{#1}{% + \skvifnum`#1>64{% + \skvifnum`#1<91{% + \@firstoftwo + }{% + \@secondoftwo + }% + }{% + \@secondoftwo + }% + }{% + \@secondoftwo + }% + }% +} + +% Parse list for 1,2,...,n,1,...,m. Return value in #1: +% +% \skv@foreach@filllist{<parser>}<listcmd> +\skvrobustdef*\skv@foreach@filllist#1#2{% + \def\skv@inalphabetic{01}% + \def\skv@isupperalpha{01}% + % If the list is alphabetic, original unit is nil: + \def\skv@foreach@origunit{}% + \def\skv@foreach@filledlist{}% + \edef\skv@foreach@parser{\skvtrimspace{#1}}% + \ifx\skv@foreach@parser\@undefined + \def\skv@foreach@parser{,}% + \fi + \def\skv@foreach@iflinkgiven{% + \skvifdef\skv@foreach@link{% + \skvnotifx\skv@foreach@link\@nnil + }{% + \skv@err{List auto-completion: 'link' is undefined}\@ehd + }% + }% + \skvexpanded{% + \noexpand\skv@foreach@filllist@a + {\skvexpandonce\skv@foreach@parser}{\skvexpandonce{#2}}% + }% + \let#2\skv@foreach@filledlist +} +\skvnewlet\skvautofilllist\skv@foreach@filllist +% \skv@foreach@filllist@a{<parser>}{<list>} +\skvrobustdef*\skv@foreach@filllist@a#1#2{% + \edef\skv@tempa{\unexpanded{#2}}% + \skv@foreach@normalize[#1]\skv@tempa + \def\skv@prova##1{% + \skvxifin{...}{\detokenize{##1}}{% + \if\skv@foreach@expandbeforefill + \edef\skv@tempa{##1}% + \skv@foreach@normalize[#1]\skv@tempa + \else + \edef\skv@tempa{\unexpanded{##1}}% + \fi + \skvexpandargonce{\skv@foreach@filllist@b{#1}}{\skv@tempa}% + \skv@foreach@normalize[#1]\skv@foreach@filledlist + }{% + \edef\skv@foreach@filledlist{% + \skvaddlist{#1}\skv@foreach@filledlist + \skvtrimspace{##1}% + }% + }% + }% + \expandafter\skv@prova\expandafter{\skv@tempa}% +} +% \skv@foreach@filllist@b{<parser>}{<list>} +\skvrobustdef*\skv@foreach@filllist@b#1#2{% + \skvxiffound{\relax...}\in{\relax\detokenize{#2}}\then + \skv@err{I can't find lower limit before '...'}\@ehd + \else + \skvxiffound{\relax\detokenize{#1}...}\in{\relax\detokenize{#2}}\then + \skv@err{I can't find lower limit before '...'}\@ehd + \fi + \fi + % \newforeach format is '<parser>...<parser>': + \skvxifin{\detokenize{#1...#1}}{\detokenize{#2}}{% + \skv@foreach@splitonguide{#1}{#2}% + \def\skv@prova##1#1##2#1...#1##3#1##4#1##5\skv@nil{% + \skvifblank{##3}{% + \skv@err{I can't find upper limit number or dimension, + \MessageBreak i.e., after symbool '...'}\@ehd + }{% + % \skv@foreach@filllist@a may be reentered. Hence accumulate + % filled list: + \skviflacus{##1}\then\else + \edef\skv@foreach@filledlist{% + \skvaddlist{#1}\skv@foreach@filledlist\unexpanded{##1}% + }% + \fi + % Complete the list: + \skv@foreach@filllist@c{#1}{##1}{##2}{##3}% + % In case the list is folded on ellipsis (...): + \skvifblank{##4}{}{\skv@foreach@filllist@a{#1}{##4#1##5}}% + }% + }% + \expandafter\skv@prova\skv@tempa#1#1\skv@nil + }{% + % Not \newforeach format: try PGF's \foreach format: + \skv@foreach@trypgfformat{#1}{#2}% + }% +} + +% \skv@foreach@zerostepwarn{<lower>}{<upper>}{<pt.or.nil>} +\skvrobustdef*\skv@foreach@zerostepwarn#1#2#3{% + \skv@warn{The tokens '\detokenize{#1}', '\detokenize{#2}' + give nil step; '1#3' used. \MessageBreak + Maybe you used the font-dependent units \MessageBreak + 'ex' or 'em' before \skv@begindoc@string}% +} + +% skv@foreach@filllist@c{<parser>}{<lower1>}{<lower2>}{<upperbound>} +% +% 1. No <guide> here. +% +\skvrobustdef*\skv@foreach@filllist@c#1#2#3#4{% + \skv@foreach@iflinkgiven{% + % <link> has been given by the user: + \skv@foreach@splitandgrow{#1}{#2}{#3}{#4}% + }{% + % No <link> has been given. The list has '...' but presumably no link. + % Note: If there're more than 1 alpha/Alpha character, both + % \skv@foreach@ifloweralpha and \skv@foreach@ifupperalpha will + % return false, since double aphabetic characters can't be grown. + % \skv@foreach@filllist@d{<parser>}{<guide>}{<lower1>}{<lower2>}{<upper>} + \skv@foreach@filllist@d{#1}{}{#2}{#3}{#4}% + }% +} + +% skv@foreach@fsplitandgrow{<parser>}{<lower1>}{<lower2>}{<upperbound>} +% +% {0\pi,0.5\pi,...,3\pi} : link = \pi ; grow left +% {1--,4--,...,10--} : link = -- ; grow left +% {2pt,4pt,...,10pt} : link = pt ; grow left (or no additional info.) +% {A_1,C_1,...,Q_1} : link = _ ; grow left +% {2^a,2^c,...,2^q} : link = ^ ; grow right +% +% 1. Automatically split and grow. +% 2. We already know that the key 'link' will reject empty values. +% +\skvrobustdef*\skv@foreach@splitandgrow#1#2#3#4{% + \ifx\skv@foreach@growleft\skv@foreach@growright + \skv@err{I can't grow the list in both directions. + \MessageBreak Maybe you haven't indicated the + \MessageBreak direction of growth (left or right), + \MessageBreak or both directions are 'true'.} + {Try one of the keys 'grow=left or right', + \MessageBreak 'grow left=true or false', + 'grow right=true or false'}\@ehd + \fi + \begingroup + \def\skv@prova##1{% + \skv@foreach@swatrue + \skviflacus#2\then\else + \skvifin{##1}{#2}{}\skv@foreach@swafalse + \fi + \skvifin{##1}{#3}{}\skv@foreach@swafalse + \skvifin{##1}{#4}{}\skv@foreach@swafalse + \ifskv@foreach@swa\else + \edef\skv@provb{\ifx\@nnil#2\@nnil\else\unexpanded{#2}, \fi}% + \skv@err{No link '##1' in one of + '\detokenize\expandafter{\skv@provb#3, #4}'}\@ehd + \fi + \def\skv@prova####1##1####2\skv@nil{% + \if\skv@foreach@growright + \edef\skv@prova{\skvtrimspace{####1##1}}% + \else + \edef\skv@prova{\skvtrimspace{##1####2}}% + \fi + \def\do########1{{\skvtrimspace{########1}}}% + % \skv@foreach@trypgfformat@a<parser><guide><lower1><lower2><upper> + \skvexpanded{\endgroup + \noexpand\skv@foreach@trypgfformat@a + {\unexpanded{#1}}{\skvexpandonce\skv@prova}\do{#2}\do{#3}\do{#4}% + }% + }% + \skv@prova#3\skv@nil + }% + \expandafter\skv@prova\expandafter{\skv@foreach@link}% +} +% +% \skv@foreach@splitonguide{<parser>}{<list>} +% +% Get the two elements before '...' or '<guide>,...'. In the case of skeyval +% format, get the two elements before '...'. The PGF format uses <guide>, +% shown in the following examples: +% +% PGF formats: +% {a^1,a^3,a^...,a^9} : <guide> = a^ +% {A_1,B_1,..._1,E_1} : <guide> = _1 +% {1--,4--,...--,16--} : <guide> = -- +% {1pt,4pt,...pt,10pt} : <guide> = pt +% {A_2pt,A_4pt,A_...pt,A_10pt} : <guide> = A_, pt +% +% skeyval formats: +% {a^1,a^3,a^...,a^9} : no additional info. required +% {A_1,B_1,..._1,E_1} : no additional info. required +% {1--,4--,...--,16--} : no additional info. required +% {1pt,4pt,...pt,10pt} : no additional info. required +% {A_2pt,A_4pt,A_...,A_10pt} : no additional info. required +% +% {a^1,a^3,...,a^9} : link = ^, grow = right +% {A_1,B_1,...,E_1} : link = _, grow = left +% {1--,4--,...,16--} : link = --, grow = left +% {1pt,4pt,...,10pt} : link = pt, grow = left (or addit. info.) +% {A_2pt,A_4pt,...,A_10pt} : link = _, grow = right +% +% The items prior to the last 2 items before '<guide>...' or before '...' +% are called 'before-the-last-2' (BL2). Collect in \skv@tempa BL2 items, +% together with the rest of the list. Save in \skv@foreach@filledlist +% the BL2 items. +% +% Return \skv@foreach@filledlist and \skv@tempa. +% +\skvrobustdef*\skv@foreach@splitonguide#1#2{% + % First count all the elements before '<guide>,...'. We're already + % sure that #2 contains '<guide>,...' or '...': + \begingroup + \skv@cnta\skvz@ + \def\do##1#1{% + \skvifin{...}{##1}{% + \def\do####1\skv@nil{}% + }{% + \advance\skv@cnta\@ne + }% + \do + }% + \do#2#1\skv@nil + \ifnum\skv@cnta>\tw@ + \skvsetno\skv@foreach@nra\m@ne + \def\do##1#1{% + \skvadvanceno\skv@foreach@nra\@ne + \ifnum\skv@foreach@nra=\numexpr\skv@cnta-\tw@\relax + \def\do####1\skv@nil{\def\skv@tempa{##1#1####1}}% + \else + \edef\skv@foreach@filledlist{% + \skvaddlist{#1}\skv@foreach@filledlist\unexpanded{##1}% + }% + \fi + \do + }% + \do#2#1\skv@nil + \else + \ifnum\skv@cnta=\@ne + \def\skv@tempa{#1#2}% + \else + \ifnum\skv@cnta=\tw@ + \def\skv@tempa{#2}% + \else + \ifnum\skv@cnta=\skvz@ + \skv@err{List <<\detokenize{#2}>>\MessageBreak + contains symbol '...' but not a lowerbound}\@ehd + \fi + \fi + \fi + \fi + \skvexpanded{\endgroup + \skvcmdexit\skv@foreach@filledlist\skvcmdexit\skv@tempa + }% +} + +% \skv@foreach@trypgfformat{<parser>}{<list>} +% +% When we say, 'try PGF format', we don't actually mean the PGF format with +% left and right guides, but the syntax '<guide>...' (ie, having only the +% left-hand-side or only the right-hand-side guide). For example, +% {A_2pt,A_4pt,A_...,A_10pt}. \skv@foreach@trypgfformat will auto-complete +% this list without knowledge of the values of the keys 'link' and 'grow'. +% +% skeyval formats: +% +% {1pt,4pt,...pt,10pt} : no additional info. required +% {A_2pt,A_4pt,A_...,A_10pt} : no additional info. required +% {1pt,4pt,...,10pt} : link = pt, grow=right (or no addit. info.) +% {A_2pt,A_4pt,...,A_10pt} : link =_, grow=right +% +% The general PGF format (with left and right guides) is illegal here, +% because the skeyval-for package uses the location of the guide (left or +% right of ...) to determine the direction of growth. +% +% {A_2pt,A_4pt,A_...pt,A_10pt} +% +\skvrobustdef*\skv@foreach@trypgfformat#1#2{% + \skv@foreach@splitonguide{#1}{#2}% + \def\skv@prova##1#1##2#1##3...##4#1##5#1##6#1##7\skv@nil{% + \skvifblank{##5}{% + \skv@err{I can't find upper limit number or dimension, + \MessageBreak i.e., after symbool '...'}\@ehd + }{% + % \skv@foreach@filllist@a may be reentered. Hence + \if\relax\detokenize{##1}\relax\else + \edef\skv@foreach@filledlist{% + \skvaddlist{#1}\skv@foreach@filledlist + \skvtrimspace{##1}% + }% + \fi + \def\do####1{{\skvtrimspace{####1}}}% + \skvifblank{##3}{% + \skvifblank{##4}{% + \skv@err{No direction of growth before and/or after + \MessageBreak symbol '...'}\@ehd + }{% + \def\skv@foreach@growleft{00}% + \def\skv@foreach@growright{01}% + \skvexpanded{% + \skv@foreach@trypgfformat@a + {\unexpanded{#1}}\do{##4}\do{##1}\do{##2}\do{##5}% + }% + }% + }{% + \skvifblank{##4}{% + \def\skv@foreach@growright{00}% + \def\skv@foreach@growleft{01}% + \skvexpanded{% + \skv@foreach@trypgfformat@a + {\unexpanded{#1}}\do{##3}\do{##1}\do{##2}\do{##5}% + }% + }{% + \skv@err{Having both '\detokenize{##3 and ##4}' in an + \MessageBreak ellipsis list is illegal in + \MessageBreak\noexpand\newforeach and \noexpand\newforeach. + \MessageBreak I know that PGF's \noexpand\foreach needs it, + \MessageBreak but I don't need it. I can + \MessageBreak auto-fill your list without it.}\@ehd + }% + }% + % In case the list is folded on ellipsis (...): + \skvifblank{##6}{}{\skv@foreach@filllist@a{#1}{##6#1##7}}% + }% + }% + \expandafter\skv@prova\skv@tempa#1#1#1\skv@nil +} +% +% \skv@foreach@trypgfformat@a{<parser>}{<guide>}{<lower1>}{<lower2>}{<upper>} +% +% 1. Use the <guide> to get the contant and variable parts of the +% elements. +% 2. Use the variable parts to determine if the list is Alpah, alpha or +% number type. In this format, the unit in dimension type of list may +% appear in <guide>. +% 3. Use the variable parts to work out the <step>. +% 4. Call the relevant macro to fill the list. +% 5. <lower1> has already been saved in \skv@foreach@filledlist. +% +\skvrobustdef*\skv@foreach@trypgfformat@a#1#2#3#4#5{% + \skv@foreach@swafalse + \skviflacus#3\then\else + \skvxifin{#2}{#3}{}\skv@foreach@swatrue + \fi + \skvxifin{#2}{#4}{}\skv@foreach@swatrue + \skvxifin{#2}{#5}{}\skv@foreach@swatrue + \ifskv@foreach@swa + \skv@err{Guide token '\detokenize{#2}' not found in some + \MessageBreak of the elements: I can't complete + \MessageBreak the current list. This may be + \MessageBreak due to wrong direction of growth}\@ehd + \fi + % Get from the left or right of 'link' (#2) the components that should be + % grown, without the link: + \def\skv@prova##1#2##2\skv@nil##3{% + \edef##3{\if\skv@foreach@growleft##1\else##2\fi}% + }% + % <lower1> is empty when there is only one element before ellipsis: + \skviflacus#3\then + \def\skv@tempa{}% + \else + \skv@prova#3\skv@nil\skv@tempa + \fi + \skv@prova#4\skv@nil\skv@tempb + \skv@prova#5\skv@nil\skv@tempc + \let\do\skvexpandonce + \skvexpandsecond + {\skv@foreach@filllist@d{#1}{#2}}% + {{\do\skv@tempa}{\do\skv@tempb}{\do\skv@tempc}}% +} + +% \skv@foreach@filllist@d{<parser>}{<guide>}{<lower1>}{<lower2>}{<upper>} +% +% 1. Use the variable parts to determine if the list is Alpah, alpha or +% number type. In this format, the unit in dimension type of list may +% appear in <guide>. +% 2. Use the variable parts to work out the <step>. +% 3. Call the relevant macro to fill the list. +% 4. <lower1> has already been saved in \skv@foreach@filledlist. +% +\skvrobustdef*\skv@foreach@filllist@d#1#2#3#4#5{% + \begingroup + \def\skv@templist{}% + \edef\skv@lowerlower{\ifx\@nnil#3\@nnil\else\unexpanded{#3}, \fi}% + \skv@foreach@ifloweralpha{#4}{% + \skv@foreach@swatrue + \ifx\@nnil#3\@nnil\else + \skv@foreach@ifloweralpha{#3}{}\skv@foreach@swafalse + \fi + \skv@foreach@ifloweralpha{#5}{}\skv@foreach@swafalse + \ifskv@foreach@swa + \ifx\@nnil#3\@nnil + \def\skv@foreach@step{1}% + \else + \edef\skv@foreach@step{\the\numexpr\lccode`#4-\lccode`#3}% + \ifnum\skv@foreach@step=\skvz@ + \def\skv@foreach@step{1}% + \skv@foreach@zerostepwarn{#3}{#4}{}% + \fi + \fi + \def\skv@isupperalpha{01}% + % \skv@foreach@origunit remains nil on this branch: + \skv@foreach@fillalphabetic{#1}{#4}{#5}\skv@templist + % Also update the items already entered in \skv@foreach@filledlist. + \skv@foreach@restoreguideandunit{#1}{#2}\skv@templist + \else + \skv@err{The tokens '\detokenize\expandafter{\skv@lowerlower#4, #5}' + \MessageBreak aren't of the same type}\@ehd + \fi + }{% + \skv@foreach@ifupperalpha{#4}{% + \skv@foreach@swatrue + \ifx\@nnil#3\@nnil\else + \skv@foreach@ifupperalpha{#3}{}\skv@foreach@swafalse + \fi + \skv@foreach@ifupperalpha{#5}{}\skv@foreach@swafalse + \ifskv@foreach@swa + \ifx\@nnil#3\@nnil + \def\skv@foreach@step{1}% + \else + \edef\skv@foreach@step{\the\numexpr\uccode`#4-\uccode`#3}% + \ifnum\skv@foreach@step=\skvz@ + \def\skv@foreach@step{1}% + \skv@foreach@zerostepwarn{#3}{#4}{}% + \fi + \fi + \def\skv@isupperalpha{00}% + % \skv@foreach@origunit remains nil on this branch: + \skv@foreach@fillalphabetic{#1}{#4}{#5}\skv@templist + \skv@foreach@restoreguideandunit{#1}{#2}\skv@templist + \else + \skv@err{The tokens '\detokenize\expandafter{\skv@lowerlower#4, #5}' + \MessageBreak aren't of the same type}\@ehd + \fi + }{% + \skv@foreach@swatrue + \ifx\@nnil#3\@nnil\else + \skvifdimensionable{#3}{}\skv@foreach@swafalse + \fi + \skvifdimensionable{#4}{}\skv@foreach@swafalse + \let\skv@foreach@origunit\skv@dimunit + \skvifdimensionable{#5}{}\skv@foreach@swafalse + \ifx\skv@foreach@origunit\skv@dimunit\else + \skv@err{The units on \detokenize{'#4', '#5'} are different}\@ehd + \fi + \ifskv@foreach@swa + \ifx\@nnil#3\@nnil + \def\skv@foreach@step{1pt}% + \else + \edef\skv@foreach@step{\the\dimexpr#4-#3}% + \ifdim\skv@foreach@step=\skvz@ + \def\skv@foreach@step{1pt}% + \skv@foreach@zerostepwarn{#3}{#4}{pt}% + \fi + \fi + \skvexpandsecond{% + \skv@foreach@fillnumordim{#1}% + }{% + {#4}{#5}% + }\skv@templist + \skv@foreach@strippoint{#1}\skv@templist + % Attach the constant part to the elements of the completed list. + % <lower1> was saved earlier in \skv@foreach@trypgfformat, and + % <lower2> and <upper> have been saved while filling the list. + % Always strip point and restore original unit here. + \skv@foreach@restoreguideandunit{#1}{#2}\skv@templist + \else + \skv@foreach@swatrue + \ifx\@nnil#3\@nnil\else + \skvifdimensionable{#3pt}{}\skv@foreach@swafalse + \fi + \skvifdimensionable{#4pt}{}\skv@foreach@swafalse + \skvifdimensionable{#5pt}{}\skv@foreach@swafalse + \ifskv@foreach@swa + \ifx\@nnil#3\@nnil + \def\skv@foreach@step{1pt}% + \else + \edef\skv@foreach@step{\the\dimexpr#4pt-#3pt}% + \ifdim\skv@foreach@step=\skvz@ + \def\skv@foreach@step{1pt}% + \skv@foreach@zerostepwarn{#3}{#4}{pt}% + \fi + \fi + % \skv@foreach@origunit remains nil on this branch: + \skvexpandsecond{% + \skv@foreach@fillnumordim{#1}% + }{% + {#4pt}{#5pt}% + }\skv@templist + \skv@foreach@strippoint{#1}\skv@templist + \skv@foreach@restoreguideandunit{#1}{#2}\skv@templist + \else + \skv@err{Sorry, the tokens + '\detokenize\expandafter{\skv@lowerlower#4, #5}' + \MessageBreak are unparsable. I have given up on them. + \MessageBreak Did you miss something syntactic? + \MessageBreak See manual for acceptable syntaxes}\@ehd + \fi + \fi + }% + }% + \skvaftergroupdef\skv@foreach@filledlist\endgroup +} + +% Restore guide and, in the case of numerical sequences, 'original unit'. +% +% \skv@foreach@restoreguideandunit{<parser>}{<guide>}{<listcmd>} +\skvrobustdef*\skv@foreach@restoreguideandunit#1#2#3{% + \def\do##1#1{% + \ifx\do##1\else + \edef\skv@foreach@filledlist{% + \skvaddlist{#1}\skv@foreach@filledlist + \if\skv@foreach@growleft + ##1\skv@foreach@origunit\unexpanded{#2}% + \else + \unexpanded{#2}##1\skv@foreach@origunit + \fi + }% + \expandafter\do + \fi + }% + \expandafter\do#3#1\do#1% +} + + +\skvrobustdef*\skv@foreach@getcomparator{% + \begingroup + % 'unit' isn't required in alphabetic sequences: + \if\skv@inalphabetic\else + \let\skvreversedo\@iden + \edef\skv@provb{\skvexpbracenext\skvreverse{\skv@foreach@step}}% + \def\skv@prova##1##2##3\skv@nil{% + \skvxifin{,\detokenize{##2##1},}{,\skvoxdetok\skv@validunit,}{% + \def\skv@foreach@unit{}% + }{% + \def\skv@foreach@unit{pt}% + }% + }% + \expandafter\skv@prova\skv@provb\skv@nil + \fi + \def\skv@prova##1##2\skv@nil{% + \edef\skv@foreach@stepisneg{0\if-##10\else1\fi}% + }% + \expandafter\skv@prova\skv@foreach@step\skv@nil + \edef\skv@comparator{\if\skv@foreach@stepisneg>\else<\fi}% + \let\do\skvcmdexit + \skvexpanded{\endgroup + \do\skv@foreach@stepisneg\do\skv@comparator + \if\skv@inalphabetic\else\do\skv@foreach@unit\fi + }% +} +% \skv@foreach@fillnumordim<parser><lower><upper><listcmd> +\skvrobustdef*\skv@foreach@fillnumordim#1#2#3#4{% + \begingroup + \skv@foreach@getcomparator + \if\skv@foreach@stepisneg + \ifdim#3\skv@foreach@unit>#2\skv@foreach@unit\relax + \skv@err{Step '\skv@foreach@step' is negative but upperbound + \MessageBreak '\detokenize{#3}' is greater than lowerbound + '\detokenize{#2}'}\@ehd + \fi + \else + \ifdim#3\skv@foreach@unit<#2\skv@foreach@unit\relax + \skv@err{Step '\skv@foreach@step' is nonnegative but upperbound + \MessageBreak '\detokenize{#3}' is less than lowerbound + '\detokenize{#2}'}\@ehd + \fi + \fi + % The bounds may have decimal places. So the calculation has to be + % done with \dimexpr: + \skv@foreach@addtolist{#1}{\the\dimexpr#2\skv@foreach@unit}#4% + % Upper number: + \edef\skv@tempa{\the\dimexpr#3\skv@foreach@unit}% + % Lower number: + \edef\skv@tempb{\the\dimexpr#2\skv@foreach@unit}% + \ifdim\skv@tempa=\skv@tempb\relax\else + \def\do{% + \edef\skv@tempb{% + \the\dimexpr\skv@tempb+\skv@foreach@step\skv@foreach@unit\relax + }% + \ifdim\skv@tempb\skv@comparator\skv@tempa\relax + \skv@foreach@addtolist{#1}{\skvexpandonce\skv@tempb}#4% + \expandafter\do + \fi + }% + \do + % The last item has to in 'pt', so that 'pt' can be stripped: + \skv@foreach@addtolist{#1}{\the\dimexpr#3\skv@foreach@unit}#4% + \fi + \skvaftergroupdef#4\endgroup +} + +% Fill Alpha or alpha: +% \skv@foreach@fillalphabetic<parser><lower><upper><listcmd> +\skvrobustdef*\skv@foreach@fillalphabetic#1#2#3#4{% + \begingroup + \def\skv@inalphabetic{00}% + \skv@foreach@getcomparator + \edef\skv@type{% + \if\skv@isupperalpha Upper\else Lower\fi case alphabetic% + }% + \edef\reserved@a{\if-\skv@foreach@step\else\skv@foreach@step\fi}% + \skvoifinteger\reserved@a{}{% + \skv@err{List is '\skv@type' type but\MessageBreak + step '\skv@foreach@step' isn't an integer}\@ehd + }% + \skv@foreach@addtolist{#1}{#2}#4% + \skvifstrcmp{#2}{#3}{}{% + \edef\skv@lowerlimit{#2}% + \edef\skv@upperlimit{#3}% + \skvexpandnext{\chardef\skv@lowerlimit`}\skv@lowerlimit\relax + \skvexpandnext{\chardef\skv@upperlimit`}\skv@upperlimit\relax + \edef\skv@lowerlimit{% + \the\numexpr\skv@lowerlimit-\if\skv@isupperalpha 64\else 96\fi + }% + \edef\skv@upperlimit{% + \the\numexpr\skv@upperlimit-\if\skv@isupperalpha 64\else 96\fi + }% + \edef\skv@charcase{\the\numexpr\skv@lowerlimit+\skv@foreach@step}% + \skvrecurse + \if\skv@isupperalpha + \edef\skv@tempa{\skv@ucalpha\skv@charcase}% + \else + \edef\skv@tempa{\skv@lcalpha\skv@charcase}% + \fi + \skv@foreach@addtolist{#1}\skv@tempa#4% + \edef\skv@charcase{\the\numexpr\skv@charcase+\skv@foreach@step}% + \while + \ifnum\skv@charcase\skv@comparator\skv@upperlimit\relax + \fi + \skv@foreach@addtolist{#1}{#3}#4% + }% + \skvaftergroupdef#4\endgroup +} + +\skv@for@restorecatcodes +\endinput |