diff options
Diffstat (limited to 'Master/texmf-dist/tex/latex')
9 files changed, 4199 insertions, 2602 deletions
diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-bc.sty b/Master/texmf-dist/tex/latex/skeyval/skeyval-bc.sty index de53f5161e0..0e468a36db6 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval-bc.sty +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-bc.sty @@ -1,7 +1,8 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% % This is file 'skeyval-bc.sty', version 0.73 of skeyval package, % -% January 2011. % +% 2011/01/01. % % NOTE % +% % % This file is provided only for backward compatibility (bc) of the % % skeyval package. Beginning from version 1.0, September 2012, the % % package has changed radically. Users of pre-version 1.0 of the package % @@ -85,7 +86,7 @@ \SKV@setcode{126}{13}% ~ \def\SKV@rcsid$#1: #2 #3 #4 #5${#4 v#3} \ProvidesPackage{skeyval}[% - \SKV@rcsid $Id: skeyval.sty,v 0.72 2010/05/21 09:00:00 Ahmed Musa $ + \SKV@rcsid $Id: skeyval.sty,v 0.73 2011/01/01 09:00:00 Ahmed Musa $ Extensions to the xkeyval parser (AM) ] \NeedsTeXFormat{LaTeX2e}[1996/12/01] diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-core.tex b/Master/texmf-dist/tex/latex/skeyval/skeyval-core.tex index 83348e842a8..709b36b5496 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval-core.tex +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-core.tex @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'skeyval-core.tex', version 1.1a, 2012/10/16. % +% This is file 'skeyval-core.tex', version 1.2, 2013/02/10. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -23,7 +23,7 @@ % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % % and skeyval-testpkg.sty. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \csname skeyval-core-loaded\endcsname @@ -75,26 +75,25 @@ \newdimen\skvz@\skvz@=0pt\relax \newcount\skvm@ne\skvm@ne=-1\relax \ifcase - \ifx\eTeXversion\@undefined0\else - \ifnum\eTeXversion<\tw@0\else1\fi\fi\relax + \ifx\eTeXversion\@undefined 0\else + \ifnum\eTeXversion<\tw@ 0\else 1\fi + \fi\relax \errhelp{This package requires eTeX version 2 or higher.} \errmessage{skeyval package: eTeX not loaded or old version.} \expandafter\endinput \fi -%\chardef\skv@five=5\relax -%\chardef\skv@six=6\relax \newif\ifskv@latex \newif\ifskv@tempst \ifx\ProvidesFile\@undefined \skv@latexfalse - \message{File 'skeyval-core.tex' 2012/10/16 v1.1a: + \message{File 'skeyval-core.tex' 2013/02/10 v1.2: Core of 'skeyval' key-value parser (AM)} \input skeyval-ltxcmds \else \skv@latextrue \ProvidesFile{skeyval-core.tex} - [2012/10/16 v1.1a Base file of skeyval package (AM)] + [2013/02/10 v1.2 Base file of skeyval package (AM)] \@addtofilelist{skeyval-core.tex} \long\def\@nodocument#1{% \@latex@error{'#1' appeared\on@line\space without @@ -105,12 +104,19 @@ % skeyval-ltxcmds.tex defines \PackageError, etc: \protected\def\skv@warn{\PackageWarningNoLine{skeyval}} \protected\def\skv@err{\PackageError{skeyval}} - +% No \protected for \skv@ehd: +\def\skv@ehd{% + I have encountered a problem here. Try typing <return> + \MessageBreak to proceed. If that doesn't work, type X then + <return>\MessageBreak to quit. +} +\let\skvgenericexception\@latexerr \protected\def\skvtracingall{% \tracinggroups\@ne\tracingifs\@ne\loggingall\tracingassigns\@ne } \let\skvloggingall\skvtracingall - +\long\def\skviofii#1#2{#1} +\long\def\skviiofii#1#2{#2} % A \relax'ed command should not be redefined, because we don't know % if it is temporarily or permanently made \relax. \long\def\skvifdefinable#1#2{% @@ -119,28 +125,81 @@ \else \expandafter\@secondoftwo \fi - {\@latex@error{Command '\string#1' already defined}\@ehd} + {\@latex@error{Command '\string#1' already defined}\skv@ehd} {#2}% } - % \skvgenloop{<parser>}{<list>}{<1.parameter.callback>} -% The parser may be empty. This is the case for nsv/tsv lists. -\def\skvgenloop#1#2#3{% +% +% 1. The parser may be empty. This is the case for nsv/tsv lists. +% 2. The normalization of the list, including dealing with active parsers, +% is left to the caller. +% 3. \@iden will help remove spurious leading spaces. +% +\protected\def\skvgenloop#1#2#3{% \def\skv@gendo##1#1{% \ifx\skv@gendo##1\expandafter\@gobble\else\expandafter\@iden\fi - {#3\skv@gendo}% + {#3\expandafter\skv@gendo\@iden}% + }% + \expandafter\skv@gendo\@iden#2#1\skv@gendo#1% +} +% \skvrescan{<macro>} +\protected\def\skvrescan#1{% + \begingroup + \endlinechar\m@ne\newlinechar\m@ne + \catcode`\@=11\relax + \everyeof{\skv@rescan@guard}% + \def\reserved@a##1\skv@rescan@guard{% + \endgroup + \edef#1{\unexpanded\expandafter{\@gobble##1}}% + }% + % \relax protects any blank space leading the content of #1: + \expandafter\reserved@a\scantokens\expandafter{\expandafter\relax#1}% +} + +% Process a comma list with a simple callback. This can't be used if #2 +% isn't scannable or if scanning #2 will change the signature of +% its token list. +% +% \skv@commaact{<list>}{<1.parameter.callback>} +% +% Example: +% +% \def\emptify{\skv@commaact{\def##1{}}} +% +\begingroup +\catcode`\,=\active +\protected\gdef\skv@commaact#1#2{% + \begingroup + \toks@{}% + \def,##1{% + \ifx\skv@commaact##1\else + \ifx,##1% + % Double comma seen: + \expandafter\expandafter\expandafter,% + \else + \toks@\expandafter{\the\toks@#2}% + \fi + \fi }% - \skv@gendo#2#1\skv@gendo#1% + \begingroup + \edef\skv@tempa{\unexpanded{,#1}}% + \catcode`\,=\active + \skvrescan\skv@tempa + % Add a trailing \skv@commaact, in case the list is ended by a comma (,): + \expandafter\endgroup\skv@tempa,\skv@commaact + \expandafter\endgroup\the\toks@ } -\def\skvnewregister#1#2{% +\endgroup + +\protected\def\skvnewregister#1#2{% \def\skv@prova{#1}% \def\skv@provb{\bool}% - % We don't want to expose \if: + % We don't want to expose \if while in the next conditional: \def\skv@provc{\if}% \ifx\skv@prova\skv@provb \let\skv@prova\skv@provc \fi - \skvgenloop{}{#2}{% + \skv@commaact{#2}{% \skvifdefinable##1{% \csname new\expandafter\expandafter\expandafter\@gobble \expandafter\string\skv@prova\endcsname##1% @@ -148,13 +207,7 @@ }% } \let\skvnewregisters\skvnewregister - -\skvnewregisters\toks{\skv@toksa\skv@toksb} - -% \skvletmanytocmd{<nsv.cmdlist>}{<cmd>} -\long\def\skvletmanytocmd#1#2{% - \skvgenloop{}{#1}{\let##1= #2}% -} +\skvnewregisters\toks{\skv@toksa,\skv@toksb} % Sometimes we change \bgroup temporarily to avoid \futurelet confusing % it with explicit \bgroup character. The change does confuse \skvifnextchar @@ -162,36 +215,50 @@ % in \skvifnextchar: \let\skv@orig@bgroup\bgroup +\def\reserved@a#1{% + \def\skvifnextisouter{% + \expandafter\skv@ifnextisouter\meaning\skv@nextseen#1\relax + }% + \def\skv@ifnextisouter##1#1##2\relax{% + \ifcat$##2$\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi + }% +} +\expandafter\reserved@a\expandafter{\detokenize{outer macro}:} + % We modify LaTeX kernel's \@ifnextchar to eliminate the need for -% doubling the hash character in #2 or #3. \@nextseen may be needed +% doubling the hash character in #2 or #3. \skv@nextseen may be needed % outside the group; so we use \global. \long\def\skvsimpleifnextchar#1#2#3{% \begingroup \let\reserved@d=#1% \edef\reserved@a{\endgroup\unexpanded{#2}}% \edef\reserved@b{\endgroup\unexpanded{#3}}% - \global\futurelet\@nextseen\skv@simpleifnext + \global\futurelet\skv@nextseen\skv@simpleifnext } \def\skv@simpleifnext{% - \ifx\@nextseen\@sptoken - % Experience shows that this \skv@ifnextdo must be unique: If we were - % to use \next or some other generic command, it might have been - % let to \if or \fi before being assigned here and will confuse - % the above \ifx: - \let\skv@ifnextdo\skv@simpleifn@xt + \ifx\skv@nextseen\@sptoken + \let\skv@letnext\skv@simpleifn@xt \else - \ifx\@nextseen\reserved@d - \let\skv@ifnextdo\reserved@a + \ifx\skv@nextseen\reserved@d + \let\skv@letnext\reserved@a \else - \let\skv@ifnextdo\reserved@b + \let\skv@letnext\reserved@b \fi \fi - \skv@ifnextdo + \skv@letnext } \lowercase{\def\skv@simpleifn@xt} {% - \global\futurelet\@nextseen\skv@simpleifnext + \global\futurelet\skv@nextseen\skv@simpleifnext } -\long\protected\def\skvifnextchar#1#2#3{% + +% Tests for \skvifnextchar: +% +% \outer\def\foo{} +% \iftrue\skvifnextchar*\relax\relax\foo\fi +% \iftrue\skvifnextchar*\relax\relax\fi +% \skvifnextchar*\relax\relax\iftrue\fi +% +\protected\long\def\skvifnextchar#1#2#3{% \skvsimpleifnextchar\skv@orig@bgroup{% \skvsimpleifnextchar{#1}{#2}{#3}% }{% @@ -200,7 +267,11 @@ \skvsimpleifnextchar\egroup{% \skvsimpleifnextchar{#1}{#2}{#3}% }{% - \skv@ifnextchar@a{#1}{#2}{#3} + \skvifnextisouter{% + \skvsimpleifnextchar{#1}{#2}{#3}% + }{% + \skv@ifnextchar@a{#1}{#2}{#3}% + }% }% }% } @@ -224,6 +295,14 @@ \fi {#1}{\unexpanded{#3}}% } +\let\skv@sav@ifnextchar\skvifnextchar +\protected\def\skvusesimpleifnextchar{% + \let\skvifnextchar\skvsimpleifnextchar +} +\let\skvuselatexifnextchar\skvusesimpleifnextchar +\protected\def\skvuserobustifnextchar{% + \let\skvifnextchar\skv@sav@ifnextchar +} % Expandable \@testopt: % @@ -267,11 +346,12 @@ \skvifstar{\let\l@ngrel@x\relax#1}{\let\l@ngrel@x\long#1}% } \long\protected\def\skv@testopt#1#2{\skvifnextchar[{#1}{#1[{#2}]}} +\long\protected\def\skv@testpnopt#1#2{\skvifnextchar({#1}{#1({#2})}} \long\protected\def\skvifstar#1{\skvifnextchar*{\@firstoftwo{#1}}} \def\skv@def@#1#2#3{% \ifdefined#3% \ifx#3\relax\else - \skv@err{Command \detokenize{#3} already exists}\@ehd + \skv@err{Command \detokenize{#3} already exists}\skv@ehd \fi \fi \ifcat$\detokenize{#2}$\else @@ -293,6 +373,7 @@ \skvrobustdef*\skvrobustredef{\skvstarorlong{\skv@redef@{}{p}}} \skvrobustdef*\skvrobustgdef{\skvstarorlong{\skv@def@{g}{p}}} \skvrobustdef*\skvnewdef{\skvstarorlong{\skv@def@{}{}}} +\skvrobustdef*\skvrenewdef{\skvstarorlong{\skv@redef@{}{}}} \skvrobustdef*\skvnewedef{\skvstarorlong{\skv@def@{e}{}}} \skvrobustdef*\skvnewgdef{\skvstarorlong{\skv@def@{g}{}}} \skvrobustdef*\skvrobustcsdef{\skvstarorlong{\skv@csdef@{}{p}}} @@ -305,10 +386,17 @@ } \skvrobustdef*\skvcomment{% \begingroup - \catcode`\{=12 \catcode`\}=12 \catcode`\#=12\relax - \skv@c@mment + \def\do##1{\catcode`##1=12\relax}% + \dospecials + \skv@endcomment } -\skvrobustdef\skv@c@mment#1\endcomment{\endgroup} +\begingroup +\catcode`\!=0 +\catcode`\\=12 +!long!gdef!skv@endcomment#1\endcomment{!endgroup} +!endgroup +%\skvrobustdef\skv@c@mment#1\endcomment{\endgroup} + \skvnewedef*\skv@hashchar{\string#} \let\nofilter\relax % Don't use '=' at the end of the following definition; the user @@ -328,6 +416,7 @@ \skvnewdef\skv@gobbletoend#1\skv@gobble@nil{} \skvnewlet\skv@gobble@nil\relax \def\@space{ } +\let\then\iffalse \skvnewdef\skvswap#1#2{#2#1} \skvnewdef*\skv@quark{\@gobble\skv@quark} \skvnewlet\skvrom\romannumeral @@ -339,9 +428,12 @@ \skvnewdef\skvafterelsei#1\else#2\fi{\fi#1} \skvnewlet\skvafterelse\skvafterelsei \skvnewdef\skvafterelseii#1\else#2\fi{\fi#2} -\skvnewedef*\skv@simplearg{\unexpanded{#1}} - -\long\def\skv@in@#1#2{% +\skvnewdef*\skv@simplearg{##1} +\skvnewlet\skvsanitizemacro\@onelevel@sanitize +\skvrobustdef*\skv@usetempst#1#2{% + \edef#2{\skvifdefboolTF{skv@tempst}\skvexpandonce\unexpanded{#1}}% +} +\skvrobustdef*\skvtestifin#1#2{% \begingroup \long\def\in@@##1#1##2\in@@{% \edef\in@@{\unexpanded{##2}}% @@ -352,7 +444,7 @@ } \skvrobustdef*\skvcsnewif#1{% \skvifstrcmpTF{#1}{x}{% - \skv@err{Redefining primitve '\@backslashchar ifx'?}\@ehd + \skv@err{Redefining primitve '\@backslashchar ifx'?}\skv@ehd }{% \csname newif\expandafter\endcsname\csname if#1\endcsname }% @@ -376,8 +468,8 @@ \edef#2{.#1}% \edef#2{\expandafter\skv@zapspaces#2 \zap@nil}% } - -\newcommand\skvifleadspace[3]{% +% \skvifleadspaceTF{<toks>}{<true>}{<false>} +\newcommand\skvifleadspaceTF[3]{% \romannumeral\csname @\skvifnullTF{#1}{second}{\iffalse{\fi\skv@ifleadspace.#1 x}}% oftwo\endcsname{0 #2}{0 #3}% @@ -387,6 +479,8 @@ \expandafter\@gobble\expandafter{\iffalse}\fi } +% \skvifldspaceTF is faster than \skvifleadspaceTF. +% % \skvifldspaceTF{ }{}{} gives <true> as desired. \begingroup \lccode`\&=0 \catcode`\&=7 \lccode`\!=0 \catcode`\!=8 @@ -406,7 +500,10 @@ }% } } - +\skvnewdef\skvotrimspace{\expandafter\skvtrimspace\expandafter} +\skvnewdef\skvxtrimspace#1{% + \expandafter\skvtrimspace\expandafter{\romannumeral-`\q#1}% +} \skvrobustdef*\skvdespace#1#2{\edef#2{\skvtrimspace{#1}}} \skvrobustdef*\skvdespacecontent#1{% \edef#1{\expandafter\skvtrimspace\expandafter{#1}}% @@ -429,16 +526,14 @@ % \skvifcsname x\then\def\x{T}\else\def\x{F}\fi \skvnewdef*\skvifcsname#1\then{\if0\skvifcsdefTF{#1}{0}{1}} \skvnewdef*\skvifdefTF#1{% - \skvifblankTF{#1}\@secondoftwo{% - \skvifxTF#1\@undefined{% - \@secondoftwo - }{% - \ifx\relax#1% - \expandafter\@secondoftwo - \else - \expandafter\@firstoftwo - \fi - }% + \skvifxTF{#1}\skv@undefined{% + \@secondoftwo + }{% + \ifx\relax#1% + \expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi }% } \skvnewdef*\skvifdefFT#1{\skvifdefTF{#1}\@secondoftwo\@firstoftwo} @@ -461,8 +556,21 @@ }% } \skvnewdef*\skvifcsdefFT#1{\skvifcsdefTF{#1}\@secondoftwo\@firstoftwo} -\def\skv@ifx@#1#2\skv@ifx@nil{\expandafter#1} -\def\skv@ifx@@#1#2\skv@ifx@nil{#1} +% Don't check for blank #1. For internal use: +\skvnewdef*\skvifnamedefTF#1{% + \ifcsname#1\endcsname + \expandafter\ifx\csname#1\endcsname\relax + \expandafter\expandafter\expandafter\@secondoftwo + \else + \expandafter\expandafter\expandafter\@firstoftwo + \fi + \else + \expandafter\@secondoftwo + \fi +} +\skvnewdef*\skvifnamedefFT#1{\skvifnamedefTF{#1}\@secondoftwo\@firstoftwo} +\skvnewdef*\skv@ifx@#1#2\skv@ifx@nil{\expandafter#1} +\skvnewdef*\skv@ifx@@#1#2\skv@ifx@nil{#1} \skvnewdef*\skvifxTF#1#2{% \csname @\expandafter\expandafter\expandafter \ifx\skv@ifx@#1\batchmode\skv@ifx@nil\skv@ifx@@#2\noboundary\skv@ifx@nil @@ -484,8 +592,6 @@ }% }% } - -\let\then\iffalse \begingroup % Keep lccode, in case the test occurs in a table: \lccode`\&=0 \catcode`\&=8 @@ -508,7 +614,7 @@ \csname @\csname if#1\endcsname first\else second\fi oftwo\endcsname }{% - \skv@err{Undefined boolean '#1'}\@ehd + \skv@err{Undefined boolean '#1'}\skv@ehd }% }% } @@ -519,6 +625,12 @@ \csname @\csname if#1\endcsname first\else second\fi oftwo\endcsname } \skvnewdef*\skvifdefboolFT#1{\skvifdefboolTF{#1}\@secondoftwo\@firstoftwo} +\skvrobustdef*\skvaftergroupifboolTF#1\endgroup{% + \skvifboolTF{#1}{\endgroup\@firstoftwo}{\endgroup\@secondoftwo}% +} +\skvrobustdef*\skvaftergroupifboolFT#1\endgroup{% + \skvifboolTF{#1}{\endgroup\@secondoftwo}{\endgroup\@firstoftwo}% +} % \skvifboolvalTF{<toks>}{<true>}{<false>} \skvrobustdef*\skvifboolvalTF#1{% \skvxifinTF{,\expandafter\skvtrimspace\expandafter @@ -553,13 +665,13 @@ \skvaftergroupdef#2\endgroup } \skvrobustdef*\skv@badboolerr#1{% - \skv@err{Invalid boolean value '#1'; expected 'true' or 'false'}\@ehd + \skv@err{Invalid boolean value '#1'; expected 'true' or 'false'}\skv@ehd } % Switches and toggles have separate namespaces. \skvrobustdef*\skvnewswitch#1{% \skvifcsdefTF{skv@switch@#1}{% - \skv@err{Switch '\detokenize{#1}' already exists}\@ehd + \skv@err{Switch '\detokenize{#1}' already exists}\skv@ehd }{% \skvcsdef{skv@switch@#1}{01}% }% @@ -581,19 +693,19 @@ \skvifcsdefTF{skv@switch@#1}{% \skvcsdef{skv@switch@#1}{00}% }{% - \skv@err{No switch '\detokenize{#1}'}\@ehd + \skv@err{No switch '\detokenize{#1}'}\skv@ehd }% } \skvrobustdef*\skvswitchfalse#1{% \skvifcsdefTF{skv@switch@#1}{% \skvcsdef{skv@switch@#1}{01}% }{% - \skv@err{No switch '\detokenize{#1}'}\@ehd + \skv@err{No switch '\detokenize{#1}'}\skv@ehd }% } \skvrobustdef*\skvnewtog#1{% \skvifcsdefTF{skv@toggle@#1}{% - \skv@err{Switch '\detokenize{#1}' already exists}\@ehd + \skv@err{Switch '\detokenize{#1}' already exists}\skv@ehd }{% \skvcslet{skv@toggle@#1}\@secondoftwo }% @@ -612,14 +724,14 @@ \skvifcsdefTF{skv@toggle@#1}{% \skvcslet{skv@toggle@#1}\@firstoftwo }{% - \skv@err{No toggle '\detokenize{#1}'}\@ehd + \skv@err{No toggle '\detokenize{#1}'}\skv@ehd }% } \skvrobustdef*\skvsettogfalse#1{% \skvifcsdefTF{skv@toggle@#1}{% \skvcslet{skv@toggle@#1}\@secondoftwo }{% - \skv@err{No toggle '\detokenize{#1}'}\@ehd + \skv@err{No toggle '\detokenize{#1}'}\skv@ehd }% } @@ -630,18 +742,6 @@ \skvnewdef*\skvifplaswFT#1{% \if#1\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi } -% \def\swa{01} \def\swb{01} -% \if\skvnegateplasw\swa...\else...\fi -% \if\skvifbothplaswtrue\swa\swb...\else...\fi -% \if\skvifoneplaswtrue\swa\swb...\else...\fi -\skvnewdef*\skvnegateplasw#1{0\skvifplaswTF{#1}10}% -\skvnewdef*\skvifbothplaswtrue#1#2{% - 0\ifcase#1#2 \expandafter0\else\expandafter1\fi -} -\skvnewdef*\skvifoneplaswtrue#1#2{% - 0\ifnum#1#2<101 \expandafter0\else\expandafter1\fi -} - \skvnewdef\skvifcondTF#1\fi{% \csname @#1first\else second\fi oftwo\endcsname } @@ -670,21 +770,33 @@ \skvrobustdef*\skvgundef#1{\global\let#1\@undefined} \skvrobustdef*\skvcsundef#1{\skvcslet{#1}\@undefined} \skvrobustdef*\skvcsgundef#1{\global\skvcslet{#1}\@undefined} +\skvrobustdef*\skvemptify#1{\skv@commaact{#1}{\def##1{}}} +\skvrobustdef*\skvinizero#1{\skv@commaact{#1}{\def##1{0}}} \skvrobustdef*\skvundefcmdlist#1{% \skvcommaparse{#1}\skv@prova{\expandafter\skvundef\skv@prova}% } \skvrobustdef*\skvemptifycmds#1{% \skvcommaparse{#1}\skv@prova{\expandafter\def\skv@prova{}}% } -\skvrobustdef*\skvemptify#1{\def\do##1{\def##1{}}#1} +% \skv@addtocollection{<toks>} +% +% Collect tokens in a group for later exiting the group with them: +% +\skvrobustdef*\skv@addtocollection#1{% + \edef\skv@collection{% + \ifdefined\skv@collection\skvexpandonce\skv@collection\fi + \unexpanded{#1}% + }% +} +% Don't use \do for \dl, in case \do appears as a garbage: +% \skvgarbageitems{\dl<cmd1>\gdl<cmd2>...} +\skvrobustdef*\skvgarbageitems{\skvappto\skv@garbagelist} \skvrobustdef*\skvdumpgarbage{% - \let\gdl\skvgundef - \let\dl\skvundef + \let\gdl\skvgundef\let\dl\skvundef \skv@garbagelist \def\skv@garbagelist{}% } -% \skvgarbageitems{\dl<cmd1>\gdl<cmd2>...} -\skvrobustdef*\skvgarbageitems{\skvappto\skv@garbagelist} + \skvifdefTF\pdfstrcmp{% \let\skv@strcmp\pdfstrcmp }{% @@ -692,8 +804,7 @@ \skvifdefTF\pdf@strcmp{% \let\skv@strcmp\pdf@strcmp }{% - \skv@err{Neither '\string\pdfstrcmp' nor - '\string\pdf@strcmp' exists}\@ehd + \skv@err{Neither '\string\pdfstrcmp' nor '\string\pdf@strcmp' exists}\skv@ehd }% } \skvnewdef\skvifstrcmpTF#1#2{% @@ -715,7 +826,7 @@ \skvrobustdef\skvcslet#1#2{\expandafter\let\csname#1\endcsname#2} \skvrobustdef\skvnewcslet#1{% \skvifcsdefTF{#1}{% - \skv@err{Command '\skvnoexpandcs{#1}' already defined}\@ehd + \skv@err{Command '\skvnoexpandcs{#1}' already defined}\skv@ehd }{% \skvcslet{#1}% }% @@ -726,7 +837,7 @@ } \skvrobustdef\skvnewletcs#1{% \skvifdefTF{#1}{% - \skv@err{Command '\string#1' already defined}\@ehd + \skv@err{Command '\string#1' already defined}\skv@ehd }{% \skvletcs#1% }% @@ -738,7 +849,7 @@ } \skvrobustdef\skvnewcsletcs#1{% \skvifcsdefTF{#1}{% - \skv@err{Command '\skvnoexpandcs{#1}' already defined}\@ehd + \skv@err{Command '\skvnoexpandcs{#1}' already defined}\skv@ehd }{% \skvcsletcs{#1}% }% @@ -755,12 +866,16 @@ \skvexpanded{\endgroup\expandafter\skvcmdexit\csname#1\endcsname}% } -% Taking command and booleans out of a local group under \edef: +% Taking commands and booleans out of a local group under \edef: \skvnewdef*\skvcmdexit#1{% - \edef\noexpand#1{\noexpand\unexpanded{\skvexpandonce{#1}}}% + \skvifdefTF{#1}{% + \edef\noexpand#1{\noexpand\unexpanded{\skvexpandonce{#1}}}% + }{}% } \skvnewdef*\skvcsexit#1{% - \skvcsedef{#1}{\noexpand\unexpanded{\skvexpandcsonce{#1}}}% + % If #1 is undefined, \skvexpandcsonce will make it relax. The + % preliminary test in \skvcmdexit will deal with that situation. + \skvaftercs\skvcmdexit{#1}% } % \edef\x{\endgroup\skvcmdexitloop{\x\y}}: \skvnewdef*\skvcmdexitloop#1{\skv@cmdexitloop#1\end} @@ -776,6 +891,7 @@ \skvnewdef*\skv@boolexitloop#1{% \ifx\end#1\else\skvboolexit{#1}\expandafter\skv@boolexitloop\fi } + \skvnewdef*\skvprotect#{% \ifx\protect\@typeset@protect\skv@protect\@firstofone\fi \ifx\protect\@unexpandable@protect\skv@protect\skvunexpandable\fi @@ -791,13 +907,14 @@ \expandafter\endgroup\ifx\skv@prova\skv@nnil \expandafter\@gobble\else\expandafter\@firstofone\fi } - +% \skvadvanceno{<cmd>}{<number>} \skvrobustdef*\skvsetnumber#1{% \begingroup \def\x{\edef\x{\endgroup\def\noexpand#1{\the\count@}}\x}% \afterassignment\x\count@ } \skvnewlet\skvsetno\skvsetnumber +% \skvadvanceno{<cmd>}{<number>} \skvrobustdef*\skvadvanceno{\skv@advanceno\relax} \skvrobustdef*\skvgadvanceno{\skv@advanceno\global} \skvrobustdef*\skv@advanceno#1#2#3{% @@ -808,7 +925,7 @@ \skvifdefTF#2{% #1\edef#2{\the\numexpr#2+#3\relax}% }{% - \skv@err{Number '\string#2' is not defined}\@ehd + \skv@err{Number '\string#2' is not defined}\skv@ehd }% } \skvrobustdef*\skvpushnumber#1{% @@ -822,20 +939,25 @@ \skvifdefTF#1{% \edef#1{\the\numexpr#1+1\relax}% }{% - \skv@err{Number '\string#1' is not defined}\@ehd + \skv@err{Number '\string#1' is not defined}\skv@ehd }% } \skvrobustdef\skv@testst#1{% \skvifstar{\skv@tempsttrue#1}{\skv@tempstfalse#1}% } +% For internal use: +\skvrobustdef\skv@i@ifstar#1{\@ifnextchar*{\@firstoftwo{#1}}} +\skvrobustdef\skv@i@testst#1{% + \skv@i@ifstar{\skv@tempsttrue#1}{\skv@tempstfalse#1}% +} \skvrobustdef\skv@testcl#1{% \skvifnextchar!{\skv@cltrue#1}{\skv@clfalse#1}% } \skvrobustdef\skv@teststopt#1#2{\skv@testst{\skv@testopt{#1}{#2}}} - -% Removing spurious spaces before checking for brace. +% Remove spurious leading and trailing spaces before checking for outer brace. +% Such spaces do hide the outer brace. % If we were to use \skvtrimspace for \skvifbracedTF, then the need % for double \romannumeral will cause problems of premature expansion. \begingroup @@ -859,28 +981,38 @@ \skvnewdef\skvifbracedFT#1{\skvifbracedTF{#1}\@secondoftwo\@firstoftwo} % \skvstripouterbraces{<nr>}<cmd> +% Example: +% \def\x{{{{X}}}} +% \skvstripouterbraces{2}\x \skvrobustdef*\skvstripouterbraces#1#2{% - \begingroup - \@tempcnta\skvz@ - \expandafter\skv@stripouterbraces#2\strip@nil{#2}{#1}% + \skvifemptyTF#2{}{% + \begingroup + \@tempcnta\skvz@ + \expandafter\skv@stripouterbraces#2\strip@nil{#2}{#1}% + }% } \skvrobustdef*\skv@stripouterbraces#1\strip@nil#2#3{% - \advance\@tempcnta\@ne - \skvifnumTF\@tempcnta=#3{% - \edef#2{\unexpanded{#1}}% + \edef\skv@prova{\unexpanded{#1}}% + \skvifxTF#2\skv@prova{% \skvaftergroupdef#2\endgroup }{% - \skv@stripouterbraces#1\strip@nil{#2}{#3}% + \advance\@tempcnta\@ne + \skvifnumTF\@tempcnta=#3{% + \let#2\skv@prova + \skvaftergroupdef#2\endgroup + }{% + \let#2\skv@prova + \expandafter\skv@stripouterbraces#2\strip@nil{#2}{#3}% + }% }% } - \skvrobustdef*\skvifescapedTF#1{% \begingroup\escapechar92\relax \edef\x{\expandafter\skv@car\string#1x\car@nil}% \expandafter\endgroup \csname @\ifx\x\@backslashchar first\else second\fi oftwo\endcsname } -\skvnewdef\skvifnotescaped#1{\skvifescapedTF{#1}\@secondoftwo\@firstoftwo} +\skvnewdef\skvifescapedFT#1{\skvifescapedTF{#1}\@secondoftwo\@firstoftwo} \skvnewdef*\skvremovescape#1{\expandafter\@gobble\string#1} \skvnewdef*\skvgobblescape#1{% \skvifblankTF{#1}{}{% @@ -908,7 +1040,13 @@ } \skvnewdef*\skvnoexpandcs#1{\skvexpandonce{\csname#1\endcsname}} \skvnewdef*\skvexpandcsonce#1{% - \unexpanded\expandafter\expandafter\expandafter{\csname#1\endcsname}% + \expandafter\skvexpandonce\expandafter{\csname#1\endcsname}% +} +\skvnewdef*\skvexpandcstwice#1{% + \expandafter\skvexpandtwice\expandafter{\csname#1\endcsname}% +} +\skvnewdef*\skvexpandcsthrice#1{% + \expandafter\skvexpandthrice\expandafter{\csname#1\endcsname}% } \skvrobustdef\skvexpanded#1{\begingroup\edef\x{\endgroup#1}\x} \skvrobustdef\skvexpandarg#1#2{\skvexpanded{\unexpanded{#1}{#2}}} @@ -928,8 +1066,15 @@ \expandafter\skvswap\expandafter{\expandafter{#2}}{#1}% } \skvnewlet\skvexpbracenext\skvexpandbracenext +% Eg, \skvexpandintonext\x[\y], \skvexpandintonext\x{\y}. +% This isn't expandable, because #1 may not be just one token. +\skvnewdef\skvexpandintonext#1{% + \begingroup + \edef\reserved@a{\endgroup\unexpanded{#1}}% + \expandafter\reserved@a\expandafter +} \skvrobustdef*\skvifinTF#1#2{% - \skv@in@{#1}{#2}% + \skvtestifin{#1}{#2}% \csname @\ifin@ first\else second\fi oftwo\endcsname } \skvrobustdef*\skvifinFT#1#2{\skvifinTF{#1}{#2}\@secondoftwo\@firstoftwo} @@ -938,40 +1083,164 @@ \skvrobustdef*\skvifindetokTF#1#2#3{% \skvexpandtwoargs\skvifinTF{#1\skvoxdetok{#2}#1}{#1\skvoxdetok{#3}#1}% } -\skvnewdef\skviffound#1\in#2\then{\skv@in@{#1}{#2}\ifin@} -\skvnewdef\skvxiffound#1\in#2\then{\skvexpandtwoargs\skv@in@{#1}{#2}\ifin@} +\skvnewdef\skviffound#1\in#2\then{\skvtestifin{#1}{#2}\ifin@} +\skvnewdef\skvxiffound#1\in#2\then{\skvexpandtwoargs\skvtestifin{#1}{#2}\ifin@} % \skv@kvsplit{<kvpair>}{<parametered.callback>} \skvrobustdef*\skv@kvsplit#1#2{% \begingroup - \def\skv@tempa##1=##2=##3\skv@kvsplit{% - \endgroup#2% - }% + \def\skv@tempa##1=##2=##3\skv@kvsplit{\endgroup#2}% \skv@tempa#1==\skv@kvsplit } -\skvrobustdef*\skv@kvosplit#1{\skvexpbracenext\skv@kvsplit{#1}} -% \skv@slsplit{<slashlist>}{<parametered.callback>} -\skvrobustdef*\skv@slsplit#1#2{% +\skvrobustdef*\skv@okvsplit#1{\skvexpbracenext\skv@kvsplit{#1}} +% \skv@slashsplit{<slashlist>}{<parametered.callback>} +% Patrons calling \skv@slashsplit should note that it may return +% ^skv^ for any missing components: +\skvrobustdef*\skv@slashsplit#1#2{% \begingroup - \def\skv@tempa##1/##2/##3/##4/##5/##6/##7/##8/##9\skv@slsplit{% + \def\skv@tempa##1/##2/##3/##4/##5/##6/##7/##8/##9\skv@slashsplit{% \endgroup#2% }% - \skv@tempa#1/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/\skv@slsplit + \skv@tempa#1/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^\skv@slashsplit } -\skvnewlet\skv@slashsplit\skv@slsplit -\skvrobustdef*\skv@slosplit#1{\skvexpbracenext\skv@slsplit{#1}} +\skvrobustdef*\skv@oslashsplit#1{\skvexpbracenext\skv@slashsplit{#1}} -\skvrobustdef*\skv@rescan#1{% +% \skv@splitpath@a{<path.macro>}{<pref.macro>}{<fam.macro>} +% Here, <path.macro> has the form {<pref>/<fam>}. +\skvrobustdef*\skv@splitpath@a#1#2#3{% \begingroup - \endlinechar\m@ne\newlinechar\m@ne - \catcode`\@=11 - \everyeof{\skv@rescan@}% - \def\reserved@a##1\skv@rescan@{% - \endgroup\edef#1{\unexpanded{##1}}% + \ifx#1\@empty + \skv@err{No key can have empty path}\skv@ehd + \else + \skv@oslashsplit{#1}{% + \edef#2{\skvtrimspace{##1}}% + \edef#3{\skvtrimspace{##2}}% + \skvstripouterbraces{2}#2% + \skvstripouterbraces{2}#3% + \ifx#3\skv@rej + \let#3#2% + \let#2\skvdefaultprefix + \fi + }% + \fi + \skvexpanded{\endgroup\skvcmdexit#2\skvcmdexit#3}% +} +% \skv@splitpath@b{<path.macro>}{<pref.macro>}{<fam.macro>} +% Here, <path.macro> has the form {<pref>}{<fam>}. +% Here, we don't expect to find empty entries in #1, since +% \skv@splitpath@a wouldn't have made such an entry in #1. But don't +% mind, let us still test for empty. +\skvrobustdef*\skv@splitpath@b#1#2#3{% + \begingroup + \def\skv@prova##1##2\@nil{% + \edef#2{\skvtrimspace{##1}}% + \edef#3{\skvtrimspace{##2}}% + \ifx#3\@empty + \let#3#2% + \let#2\skvdefaultprefix + \fi + }% + \expandafter\skv@prova#1\@nil + \skvexpanded{\endgroup\skvcmdexit#2\skvcmdexit#3}% +} +% \skv@formatpaths{<paths>}{<macro.to.reveive.formated.paths>} +% +% Format <paths> given in the form +% +% {<pref1>/<fam1>},...,{<pref-n>/<fam-n>} +% +% into +% +% \skv@pathdo{<pref1>}{<fam1>}...\skv@pathdo{<pref-n>}{<fam-n>} +% +\skvrobustdef*\skv@formatpaths#1#2{% + \begingroup + \skvifdefTF#2{}{\def#2{}}% + \edef\skv@prova{#1}% + \skvcsvnormalize[/]\skv@prova + \skvcommaparse*\skv@prova\skv@prova{% + \skv@splitpath@a\skv@prova\skv@tempa\skv@tempb + \edef\skv@prova{{\skv@tempa}{\skv@tempb}}% + \skvxifinTF{\skvoxdetok\skv@prova}{\skvoxdetok{#2}}{}{% + \edef#2{\skvexpandonce#2\noexpand\skv@pathdo\skv@prova}% + }% + }% + \skvaftergroupdef#2\endgroup +} +% \skv@makepaths{<prefix.macro>}{<families.macro>}{<pathlist.macro>} +% {<wrapper.macro>} +% +% Attach prefix to families, to make pathlist. <prefix> must contain +% only one element. +% +\skvrobustdef*\skv@makepaths#1#2#3#4{% + \begingroup + \skv@ifnoprefix#1{\let#1\skvdefaultprefix}{}% + \edef\skv@pref{#1}% + \skvdespacecontent\skv@pref + \skvstripouterbraces{2}\skv@pref + \skv@ifoneprefix\skv@pref{% + \skvifdefTF#3{}{\def#3{}}% + \skvcommaparse*#2\skv@prova{% + \skvstripouterbraces{2}\skv@prova + \edef\skv@prova{{\skv@pref}{\skv@prova}}% + \skvxifinTF{\skvoxdetok\skv@prova}{\skvoxdetok{#3}}{}{% + \edef#3{\skvexpandonce{#3}\noexpand#4\skv@prova}% + }% + }% + }{% + \skv@err{Only one prefix allowed here} + {The service you've called takes only one key prefix}% + }% + \skvaftergroupdef#3\endgroup +} +% \skv@ifoneprefix{<prefix>} +\skvrobustdef*\skv@ifoneprefix#1{% + \skvxifinTF{,}{\skvoxdetok{#1}}{% + \begingroup + \def\skv@prova##1,##2\skv@nil{% + \endgroup + \skvifblankTF{##2}{% + \def#1{##1}% + }{% + \@secondoftwo + }% + }% + \expandafter\skv@prova#1\skv@nil + }{% + \@firstoftwo + }% +} +% \skv@ifnoprefix{<prefix.macro>} +\skvrobustdef*\skv@ifnoprefix#1{% + % Think twice before changing this conditional! + \ifcase0% + \ifx#1\skv@undefined\else\ifx#1\@empty\else 1\fi\fi\relax + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +\skvrobustdef*\skvifmacroTF#1{% + \skvifntypeTF{#1}{% + \begingroup + \edef\skv@tempa##1{\def##1####1\detokenize{macro}:####2\skvrelax}% + \skv@tempa\skv@tempa{% + \expandafter\endgroup\ifx\@nnil##2\@nnil + \expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi + }% + \edef\skv@tempb##1{##1\detokenize{macro}:\skvrelax}% + \skv@tempb{\expandafter\skv@tempa\meaning#1}% + }{% + \@secondoftwo }% - \expandafter\reserved@a\scantokens\expandafter{#1}% } +\skvrobustdef*\skvifmacroFT#1{\skvifmacroTF{#1}\@secondoftwo\@firstoftwo} +% If there is a digit present in #1: \skvnewdef*\skvifdigitpresentTF#1{% \skvifcondTF\if0\skvifblankTF{#1}{1}{\skv@ifdigitpresent#1\skv@nnil}\fi } @@ -1072,10 +1341,10 @@ }\x } \endgroup -\skvdefregistertester\skip\skvifskip -\skvdefregistertester\count\skvifcount -\skvdefregistertester\dimen\skvifdimen -\skvdefregistertester\toks\skviftoks +\skvdefregistertester\skip\skvifskipTF +\skvdefregistertester\count\skvifcountTF +\skvdefregistertester\dimen\skvifdimenTF +\skvdefregistertester\toks\skviftoksTF % Converting units. % Examples: @@ -1134,17 +1403,17 @@ % \skvifdimensionable{1pt\relax\skvrelax}{\def\x{T}}{\def\x{F}} % -\skvnewregister\bool\ifskv@isinteger +\skvnewregister\bool{\ifskv@isinteger} % In case the argument of \skvifintegerTF containes \numexpr: \skvnewlet\skv@catch@nil\relax -% #1: Essence, #2: Test token +% \skvensureinteger{<essence>}{<test token>} \skvrobustdef*\skvensureinteger#1#2{% \begingroup \def\skv@prova##1\skv@catch@nil{% % If ##1 is empty or contains nothing before a \relax, it's fine: \ifx\relax##1\relax\else - \skv@err{Token '#2' for '#1' isn't an integer}\@ehd + \skv@err{Token '#2' for '#1' isn't an integer}\skv@ehd \fi }% \afterassignment\skv@prova\skv@cnta#2\relax\skv@catch@nil @@ -1170,7 +1439,7 @@ \def\skv@dimunit{}% % Does 'pt' mean 0pt or 1pt? Make it an invalid input: \lowercase{\skvifindetokTF{,}{#1}}\skv@validunit{% - \@latexerr{Illegal step '#1': no number found with it}\@ehd + \skv@err{Illegal step '#1': no number found with it}\skv@ehd }{}% \skv@isintegerfalse \skvifintegerTF{#1}{% @@ -1214,7 +1483,7 @@ \skvifinTF{,#1,}{,\hsize,\vsize,}{% \skv@provb }{% - \skvifdimen{#1}{% + \skvifdimenTF{#1}{% \skv@provb }{% \lowercase{\skvifindetokTF{,}{#1#2}}\skv@validunit{% @@ -1299,7 +1568,7 @@ \skvifinTF{*}{#1}{% \skvifinTF{/}{#1}{% \skv@err{I can't parse this: both star (*) and slash - \MessageBreak (/) are in '#1'}\@ehd + \MessageBreak (/) are in '#1'}\skv@ehd }{% \skvifblankTF{#1}{}{\skv@dimexpr@times#1*\skv@catch@nil}% }% @@ -1378,7 +1647,7 @@ \skvrobustdef*\skvnormalize#1#2#3#4{% \def\skv@prova##1#1##2##3\skv@nil{% \ifx\skv@nnil##2% - \skv@err{Invalid list type '#1' for command \string\skvnormalize}\@ehd + \skv@err{Invalid list type '#1' for command \string\skvnormalize}\skv@ehd \fi \edef#4{\unexpanded{#3}}% ##2[#2]#4% @@ -1412,6 +1681,7 @@ \do#2,\skv@nil,% \expandafter\endgroup\the\toks@ } +% \skvkvnormalize{<kvlistcmd>} \skvrobustdef*\skvkvnormalize#1{% \begingroup \skv@setupnormalizer{,}% @@ -1518,7 +1788,7 @@ }% \def\skv@parserequalerr##1#1=##2\normal@nil{% \skvifblankTF{##2}{}{% - \skv@err{There is '#1=' in your key-value list}\@ehd + \skv@err{There is '#1=' in your key-value list}\skv@ehd }% }% } @@ -1586,7 +1856,60 @@ {\skv@mac@doubleparser##1#1##2\normal@nil}% }% } -% \skvpushfunctions<base-fn>{<fn-list>}<cnt> +% \skvletmanytocmd{<cmd list>}{<cmd>} +\skvrobustdef*\skvletmanytocmd#1#2{% + \skvcommaparse{#1}\skv@prova{% + \expandafter\let\skv@prova= #2% + }% +} +% \skvnewletmanytocmd{<cmd list>}{<cmd>} +\skvrobustdef*\skvnewletmanytocmd#1#2{% + \skvcommaparse{#1}\skv@prova{% + \expandafter\skv@newcastcommand\skv@prova=#2=\cast@nil + }% +} +% \skvcastcommands{<cmd list>} +% +% <cmd list> -> {<cmd-a1>=<cmd-a2>,...,<cmd-b1>=<cmd-b2>} +% +% In <cmd list>, cast left-hand command to the right-hand command. +% Raise error if left-hand command already exists and isn't equal to +% the right-hand command. +% +% Example: +% +% \skvcastcommands{\ifxx=\ifx,\fii=\fi} +% +\skvrobustdef*\skvcastcommands#1{% + \def\skv@provb##1=##2=##3\cast@nil{\let##1= ##2}% + \skvkvparse{#1}\skv@prova{% + \expandafter\skv@provb\skv@prova==\cast@nil + }% +} +% \skvnewcastcommands{<cmd list>} +% +% <cmd list> -> {<cmd-a1>=<cmd-a2>,...,<cmd-b1>=<cmd-b2>} +% +\skvrobustdef*\skvnewcastcommands#1{% + \skvkvparse{#1}\skv@prova{% + \expandafter\skv@newcastcommand\skv@prova==\cast@nil + }% +} +\skvrobustdef*\skv@newcastcommand#1=#2=#3\cast@nil{% + \skvifdefTF{#1}{% + \ifx#1#2\else + \skv@err{Command \noexpand#1 already exists: + \MessageBreak it can't be cast to \string#2}\skv@ehd + \fi + }{% + \let#1= #2% + }% +} +% \skvpushfunctions<base-fn>{<fn-list>}<counter-number> +% +% 1. <counter-number> is a number, not a counter. +% 2. See file skeyval-for.tex for \skvsavestate and \skvrestorestate. +% \skvrobustdef*\skvpushfunctions#1#2#3{% \skvgadvanceno#3\@ne \begingroup @@ -1601,16 +1924,16 @@ \def\do##1{\let\skvnoexpandcs{\skv@prova{##1}}\noexpand##1}% \skvexpanded{\endgroup#2}% } -% \skvpopfunctions<base-fn><counter> +% \skvpopfunctions<base-fn><counter-number> \skvrobustdef*\skvpopfunctions#1#2{% \begingroup \edef\skv@elt{\skvnoexpandcs{\skvremovescape{#1}@skv@stack}}% \expandafter\skvifdefTF\skv@elt{% \expandafter\ifx\skv@elt\@empty - \skv@err{Stack of '\noexpand#1' is empty}\@ehd + \skv@err{Stack of '\noexpand#1' is empty}\skv@ehd \fi }{% - \skv@err{Stack of '\noexpand#1' is undefined}\@ehd + \skv@err{Stack of '\noexpand#1' is undefined}\skv@ehd }% \edef\skv@prova{\skvexpandtwice\skv@elt}% \edef\skv@provb##1##{\endgroup##1\gdef\skvexpandonce\skv@elt}% @@ -1619,11 +1942,15 @@ } \chardef\skv@stackdepthlimit=6\relax -% #1=stack (macro), #2=list, #3=max depth +% #1=stack (a macro), #2=list, #3=max depth \skvrobustdef*\skvbuildmacrostack#1#2#3{% \begingroup \escapechar92\relax - \@ifdefinable#1{\def#1{}}% + \ifdefined#1% + \skv@err{Stack \noexpand#1 already exists}\skv@ehd + \else + \def#1{}% + \fi \@tempcnta\skvz@ \def\do##1{% \noexpand\skv@elt\noexpand##1% @@ -1651,13 +1978,13 @@ \def\skv@elt##1##2{\let##2=##1}% \else \ifnum#2<\@ne - \skv@err{Can't pop stack: depth currently less than 1}\@ehd + \skv@err{Can't pop stack: depth currently less than 1}\skv@ehd \else \def\skv@elt##1##2{\let##1=##2}% \fi \fi \ifnum#2>\skv@stackdepthlimit - \skv@err{Stack depth limit '\number\skv@stackdepthlimit' exceeded}\@ehd + \skv@err{Stack depth limit '\number\skv@stackdepthlimit' exceeded}\skv@ehd \fi \def\skv@prova##1{% \def\skv@prova####1.##1.####2####3\skv@nil{####2}% @@ -1677,7 +2004,7 @@ \def\do##1,{% \ifx\do##1\else \skvifcsdefTF{if#1##1}{% - \skv@err{Boolean '\skvnoexpandcs{if#1##1}' already exists}\@ehd + \skv@err{Boolean '\skvnoexpandcs{if#1##1}' already exists}\skv@ehd }{% \toks@\expandafter{\the\expandafter\toks@ \csname newif\expandafter\endcsname\csname if#1##1\endcsname}% @@ -1688,18 +2015,35 @@ \expandafter\do\skv@prova,\do,% \expandafter\endgroup\the\toks@ } -% \ifskv@inoptionsec determines if we're in skeyval options section or not. -% Some checks are done in that section. +% Some booleans: +% +% inset = in \skvsetkeys +% viarootofsetkeys = a key is being set via the root of the command +% \skvsetkeys. This is needed because sometimes we +% bypass the root of \skvsetkeys, eg, by calling +% \skv@setkeys@a. +% inclass = in class file. +% kf = key has been found while in \skvsetkeys. +% intry = in 'try set keys'. +% insa = in 'search also set keys'. +% success = key has been found while in 'try set keys'. +% inopt = in process/execute options. +% inpox = in process options. +% inprepo = presetting or post-setting keys. +% inoptionsec = in skeyval package's options processing section. +% Some checks are done in that section. +% \skvnewbools[skv@]{% - inset,st,cl,pl,kf,inpox,prepo,tracingkeys,swa,swb,verbose,% - intry,insa,success,inoptionsec,inopt,handlerswa,handlerswb% + inclass,inset,viarootofsetkeys,processvalueaslist,st,cl,pl,kf,inpox,inopt,% + inprepo,tracingkeys,swa,swb,verbose,intry,insa,success,inoptionsec,% + inreservedhandler,ignorepointers% } -%\skvnewbools{indirkeys} -\skvnewbools[skv]{indef,indirkeys,novalue,valuebraced} +\skvnewbools{indirectkeys} +\skvnewbools[skv]{indef,novalue,valuebraced} \skvnewbools[dirkeys@]{saveunknownkeys} - +% \skvnewcounts[<optional prefix>]{<name list>} \skvrobustdef*\skvnewcounts{\skv@testopt\skv@newcounts{}} \skvrobustdef*\skv@newcounts[#1]#2{% \begingroup @@ -1709,7 +2053,7 @@ \def\do##1,{% \ifx\do##1\else \skvifcsdefTF{#1##1}{% - \skv@err{Counter '\skvnoexpandcs{#1##1}' already exists}\@ehd + \skv@err{Counter '\skvnoexpandcs{#1##1}' already exists}\skv@ehd }{% \toks@\expandafter{\the\expandafter\toks@ \csname newcount\expandafter\endcsname\csname#1##1\endcsname}% @@ -1720,8 +2064,8 @@ \expandafter\do\skv@prova,\do,% \expandafter\endgroup\the\toks@ } -\skvnewcounts[skv@]{cnta,cntb} - +\skvnewcounts[skv@]{tempcnt,cnta} +% \skvnewnumbers[<optional prefix>]{<name list>} \skvrobustdef*\skvnewnumbers{\skv@testopt\skv@newnumbers{}} \skvrobustdef*\skv@newnumbers[#1]#2{% \begingroup @@ -1731,7 +2075,7 @@ \def\do##1,{% \ifx\do##1\else \skvifcsdefTF{#1##1}{% - \skv@err{Number '\skvnoexpandcs{#1##1}' already exists}\@ehd + \skv@err{Number '\skvnoexpandcs{#1##1}' already exists}\skv@ehd }{% \toks@\expandafter{\the\expandafter\toks@ \expandafter\def\csname#1##1\endcsname{0}}% @@ -1742,9 +2086,9 @@ \expandafter\do\skv@prova,\do,% \expandafter\endgroup\the\toks@ } - -\skvnewnumbers[skv@]{keydepth,setkeysdepth,makekeysdepth, - usekeysdepth,trysetkeysdepth,trysetkeysdepth@b,gendepth} +\skvnewlet\skvnewnumber\skvnewnumbers +\skvnewnumbers[skv@]{keydepth,setkeysdepth,preposetdepth,makekeysdepth, + usekeysdepth,trysetkeysdepth,trysetkeysidepth,gendepth} \skvnewnumbers{dirkeys@depth} \skvnewlet\skv@novalue\relax \skvnewdef*\skv@novaluetoks{\skv@novalue} @@ -1754,8 +2098,9 @@ % \quickkeys.define{<family>}[<hp>]{<list>} % \quickkeys.set{<family>}[<na>]{<kvlist>} % -% 1. Quickly defines and set command/store keys. -% 2. Pointers aren't used here, to speed up parsing. +% 1. Quickly define and set command/store keys. +% 2. Pointers aren't used here, to speed up parsing. Use other key +% machineries instead. % 3. Package and class options can't be passed via quick keys. % 4. When defining keys, the syntax of <list> is: % @@ -1768,7 +2113,9 @@ % % 5. The special keys '.exec' and '.exec code' will simply execute the % code <default>, without defining anything. -% 6. Use .na to indicate a missing item that isn't blank or empty. +% 6. Use the token '.na' to indicate a missing item that isn't blank or empty. +% 7. The parser for defining the keys can be specified via \setquickkeysparser. +% The default parser is semicolon (;). % % Example: % \quickkeys.define{fam}[mp@]{% @@ -1781,22 +2128,14 @@ \skvifstrcmpTF{#1}{^skv^}{% \@firstoftwo }{% - \skvifblankTF{#1}{% - \@firstoftwo - }{% - \@secondoftwo - }% + \skvifblankTF{#1}% }% } \skvnewdef*\skv@ifstrrejordotna#1{% \skvifstrcmpTF{#1}{^skv^}{% \@firstoftwo }{% - \skvifstrcmpTF{#1}{.na}{% - \@firstoftwo - }{% - \@secondoftwo - }% + \skvifstrcmpTF{#1}{.na}% }% } \skvnewdef*\skv@ifstrnut#1{% @@ -1806,11 +2145,7 @@ \skvifstrcmpTF{#1}{.na}{% \@firstoftwo }{% - \skvifblankTF{#1}{% - \@firstoftwo - }{% - \@secondoftwo - }% + \skvifblankTF{#1}% }% }% } @@ -1818,22 +2153,14 @@ \skvifxTF#1\skv@rej{% \@firstoftwo }{% - \skvifemptyTF#1{% - \@firstoftwo - }{% - \@secondoftwo - }% + \skvifemptyTF#1% }% } \skvnewdef*\skv@ifcmdrejordotna#1{% \skvifxTF#1\skv@rej{% \@firstoftwo }{% - \skvifxTF#1\skv@dotna{% - \@firstoftwo - }{% - \@secondoftwo - }% + \skvifxTF#1\skv@dotna }% } \skvnewdef*\skv@ifcmdnut#1{% @@ -1843,15 +2170,24 @@ \skvifxTF#1\skv@dotna{% \@firstoftwo }{% - \skvifemptyTF#1{% - \@firstoftwo - }{% - \@secondoftwo - }% + \skvifemptyTF#1% }% }% } - +% \skv@qkeysgetkeynames{<kvlist.cmd>}{<return.cmd>} +\skvrobustdef*\skv@qkeysgetkeynames#1#2{% + \begingroup + \let#2\@empty + \skvkvparse*#1\skv@prova{% + \def\do##1=##2=##3\skv@nil{% + \edef#2{\skvaddlist,#2##1}% + }% + \expandafter\do\skv@prova==\skv@nil + }% + \skvaftergroupdef#2\endgroup +} +\skvrobustdef*\skvsetquickkeysparser{\def\skv@qkeysparser} +\skvsetquickkeysparser{;} \skvrobustdef*\quickkeys#1#{% \edef\skv@tempa{\skvtrimspace{#1}}% \skvxifstrcmpTF{\skvexpandonce\skv@tempa}{.define}{% @@ -1861,44 +2197,54 @@ \skvxifstrcmpTF{\skvexpandonce\skv@tempa}{.set}{% \skv@setquickkeys }{% - \skv@err{Unknown task for \string\quickkeys}\@ehd + \skvxifstrcmpTF{\skvexpandonce\skv@tempa}{.preset}{% + \skv@presetquickkeys + }{% + \skv@err{Unknown task for \string\quickkeys}\skv@ehd + }% }% }% } \skvrobustdef*\skv@defquickkeys#1{\skv@testopt{\skv@defquickkeys@a{#1}}{}} \skvrobustdef*\skv@defquickkeys@a#1[#2]#3{% \endgroup + \edef\skv@qkeysfam{\skvtrimspace{#1}}% \edef\skv@tempa{\skvkeepdoubleslashnormalize{#3}}% - \def\skv@defquickkeys@b##1/##2/##3/##4/##5/##6/##7/##8/##9\skv@nil{% - \skvifinTF{,##1,}{,.exec,.exec code,}{% - ##2\relax - }{% - % Loop over key list, if there are more than one key: - \skvparselist{,}{##1}\skv@tempa{% - % If ##2 is empty, the default will be empty: - \skv@ifstrrejordotna{##2}{}{% - \skvcsedef{#1/\skv@tempa/qkeys.def}{\unexpanded{##2}}% - }% - \skvcsedef{#1/\skv@tempa/qkeys.cbk}{% - % ##3 may be empty: - \skv@ifstrrejordotna{##3}{}{\unexpanded{##3}}% - }% - \skv@ifstrnut{##4}{}{% - \skvcsedef{#1/\skv@tempa/qkeys.chc}{\unexpanded{##4}}% - }% - \skv@ifstrnut{##5}{}{% - \skvcsedef{#1/\skv@tempa/qkeys.arg}{\unexpanded{##5}}% - }% - \skvifblankTF{#2}{}{% - \skvcsedef{#1/\skv@tempa/qkeys.hp}{\unexpanded{#2}}% + \skvexpanded{\skvparselist*{\skv@qkeysparser}}\skv@tempa\skv@tempa{% + \skv@oslashsplit\skv@tempa{% + \skvifinTF{,##1,}{,.exec,.exec code,}{% + ##2\relax + }{% + % Loop over key list, in case there are more than one key: + \skvparselist{,}{##1}\skv@tempa{% + % If ##2 is empty, the default will be empty: + \skv@ifstrrejordotna{##2}{}{% + \skvcsedef{\skv@qkeysfam/\skv@tempa/qkeys.def}{\unexpanded{##2}}% + }% + \skvcsedef{\skv@qkeysfam/\skv@tempa/qkeys.cbk}{% + \skvifblankTF{#2}{}{% + \skvcsletcs{#2\skv@tempa}{\skv@qkeysfam/\skv@tempa/qkeys.val}% + }% + \skv@ifstrrejordotna{##3}{}{\unexpanded{##3}}% + }% + \skv@ifstrnut{##4}{}{% + \skvcsedef{\skv@qkeysfam/\skv@tempa/qkeys.chc}{\unexpanded{##4}}% + }% + \skv@ifstrnut{##5}{}{% + \skvcsedef{\skv@qkeysfam/\skv@tempa/qkeys.arg}{\unexpanded{##5}}% + }% }% }% }% }% - \skvparselist*{;}\skv@tempa\skv@tempa{% - \expandafter\skv@defquickkeys@b\skv@tempa - /^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^\skv@nil - }% +} + +% \quickkeys.preset{<family>}{<kvlist>} +% +\skvrobustdef*\skv@presetquickkeys#1#2{% + \edef\skv@prova{\unexpanded{#2}}% + \skvkvnormalize\skv@prova + \skvcslet{\skvtrimspace{#1}/qkeys.preset}\skv@prova } \skvnewnumbers[skv@]{setqkeysdepth} @@ -1907,60 +2253,80 @@ \skvrobustdef*\skv@setquickkeys#1{\skv@testopt{\skv@setquickkeys@a{#1}}{}} \skvrobustdef*\skv@setquickkeys@a#1[#2]#3{% - \skvsavestate\skv@setquickkeys{\do\skv@qkeysna}\skv@setqkeysdepth + \skvsavestate\skv@setquickkeys{% + \do\skv@qkeysfam\do\skv@qkeysna\do\skv@qkeyskvlist + \do\skv@qkeyscurrnames + }\skv@setqkeysdepth \edef\skv@qkeysna{\unexpanded{#2}}% \skvcsvnormalize\skv@qkeysna - \edef\skv@tempa{\unexpanded{#3}}% - \skvkvnormalize\skv@tempa - \def\skv@setqkeys##1##2{% - \skvifcsdefTF{#1/##1/qkeys.cbk}{}{% - \skv@err{Key '#1/##1' is not defined}\@ehd + \edef\skv@qkeyskvlist{\unexpanded{#3}}% + \skvkvnormalize\skv@qkeyskvlist + \edef\skv@qkeysfam{\skvtrimspace{#1}}% + \def\skv@setqkeys@a##1##2{% + \skvifcsdefTF{\skv@qkeysfam/##1/qkeys.cbk}{}{% + \skv@err{Key '\skv@qkeysfam/##1' + \MessageBreak is not defined}\skv@ehd }% \skvifstrcmpTF{##2}\skv@novalue{% - \skvifcsdefTF{#1/##1/qkeys.def}{% - \skvcsletcs{#1/##1/qkeys.val}{#1/##1/qkeys.def}% + \skvifcsdefTF{\skv@qkeysfam/##1/qkeys.def}{% + \skvcsletcs{\skv@qkeysfam/##1/qkeys.val}{\skv@qkeysfam/##1/qkeys.def}% }{% \skv@err{No user value and no default - \MessageBreak for key '#1/##1'}\@ehd + \MessageBreak for key '\skv@qkeysfam/##1'}\skv@ehd }% }{% - \skvcsedef{#1/##1/qkeys.val}{\unexpanded{##2}}% + \skvcsedef{\skv@qkeysfam/##1/qkeys.val}{\unexpanded{##2}}% }% - \skvifcsdefTF{#1/##1/qkeys.chc}{% - \skvletcs\reserved@a{#1/##1/qkeys.chc}% - \edef\reserved@b{\skvexpandcsonce{#1/##1/qkeys.val}}% - \skvxifinTF{,\skvoxdetok\reserved@b,}{,\skvoxdetok\reserved@a,}{}{% + \skvletcs\skv@tempval{\skv@qkeysfam/##1/qkeys.val}% + \skvletcs\reserved@a{\skv@qkeysfam/##1/qkeys.chc}% + \skvifdefTF\reserved@a{% + \skvxifinTF{,\detokenize{##2},}{,\skvoxdetok\reserved@a,}{}{% \skv@err{Value '\detokenize{##2}' for key '##1' \MessageBreak is not in prescribed list - \MessageBreak '\skvoxdetok\reserved@a'}\@ehd + \MessageBreak '\skvoxdetok\reserved@a'}\skv@ehd }% }{}% - \skvifcsdefTF{#1/##1/qkeys.hp}{% - \skvletcs\reserved@a{#1/##1/qkeys.hp}% - \skvcsletcs{\reserved@a##1}{#1/##1/qkeys.val}% - }{}% - \skvifcsdefTF{#1/##1/qkeys.arg}{% - \skvletcs\reserved@a{#1/##1/qkeys.arg}% + \skvifcsdefTF{\skv@qkeysfam/##1/qkeys.arg}{% + \skvletcs\skv@argpattern{\skv@qkeysfam/##1/qkeys.arg}% }{% - \let\reserved@a\skv@simplearg + \let\skv@argpattern\skv@simplearg }% - \skvletcs\reserved@b{#1/##1/qkeys.cbk}% + \skvletcs\skv@callback{\skv@qkeysfam/##1/qkeys.cbk}% \expandafter\expandafter\expandafter\def\expandafter\expandafter - \expandafter\reserved@a\expandafter\reserved@a\expandafter - \quickkeyseov\expandafter{\reserved@b}% - \expandafter\expandafter\expandafter - \reserved@a\csname#1/##1/qkeys.val\endcsname\quickkeyseov + \expandafter\reserved@a\expandafter\skv@argpattern\expandafter + \quickkeyseov\expandafter{\skv@callback}% + \expandafter\reserved@a\skv@tempval\quickkeyseov }% - \def\skv@setquickkeys@c##1=##2=##3\skv@nil{% + \def\skv@setqkeys@b##1=##2=##3\skv@setqkeys@nil{% \skvxifinTF{,\detokenize{##1},}{,\skvoxdetok\skv@qkeysna,}{}{% - \skv@setqkeys{##1}{##2}% + \skv@setqkeys@a{##1}{##2}% + }% + }% + \skvifcsdefFT{\skv@qkeysfam/qkeys.preset}{}{% + \skv@qkeysgetkeynames\skv@qkeyskvlist\skv@qkeyscurrnames + \def\skv@setqkeys@c##1=##2=##3\skv@setqkeys@nil{% + \skvxifinTF{,\detokenize{##1},}{,\skvoxdetok\skv@qkeyscurrnames,}{}{% + \let\skv@setquickkeys@a\skv@bad@setquickkeys@a + \skv@setqkeys@b##1={##2}=##3\skv@setqkeys@nil + \let\skv@setquickkeys@a\skv@sav@setquickkeys@a + }% + }% + \skvletcs\skv@tempa{\skv@qkeysfam/qkeys.preset}% + \skvkvparse*\skv@tempa\skv@tempa{% + \expandafter\skv@setqkeys@c\skv@tempa=\skv@novalue=\skv@setqkeys@nil }% }% - \skvdolist*{,}\skv@tempa\skv@tempa{% - \expandafter\skv@setquickkeys@c\skv@tempa=\skv@novalue=\skv@nil + \skvkvparse*\skv@qkeyskvlist\skv@tempa{% + \expandafter\skv@setqkeys@b\skv@tempa=\skv@novalue=\skv@setqkeys@nil }% \skvrestorestate\skv@setquickkeys\skv@setqkeysdepth } +\skvnewlet\skv@sav@setquickkeys@a\skv@setquickkeys@a +\skvrobustdef*\skv@bad@setquickkeys@a{% + \skv@err{'\string\quickkeys.set' can't be nested in a preset + \MessageBreak key's callback: this will cause a cyclic call + \MessageBreak to '\string\quickkeys.set'}\skv@ehd +} % \skvinitializeqkeys{<fam>}[<na>]{<kvlist>} \skvrobustdef*\skvinitializeqkeys#1{% @@ -1980,6 +2346,12 @@ % {<no match>} % \endif % +% 1. \skvifcase is expandable but, to simplify the code, \elsedo is mandatory. +% See \ltsifcases of ltxtools package; it is expandable and the 'else part' +% can be omitted in it. +% 2. \skvifcasse and \skvifcases aren't expandable, but \elsedo isn't +% mandatory. +% % Example: % % \skvifcase\skvifstrcmpTF{c} @@ -1989,14 +2361,111 @@ % \elsedo % no match% % \endif +% +% \skvifcase is expandable. +% \skvnewdef\skvifcase#1#2#3\elsedo#4\endif{% + % {#2}{#4} represent default action: \skv@ifcase{#1}{#2}#3{#2}{#4}\skv@casestop } \skvnewdef\skv@ifcase#1#2#3{% - #1{#2}{#3}\skv@ifcase@domatch{\skv@ifcase@a{#1}{#2}}% + #1{#2}{#3}{% + \skv@ifcase@domatch + }{% + \skv@ifcase@a{#1}{#2}% + }% } \skvnewdef\skv@ifcase@a#1#2#3{\skv@ifcase{#1}{#2}} -\skvnewdef\skv@ifcase@domatch#1#2\skv@casestop{\unexpanded{#1}} +\skvnewdef\skv@ifcase@domatch#1#2\skv@casestop{\skvtrimspace{#1}} + +% \skvifcasse{<teststr>} +% {<cases>} +% \elsedo +% {<no match>} +% \endif +% +% 1. \elsedo can be omitted by the user, ie, it is optional. See also +% \skvifcases. +% 2. Because of the need to remove blank spaces before 'case', +% \skvifcasse isn't expandable. +% +% Example: +% +% \skvifcasse{x} +% case{a}{\def\x{do a}} +% case{b}{\def\x{do b}} +% case{c}{\def\x{do c}} +% \elsedo +% \def\x{no match} +% \endif +% +\skvrobustdef*\skvifcasse#1#2\endif{% + \skvxifinTF{\detokenize{\elsedo}}{\detokenize{#2}}{% + \begingroup + \def\skv@prova##1\elsedo##2\skv@ifcasse@nil{% + \endgroup + \skv@ifcasse@a{#1}##1case{#1}{##2}\skv@casse@stop + }% + \skv@prova#2\skv@ifcasse@nil + }{% + \skv@ifcasse@a{#1}#2case{#1}{}\skv@casse@stop + }% +} +\skvrobustdef*\skv@ifcasse@a#1{% + \@ifnextchar\relax{\skv@ifcasse@b#1}{\skv@ifcasse@b#1}% +} +\skvrobustdef*\skv@ifcasse@b#1case#2{% + \skvxifstrcmpTF{#1}{#2}{% + \skv@ifcasse@domatch + }{% + \skv@ifcasse@c{#1}% + }% +} +\skvrobustdef*\skv@ifcasse@c#1#2{\skv@ifcasse@a{#1}} +\skvrobustdef*\skv@ifcasse@domatch#1#2\skv@casse@stop{\skvtrimspace{#1}} + +% \skvifcases<teststr>\then +% <cases>{<acts>} +% <default>{<act>} +% \fi +% +% 1. <default>{<act>} can be omitted by the user, ie, it is optional. +% 2. \skvifcases isn't expandable. +% +% Example: +% \skvifcases x\then +% case{a}{\def\x{do a}} +% case{b}{\def\x{do b}} +% case{c}{\def\x{do c}} +% default{\def\x{no match}} +% \fi +% +\skvrobustdef*\skvifcases#1\then#2\fi{% + % Any space trailing #2 will be absorbed by ##3 of the following + % \skv@prova. + \begingroup + \def\skv@prova##1default##2##3\skv@ifcases@nil{% + \endgroup + \skvifstrcmpTF{##2}{\@nil}{% + \skv@ifcases@a{#1}##1case{#1}{}\skv@cases@stop + }{% + \skv@ifcases@a{#1}##1case{#1}{##2}\skv@cases@stop + }% + }% + \skv@prova#2default{\@nil}\skv@ifcases@nil +} +\skvrobustdef*\skv@ifcases@a#1{% + \@ifnextchar\relax{\skv@ifcases@b#1}{\skv@ifcases@b#1}% +} +\skvrobustdef*\skv@ifcases@b#1case#2{% + \skvxifstrcmpTF{#1}{#2}{% + \skv@ifcases@domatch + }{% + \skv@ifcases@c{#1}% + }% +} +\skvrobustdef*\skv@ifcases@c#1#2{\skv@ifcases@a{#1}} +\skvrobustdef*\skv@ifcases@domatch#1#2\skv@cases@stop{#1} % Evaluating a series of boolean expressions. % @@ -2092,17 +2561,18 @@ } \skvbuildmacrostack\skv@keystate{% - \do\skv@prefix\do\skvcurrentprefix\do\skv@fams\do\skvcurrentfamily + \do\skvcurrentprefix\do\skv@fams\do\skvcurrentfamily \do\skvcurrentkey\do\skv@header\do\skvcurrentpath\do\skv@na - \do\skv@naa\do\ifskv@st\do\ifskv@pl\do\ifskv@kf\do\ifskvnovalue + \do\skv@currentnames\do\ifskv@st\do\ifskv@pl\do\ifskv@kf\do\ifskvnovalue \do\skvcurrentvalue\do\CurrentOption\do\ifskv@intry\do\ifskv@success - \do\ifskv@inpox\do\ifskv@prepo + \do\ifskv@inpox\do\ifskv@inprepo\do\skv@pathdo\do\skv@rmkeys + \do\ifskv@viarootofsetkeys\do\skv@currpref\do\skv@currfam }\skv@stackdepthlimit \skvbuildmacrostack\skv@dirkeys@state{% - \do\dirkeys@prefixlist\do\dirkeys@familylist\do\dirkeys@holderprefixtoks + \do\dirkeys@pathlist\do\dirkeys@holderprefixtoks\do\dirkeys@parser \do\dirkeys@unknownkeysmacro\do\ifdirkeys@saveunknownkeys - \do\ifskvindirkeys\do\ifskvdfk@initialize\do\ifskvdfk@saveinitialvalues + \do\ifindirectkeys\do\ifskvdfk@initialize\do\ifskvdfk@saveinitialvalues }\skv@stackdepthlimit \skvrobustdef\skvappto#1#2{% @@ -2127,19 +2597,18 @@ }% }% }{% - \skv@err{Token '\detokenize{#3}' is not escaped}\@ehd + \skv@err{Token '\detokenize{#3}' is not escaped}\skv@ehd }% } -% \skvaddlist{<parser>}{<listitem>} -% This is usually called under \edef. +% \skvaddlist{<parser>}{<listcmd>} +% This is usually called under \edef. <listcmd> must have been +% initialized. \skvnewdef*\skvaddlist#1#2{% \skvifemptyTF#2{}{\skvexpandonce#2\unexpanded{#1}}% } % \skvxaddtolist{<parser>}{<listcmd>}{<newitem>} -\skvrobustdef\skvxaddtolist#1#2#3{% - \edef#2{#2\ifx#2\@empty\else#1\fi#3}% -} +\skvrobustdef\skvxaddtolist#1#2#3{\edef#2{\skvaddlist#1#2#3}} % \skvaddtolist[<parser>]{<listcmd>}{<newitem>} \skvrobustdef*\skvaddtolist{\skv@teststopt{\skv@addtolist{}},} \skvrobustdef*\skvgaddtolist{\skv@teststopt{\skv@addtolist{\global}},} @@ -2164,53 +2633,73 @@ }% } -% \skvfiltermergelist!<cmd>{<sublist>}<filter> -% The exclamation mark (!) implies that the outcome is globalized. -% When there is no filter to be applied, \skvmergelist is faster -% than \skvfiltermergelist. -\skvrobustdef*\skvfiltermergelist{\skv@testcl\skv@filtermergelist} -\skvrobustdef*\skv@filtermergelist#1#2#3{% +% \skvfiltermergelist![<parser>](<wrapper>)<cmd>{<sublist>}<filter> +% +% 1. The exclamation mark (!) implies that the outcome is globalized. +% 2. When there is no filter to be applied, \skvmergelist is faster +% than \skvfiltermergelist. +% 3. <wrapper> will be applied to all the elements (new and old). +% The default value of <wrapper> is \skvexpandonce. +% 4. Example: +% \def\alist{a;b;c} +% \def\wrap#1{{#1}} +% \skvfiltermergelist[;](\wrap)\alist{a;d;e}\nofilter +% \show\alist +% +\skvrobustdef*\skvfiltermergelist{% + \skv@testcl{\skv@testopt\skv@filtermergelist,}% +} +\skvrobustdef*\skv@filtermergelist[#1]{% + \skv@testpnopt{\skv@f@ltermergelist{#1}}\skvexpandonce +} +\skvrobustdef*\skv@f@ltermergelist#1(#2)#3#4#5{% \begingroup - \skv@declarefilter{#3}% - \skvifdefTF#1{\skvkvnormalize#1}{\def#1{}}% - \edef\skv@merga{\unexpanded{#2}}% - \skvkvnormalize\skv@merga - \skvcommaloop*\skv@merga\skv@merga{% + \skv@declarefilter{#5}% + \skvifdefTF#3{\skvcsvnormalize[#1]#3}{\def#3{}}% + \edef\skv@merga{\unexpanded{#4}}% + \skvcsvnormalize[#1]\skv@merga + \skvdolist*{#1}\skv@merga\skv@merga{% \@tempswatrue \skv@filter\skv@merga\skv@mergb - \let\skv@mergc#1% - \let#1\@empty - \skvcommaloop*\skv@mergc\skv@mergc{% + \let\skv@mergc#3% + \let#3\@empty + \skvdolist*{#1}\skv@mergc\skv@mergc{% \skv@filter\skv@mergc\skv@mergd \ifx\skv@mergb\skv@mergd \@tempswafalse - \edef#1{\skvaddlist,#1\skvexpandonce\skv@merga}% + \edef#3{\skvaddlist#1#3#2{\skv@merga}}% \else - \edef#1{\skvaddlist,#1\skvexpandonce\skv@mergc}% + \edef#3{\skvaddlist#1#3#2{\skv@mergc}}% \fi }% \if@tempswa - \edef#1{\skvaddlist,#1\skvexpandonce\skv@merga}% + \edef#3{\skvaddlist#1#3#2{\skv@merga}}% \fi }% - \skvaftergroupdef#1\endgroup - \ifskv@cl\global\let#1#1\fi + \skvaftergroupdef#3\endgroup + \ifskv@cl\global\let#3#3\fi } -% \skvmergelist!<cmd>{<sublist>} -% The exclamation mark (!) implies that the outcome is globalized. -\skvrobustdef*\skvmergelist{\skv@testcl\skv@mergelist} -\skvrobustdef*\skv@mergelist#1#2{% +% \skvmergelist![<parser>](<wrapper>)<cmd>{<sublist>} +% +% 1. The exclamation mark (!) implies that the outcome is globalized. +% 2. <wrapper> will be applied to only the new elements. The default +% value of <wrapper> is \skvexpandonce. +\skvrobustdef*\skvmergelist{\skv@testcl{\skv@testopt\skv@mergelist,}} +\skvrobustdef*\skv@mergelist[#1]{% + \skv@testpnopt{\skv@m@rgelist{#1}}\skvexpandonce +} +\skvrobustdef*\skv@m@rgelist#1(#2)#3#4{% \begingroup - \skvifdefTF#1{\skvkvnormalize#1}{\def#1{}}% - \edef\skv@tempa{\unexpanded{#2}}% - \skvkvnormalize\skv@tempa - \skvcommaloop*\skv@tempa\skv@tempa{% - \skvxifinTF{,\skvoxdetok\skv@tempa,}{,\skvoxdetok#1,}{}{% - \edef#1{\skvaddlist,#1\skvexpandonce\skv@tempa}% + \skvifdefTF#3{\skvcsvnormalize[#1]#3}{\def#3{}}% + \edef\skv@tempa{\unexpanded{#4}}% + \skvcsvnormalize[#1]\skv@tempa + \skvdolist*{#1}\skv@tempa\skv@tempa{% + \skvxifinTF{#1\skvoxdetok\skv@tempa#1}{#1\skvoxdetok#3#1}{}{% + \edef#3{\skvaddlist#1#3#2{\skv@tempa}}% }% }% - \skvaftergroupdef#1\endgroup - \ifskv@cl\global\let#1#1\fi + \skvaftergroupdef#3\endgroup + \ifskv@cl\global\let#3#3\fi } % \skvfilterremoveelements!<cmd>{<sublist>}<filter> @@ -2278,15 +2767,20 @@ } % \skvfilterreplaceelements!<listcmd>{<replacements>}<filter> +% % <replacements> => {<old-1>}{<new-1>},...,{<old-n>}{<new-n>} +% % An exclamation mark suffix (!) implies that the outcome is globalized. % When there is no filter to be applied, \skvreplaceelements is only % negligibly faster than \skvfilterreplaceelements. Hence \skvreplaceelements % isn't defined in this package. When there is no <filter>, use \nofilter % as the filter. +% % Example: +% % \def\cmd{a = 1 , b = 2 , c = 3} % \skvfilterreplaceelements\cmd{{a = 1}{x = 1},{c = 3}{z=3}}\skv@getkeyname +% \skvrobustdef*\skvfilterreplaceelements{% \skv@testcl\skv@filterreplaceelements } @@ -2322,44 +2816,61 @@ \skvaftergroupdef#1\endgroup \ifskv@cl\global\let#1#1\fi } +\skvnewdef*\skvcurrentfullkey{\skv@header\skvcurrentkey} +\skvnewlet\skvcurrenttriple\skvcurrentfullkey +\skvrobustdef*\skvsetdefaultprefix#1{% + \edef\skvdefaultprefix{\skvtrimspace{#1}}% + \let\skv@defapf\skvdefaultprefix +} +\skvsetdefaultprefix{KV} \skvrobustdef*\skv@makeprefix#1{% % It is required to first fully expand the prefix: \edef\skvcurrentprefix{#1}% \skvdespacecontent\skvcurrentprefix - \edef\skv@prefix{% - \ifx\skvcurrentprefix\@empty\else\skvcurrentprefix/\fi - }% } +% \skv@makeheader{<family>} \skvrobustdef*\skv@makeheader#1{% % Fully expand the family, in case it is given as \skvcurrentfamily or % a local/temporary macro: \edef\skvcurrentfamily{#1}% \skvdespacecontent\skvcurrentfamily - \edef\skvcurrentpath{\skv@prefix\skvcurrentfamily}% + \ifx\skvcurrentprefix\@undefined + \let\skvcurrentprefix\skvdefaultprefix + \fi \edef\skv@header{% - \skv@prefix\ifx\skvcurrentfamily\@empty\else\skvcurrentfamily/\fi + \ifx\skvcurrentprefix\@empty\else\skvcurrentprefix/\fi + \ifx\skvcurrentfamily\@empty\else\skvcurrentfamily/\fi }% + \ifx\skv@header\@empty + \def\skv@header{/}% + \let\skvcurrentpath\skv@header + \else + \def\reserved@a##1/\@nil{##1}% + \edef\skvcurrentpath{\expandafter\reserved@a\skv@header\@nil}% + \ifx\skvcurrentpath\@empty + \def\skvcurrentpath{/}% + \fi + \fi } -\skvrobustdef*\skvdefaultprefix#1{\edef\skv@defaultpref{#1}} -\skvdefaultprefix{KV} \skvrobustdef*\skv@testopta#1{% \skvifstar - {\skv@sttrue\skv@t@stopta{#1}}{\skv@stfalse\skv@t@stopta{#1}}% + {\skv@sttrue\skv@t@stopta{#1}} + {\skv@stfalse\skv@t@stopta{#1}}% } \skvrobustdef*\skv@t@stopta#1{\skvifplus{\skv@pltrue#1}{\skv@plfalse#1}} \skvrobustdef*\skv@testoptb#1{% - \skv@testopt{\skv@t@stoptb{#1}}\skv@defaultpref + \skv@testopt{\skv@t@stoptb{#1}}\skvdefaultprefix } \skvrobustdef*\skv@t@stoptb#1[#2]#3{% \skv@makeprefix{#2}\skv@makeheader{#3}#1% } \skvrobustdef*\skv@testoptc#1{% - \skv@testopt{\skv@t@stoptc{#1}}\skv@defaultpref + \skv@testopt{\skv@t@stoptc{#1}}\skvdefaultprefix } \skvrobustdef*\skv@t@stoptc#1[#2]#3{% \skvxifinTF{,}{\detokenize{#2}}{% \skv@err{Only one prefix is allowed here, - \MessageBreak but you gave '#2'}\@ehd + \MessageBreak but you gave '#2'}\skv@ehd }{% \skv@makeprefix{#2}% \edef\skv@fams{#3}% @@ -2384,43 +2895,51 @@ \skvifnextchar[{\skv@sttrue#1{#2}{#3}}{\skv@stfalse#1{#2}{#3}[]}% } \skvrobustdef*\skv@getkeyname#1#2{% - \expandafter\skv@g@tkeyname#1=\skv@nil#2% + \expandafter\skv@g@tkeyname#1=\skv@getname@nil#2% } -\skvrobustdef*\skv@g@tkeyname#1=#2\skv@nil#3{% - \skv@strippointers{#1}\skvcurrentkey +\skvrobustdef*\skv@g@tkeyname#1=#2\skv@getname@nil#3{% + \skv@strippointersfromkey{#1}% \let#3=\skvcurrentkey } - -% #1=key-value pairs; #2=result macro -\skvrobustdef*\skv@getkeynames#1#2{% +\skvrobustdef*\skv@getkeyvalue#1#2{% + \expandafter\skv@g@tkeyvalue#1==\skv@getvalue@nil#2% +} +\skvrobustdef*\skv@g@tkeyvalue#1={\skv@g@tk@yvalue#1=.} +\skvrobustdef*\skv@g@tk@yvalue#1=#2=#3\skv@getvalue@nil#4{% + \edef#4{\unexpanded\expandafter{\@gobble#2}}% + \skvexpbracenext\skvifbracedTF#4{% + \skvvaluebracedtrue + }{% + \skvvaluebracedfalse + \skvexpbracenext\skv@strippointersfromvalue#4% + }% + \let#4=\skvcurrentvalue +} +% \skv@getnamesofkeys{<kv list>}{<result macro>} +\skvrobustdef*\skv@getnamesofkeys#1#2{% \begingroup \edef\skv@prova{\unexpanded{#1}}% \skvkvnormalize\skv@prova \let#2\@empty \skvcommaloop*\skv@prova\skv@prova{% - \expandafter\expandafter\expandafter - \skv@g@tkeyname\skv@prova=\skv@nil\skv@prova - \skvaddtolist*#2\skv@prova + \expandafter\skv@g@tkeyname\skv@prova=\skv@getname@nil\skv@prova + \edef#2{\skvaddlist,#2\skvexpandonce\skv@prova}% }% \skvaftergroupdef#2\endgroup } \skvnewdef*\skv@badkeynames{} \skvnewdef*\skvaddbadkeynames{\skvappendtomacro\skv@badkeynames} -\skvnewdef\skvcurrenttriple{% - \skvcurrentprefix/\skvcurrentfamily/\skvcurrentkey -} \skvrobustdef*\skv@definedefault#1#2{% \ifskv@inoptionsec\else \skvxifinTF{,\skvcurrentprefix,}{,skv,SKV,}{% \skvxifinTF{,\skvcurrentfamily,}{,skeyval,}{% - \skv@err{Prefix/family '\skvcurrentprefix/\skvcurrentfamily' - are reserved}\@ehd + \skv@err{Prefix/family '\skvcurrentpath' are reserved}\skv@ehd }{}% }{}% \fi \ifskv@tracingkeys \skvxifinTF{,#1,}{,\skv@badkeynames,}{% - \skv@err{Key name '#1' not allowed}\@ehd + \skv@err{Key name '#1' not allowed}\skv@ehd }{}% \fi \skvcsedef{\skv@header#1.@defa}{% @@ -2444,102 +2963,173 @@ % create 'needini' lists of families. \skvrobustdef*\skv@recordkey#1#2{% \begingroup - \skvifcsdefFT{\skv@header.@needini}{% + \skvifcsdefFT{\skvcurrentpath.@needini}{% \endgroup\skv@swafalse }{% \skv@swatrue - \skvxifinTF{,#1,}{,\skvexpandcsonce{\skv@header.@needini},}{% + \skvxifinTF{,#1,}{,\skvexpandcsonce{\skvcurrentpath.@needini},}{% \edef\skv@tempa{\skvtrimspace{#2}}% \edef\skv@tempa{% #1=\skvoifstrcmpTF{\skv@tempa}{true}{false}{\skvexpandonce\skv@tempa}% }% - \skvletcs\skv@tempb{\skv@header.@inikv}% + \skvletcs\skv@tempb{\skvcurrentpath.@inikv}% \skvifdefTF\skv@tempb{% \skvxifinTF{,\skvoxdetok\skv@tempa,}{,\skvoxdetok\skv@tempb,}{}{% - \skvcsedef{\skv@header.@inikv}{% + \skvcsedef{\skvcurrentpath.@inikv}{% \skvaddlist,\skv@tempb\skvexpandonce\skv@tempa }% }% }{% - \skvcsedef{\skv@header.@inikv}{\skvexpandonce\skv@tempa}% + \skvcsedef{\skvcurrentpath.@inikv}{\skvexpandonce\skv@tempa}% }% }{}% }% \ifskv@swa \expandafter\skvaftergroupdef\csname - \skv@header.@inikv\expandafter\endcsname + \skvcurrentpath.@inikv\expandafter\endcsname \expandafter\endgroup \fi } % Key will be given in the form <pointer>{<key>}. The command -% \skv@strippointers is called both when defining and setting keys. When -% setting keys, we also call \skv@replacepointers to replace .usevalue -% pointer with the value of the key. +% \skv@strippointersfromkey is called both when defining and setting keys. % % Notes: -% 1. The pointer \savevalue (of ltxkeys package) or .save value is -% not used in the skeyval package, since the key's value is +% 1. When setting keys, we also call \skv@replacepointers to replace +% '.use value' pointer with the value of the key. +% 2. There is no pointer '.save value', since the key's value is % always saved automatically. % -\skvrobustdef*\skv@strippointers#1#2{% +% \skv@strippointersfromkey{<key name>} +% \skv@strippointersfromkey*{<key name cmd>} +% +% Return \skvcurrentkey. +% +\skvrobustdef*\skv@strippointersfromkey{% + \skv@i@testst\skv@str@ppointersfromkey +} +\skvrobustdef*\skv@str@ppointersfromkey#1{% \begingroup - \edef#2{% - \skvifstrcmpTF{#1}{\skvcurrentkey} - {\skvcurrentkey}{\skvtrimspace{#1}}% - }% - \def\skv@prova{\expandafter\skv@findpointer\expandafter}% - % We can't use #1 in place of #2 in the following, since - % #2 may have had some pointers stripped in the last call - % to \skv@findpointer. Also, we can't \edef #2 here, since - % after each call to \skv@findpointer, we want to use the latest - % meaning of #2. - \def\do{}% - \def\skv@add##1{% - \edef\do{\skvexpandonce\do\unexpanded{##1}}% - }% - \skv@prova{#2}{.need value}#2{% - \skv@add{\skvcsdef{\skv@header#2.@ndv}{00}}% - }{% - \skv@prova{#2}{.forbid value}#2{% - \skv@add{\skvcsdef{\skv@header#2.@fbv}{00}}% + \toks@{}% + \skv@usetempst{#1}\skv@tempa + % We can choose to ignore the search for pointers where we don't + % use pointers. This is useful at least in one respect: during debugging + % in non-pointer circumstances. In general, it is not advisable to ignore + % pointers. + \ifskv@ignorepointers\else + \def\skv@tempb{\expandafter\skv@findpointer\expandafter{\skv@tempa}}% + \def\skv@add##1{\edef\x{\toks@{\the\toks@##1}}\x}% + \skv@tempb{.need value}\skv@tempa{% + \skv@add{\skvcsdef{\skv@header\skv@tempa.@ndv}{}}% }{% - \skv@prova{#2}{.expanded}#2{% - \edef#2{#2}% + \skv@tempb{.gneed value}\skv@tempa{% + \skv@add{\skvcsgdef{\skv@header\skv@tempa.@ndv}{}}% }{% - \skv@prova{#2}{.expand once}#2{% - \edef#2{\skvexpandtwice{#2}}% + \skv@tempb{.forbid value}\skv@tempa{% + \skv@add{\skvcsdef{\skv@header\skv@tempa.@fbv}{}}% }{% - \skv@prova{#2}{.expand twice}#2{% - \edef#2{\skvexpandthrice{#2}}% + \skv@tempb{.gforbid value}\skv@tempa{% + \skv@add{\skvcsgdef{\skv@header\skv@tempa.@fbv}{}}% }{}% }% }% }% + \fi + \skvexpanded{\endgroup + \the\toks@ + % The following complication is because of, e.g., pntkeys: + \edef\noexpand\skvcurrentkey{% + \noexpand\unexpanded{\skvexpandonce\skv@tempa}% + }% }% - \skvexpanded{\endgroup\skvcmdexit#2\do}% } -\skvrobustdef*\skv@findpointer#1#2#3{% +% \skv@strippointersfromvalue{<key value>} +% \skv@strippointersfromvalue*{<key value cmd>} +% +% Return \skvcurrentvalue. +% +\skvrobustdef*\skv@strippointersfromvalue{% + \skv@i@testst\skv@str@ppointersfromvalue +} +\skvrobustdef*\skv@str@ppointersfromvalue#1{% \begingroup - \def\skv@prova##1#2##2##3\pointer@nil{% - \endgroup + \skv@usetempst{#1}\skv@tempa + \ifskv@ignorepointers\else + \def\skv@tempb{\expandafter\skv@findpointer\expandafter{\skv@tempa}}% + % The following order is important, since '.expand' will match + % '.expand once' and erroneously give the key's value as 'o'. + \skv@tempb{.expand once process list}\skv@tempa{% + \skv@processvalueaslisttrue + \edef\skv@tempa{\skvexpandtwice\skv@tempa}% + }{% + \skv@tempb{.expand twice process list}\skv@tempa{% + \skv@processvalueaslisttrue + \edef\skv@tempa{\skvexpandthrice\skv@tempa}% + }{% + \skv@tempb{.expand process list}\skv@tempa{% + \skv@processvalueaslisttrue + \edef\skv@tempa{\skv@tempa}% + }{% + \skv@tempb{.eprocess list}\skv@tempa{% + \skv@processvalueaslisttrue + \edef\skv@tempa{\skv@tempa}% + }{% + \skv@tempb{.process list}\skv@tempa{% + \skv@processvalueaslisttrue + }{% + \skv@tempb{.expand once}\skv@tempa{% + \edef\skv@tempa{\skvexpandtwice\skv@tempa}% + }{% + \skv@tempb{.expand twice}\skv@tempa{% + \edef\skv@tempa{\skvexpandthrice\skv@tempa}% + }{% + \skv@tempb{.expanded}\skv@tempa{% + \edef\skv@tempa{\skv@tempa}% + }{% + \skv@tempb{.expand}\skv@tempa{% + \edef\skv@tempa{\skv@tempa}% + }{}% + }% + }% + }% + }% + }% + }% + }% + }% + \fi + \let\skvcurrentvalue\skv@tempa + \skvexpanded{\endgroup + \skvcmdexit\skvcurrentvalue + \skvboolexit\ifskv@processvalueaslist + }% +} +\skvrobustdef*\skv@findpointer#1#2#3{% + \def\skv@f@ndpointer##1#2##2##3\skv@pointer@nil{% \skvifstrcmpTF{##2}{\skv@nil}{% \@secondoftwo }{% - \skviflacus##1\then\else + % We don't want, eg, '<tokens>.expanded{value}', since in this case + % applying \edef to the value macro may be unsafe on <tokens>: + \skvifblankTF{##1}{}{% \skv@err{Nothing should come before the - \MessageBreak pointer '#2' on key '##2'}\@ehd - \fi + \MessageBreak pointer '#2' on key '##2'. + \MessageBreak If you require the value of the key to be expanded, + \MessageBreak you should have done the expansion yourself}\skv@ehd + }% \edef#3{\skvtrimspace{##2}}% \@firstoftwo }% }% - \skv@prova#1#2{\skv@nil}\pointer@nil + \skv@f@ndpointer#1#2{\skv@nil}\skv@pointer@nil } - -% Extract pseudo key name from a weird key name of the form -% 'evaluate (\x) as (\y) using (\numexpr\x*2)': -\skvrobustdef*\skv@extractpntkey#1#2{% +% \skv@extractpntkey@atdefkey{<toks>}{<cmd>} +% +% At define key, extract pseudo key name from a weird key name of the form +% +% evaluate (?) as (?) using (?) +% +\skvrobustdef*\skv@extractpntkey@atdefkey#1#2{% \begingroup \@tempcnta\skvz@ \def#2{}% @@ -2552,44 +3142,44 @@ \fi }% \skv@prova#1(\@nil)% - \in@false \ifx#2\@empty \edef#2{\unexpanded{#1}}% \else - \skvifstreq{#2}{\skvcurrentkey}\then - \in@true - % The number of arguments of the pseudo key is determined by the - % number of closed parentheses: - \skvcsedef{\skv@header#2.@x0arg}{% - \skvgenerateparameters{1}\@tempcnta - }% - \fi + % The number of arguments of the pseudo key is determined by the + % number of closed parentheses: + \skvcsedef{\skv@header#2.@x0arg}{\skvgenerateparameters{1}\@tempcnta}% \fi \skvexpanded{\endgroup \skvcmdexit#2% - \ifin@ - \expandafter\skvcmdexit\csname\skv@header#2.@x0arg\endcsname - \fi + \skvcsexit{\skv@header#2.@x0arg}% }% } -\skvrobustdef*\skv@extr@ctpntkey#1#2#3{% +% \skv@extractpntkey@atsetkey{<toks>} +% +% At set key, extract pseudo key name from a weird key name of the form +% +% evaluate (?) as (?) using (?) +% +\skvrobustdef*\skv@extractpntkey@atsetkey#1{% \begingroup - \let\skv@tvalue#3% - \def#2{}\def#3{}% + \def\skvcurrentkey{}% + \def\skvcurrentvalue{}% \def\skv@prova##1(##2){% \def\skv@provb{##2}% \ifx\skv@provb\@nnil\else - \edef#2{\skvexpandonce#2\skvtrimspace{##1}}% - \edef#3{\skvexpandonce#3{\skvtrimspace{##2}}}% + \edef\skvcurrentkey{\skvxonce\skvcurrentkey\skvtrimspace{##1}}% + \edef\skvcurrentvalue{\skvxonce\skvcurrentvalue{\skvtrimspace{##2}}}% \expandafter\skv@prova \fi }% \skv@prova#1(\@nil)% - \ifx#2\@empty - \edef#2{\unexpanded{#1}}% - \let#3\skv@tvalue + \ifx\skvcurrentkey\@empty + \skv@err{No key name for a parenthesized key}\skv@ehd + \expandafter\@nodocument \fi - \skvexpanded{\endgroup\skvcmdexit#2\skvcmdexit#3}% + \skvexpanded{\endgroup + \skvcmdexit\skvcurrentkey\skvcmdexit\skvcurrentvalue + }% } \skvrobustdef*\skv@replacepointers#1{% \begingroup @@ -2602,33 +3192,30 @@ }% \skvaftergroupdef\skvcurrentvalue\endgroup } -% In xkeyval package, if we put, eg, +% In the following scheme, if we have, eg, % -% key2=\dimexpr\usevalue{key1}*5\relax +% key2=\dimexpr.use value{key1}*5\relax % -% \dimexpr will be lost (as part of the value of key2) in pointer -% replacement. We avoid that deficiency here. +% \dimexpr will be retained as part of the value of key2 in pointer +% replacement. % \skvrobustdef*\skv@r@placepointers#1.use value#2{% + % In case #1 isn't empty: + \edef\skvcurrentvalue{\skvexpandonce\skvcurrentvalue\unexpanded{#1}}% \edef\skv@prova{\unexpanded{#2}}% - \skvifxTF\skv@prova\skv@nnil{% - \edef\skvcurrentvalue{\unexpanded{#1}}% - }{% + \skvifxTF\skv@prova\skv@nnil{}{% \skvifcsdefFT{\skv@header#2.@value}{% - \skv@err{No value recorded for key '#2'; ignored}\@ehd + \skv@err{No value recorded for key '#2'; ignored}\skv@ehd \skv@r@placepointers }{% \skvxifinTF{,\detokenize{#2},}{,\skvoxdetok\skv@tempa,}{% \skv@err{Back linking of pointers; - \MessageBreak pointer replacement canceled}\@ehd + \MessageBreak pointer replacement canceled}\skv@ehd }{% \edef\skv@tempa{\skvaddlist,\skv@tempa\unexpanded{#2}}% - \edef\skv@prova{\skvexpandcsonce{\skv@header#2.@value}}% - \skvexpandbracenext\skvifbracedTF\skv@prova{% - \skvexpandbracenext{\skv@r@placepointers#1}\skv@prova - }{% - \skvexpandnext{\skv@r@placepointers#1}\skv@prova - }% + \skvletcs\skv@prova{\skv@header#2.@value}% + \skvexpbracenext\skvifbracedTF\skv@prova\skvexpbracenext\skvexpandnext + \skv@r@placepointers\skv@prova }% }% }% @@ -2638,9 +3225,7 @@ % % \skvassignargs[<prefixes>]{<families>}[<expansion.type>]{<keys>}{<arg>} % -% 1. Valid expansion types are x0 (unexpanded), x1 (expand once), -% x2 (expand twice), xx (expand fully). The default expansion type is -% x0 (unexpanded). +% 1. Valid expansion types are .expand once, .expand twice, .expanded. % 2. At set keys (not at define keys), the argument to the listed keys will % be expanded using the expansion type. % 3. The argument will be assigned whether or not a key already has been @@ -2651,74 +3236,202 @@ % % Example: % -% \skvassignargs[KV1,KV2]{fam1,fam2}[x1]{keya,keyb}{#1/#2} +% \skvassignargs[KV1,KV2]{fam1,fam2}[.expand once]{keya,keyb}{#1/#2} +% +% The keys could then be set as +% % \skvsetkeys[KV1]{fam2}{keya=vala/valb} % % For each prefix and family, this will define parameterless functions % -% \<prefix>/<family>/key/.@x1arg. +% \<prefix>/<family>/<key>.@x1arg. % % which will be used at setkeys to define and execute the key's callback. % -\skvrobustdef*\skvassignargs{\skv@testopt\skv@assignargs\skv@defaultpref} +\skvrobustdef*\skvassignargs{\skv@testopt\skv@assignargs\skvdefaultprefix} \skvrobustdef*\skv@assignargs[#1]#2{% \begingroup \skv@testopt{\skv@assignargs@a{#1}{#2}}{^skv^}% } \skvrobustdef*\skv@assignargs@a#1#2[#3]#4#5{% - \edef\skv@tempc{\skvtrimspace{#5}}% - \def\skv@tempd{}% + \edef\skv@tempb{\skvtrimspace{#5}}% + \def\skv@tempc{}% \skvifstrcmpTF{#3}{^skv^}{% \def\skvexpander{x0}% }{% - \skv@checkexpander{#3}% - \edef\skvexpander{\skvtrimspace{#3}}% + \skv@getexpander@a{#3}\skvexpander }% - \def\\{\noexpand\unexpanded}% - \skvcommaloop{#1}\skv@tempa{% + \skvcommaparse{#1}\skv@tempa{% \skv@makeprefix\skv@tempa - \skvcommaloop{#2}\skv@tempa{% + \skvcommaparse{#2}\skv@tempa{% \skv@makeheader\skv@tempa \skvcommaparse{#4}\skv@tempa{% - \edef\skv@tempd{\skvexpandonce\skv@tempd + \edef\skv@tempc{% + \skvexpandonce\skv@tempc \skvcsedef{\skv@header\skv@tempa.@\skvexpander arg}{% - \\{\\{\skvexpandonce\skv@tempc}}% + \noexpand\unexpanded{\skvexpandonce\skv@tempb}% }% }% }% }% }% - \skvexpanded{\endgroup\skv@tempd}% + \expandafter\endgroup\skv@tempc } -\skvrobustdef*\skv@checkexpander#1{% - \skvxifinTF{,\expandafter\skvtrimspace\expandafter - {\detokenize\expandafter{#1}},}{,\detokenize{x0,x1,x2,xx},}{}{% - \skv@err{Illegal expansion type '#1'}\@ehd + +% \skv@getexpander@a{<expander.type>}{<return.cmd>} +% +% 1. <return.cmd> will contain one of 'x0', 'x1', 'x2', 'xx', which will be +% saved in a key-dependent macro that represents the key's argument. +% +\skvrobustdef*\skv@getexpander@a#1#2{% + \begingroup + \edef\skv@prova{\skvotrimspace{#1}}% + \def\skv@provb##1{% + \def\skv@provb####1##1####2####3\skv@nil{% + \endgroup + \def#2{####2}% + \ifx#2\@nnil + \skv@err{Unknown expansion type '\detokenize{##1}'}\skv@ehd + \fi + }% + \skv@provb .expand once{x1},.expand twice{x2},.expanded{xx},% + .expand{xx},##1{\@nil}\skv@nil }% + \expandafter\skv@provb\expandafter{\skv@prova}% } - -% Ordinary keys: +% \skv@getexpander@b{<expander.type>} +% +% 1. <expander.type> is one of 'x0', 'x1', 'x2', 'xx', which had been +% saved in a key-dependent macro. +% +% 2. \skv@getexpander@b returns macro \skvexpander, which will +% contain one of \unexpanded, \skvexpandonce, \skvexpandtwice, \@iden. +% +\skvrobustdef*\skv@getexpander@b#1{% + \begingroup + \edef\skv@prova{\skvtrimspace{#1}}% + \def\skv@provb##1{% + \def\skv@provb####1##1####2####3\skv@nil{% + \endgroup + \def\skvexpander{####2}% + \ifx\skvexpander\@nnil + \skv@err{Unknown expansion type '\detokenize{##1}'}\skv@ehd + \fi + }% + \skv@provb x0{\unexpanded},x1{\skvexpandonce},x2{\skvexpandtwice},% + xx{\@iden},##1{\@nil}\skv@nil + }% + \expandafter\skv@provb\expandafter{\skv@prova}% +} +% \skv@getargpattern{<callback token list>} +% +% Get argument type from the key's callback. The valid tags are +% +% .arg, .arg unexpanded, .arg expanded, .arg expand, .arg expand once, +% .arg expand twice. +% +\skvrobustdef*\skv@getargpattern{% + \let\skv@argpattern\@undefined + \def\do##1##2{% + \ifx\do##1\else + \skvxifinTF{\detokenize{##1}}{\skvoxdetok\skv@callback}{% + \def\skv@prova####1##1####2####3\skv@argpattern@nil{% + \edef\skv@argpattern{\unexpanded{####2}}% + \ifx\skv@argpattern\@empty + \let\skv@argpattern\skv@simplearg + \fi + \edef\skv@callback{\skvtrimspace{####1}\skvtrimspace{####3}}% + }% + \expandafter\skv@prova\skv@callback\skv@argpattern@nil + \def\skvexpandertype{##2}% + \def\do####1\do\do{}% + }{}% + \expandafter\do + \fi + }% + % The following order is important, to avoid incorrect match + % of the search term: + \do{.arg unexpanded}{x0}{.arg expand once}{x1}{.arg expand twice}{x2}% + {.arg expanded}{xx}{.arg expand}{xx}{.arg}{x0}\do\do + \ifdefined\skv@argpattern\else + % Argument pattern might have been specified outside the key's + % callback. + \def\do##1{% + \ifx\do##1\else + \skvifnamedefTF{\skvcurrentfullkey.@##1arg}{% + \skvletcs\skv@argpattern{\skvcurrentfullkey.@##1arg}% + \def\skvexpandertype{##1}% + \def\do####1\do{}% + }{}% + \expandafter\do + \fi + }% + \do{xx}{x2}{x1}{x0}\do + \fi + \ifdefined\skv@argpattern + % Possibly expand value: + \skvstripouterbraces{2}\skv@argpattern + \def\do##1##2{% + \ifx\do##1\else + \skvxifstrcmpTF{##2}\skvexpandertype{% + \edef\skvcurrentvalue{% + \expandafter##1\expandafter{\skvcurrentvalue}% + }% + \def\do####1\do\do{}% + }{}% + \expandafter\do + \fi + }% + \do\@iden{xx}\skvexpandtwice{x2}\skvexpandonce{x1}\unexpanded{x0}\do\do + \else + \let\skv@argpattern\skv@simplearg + \fi +} +% +++++++++++++ Ordinary keys: % % \skvordkey[<pref>]{<fam>}{<key>}[<defa>]{<callback>} % -\skvrobustdef*\skvordkey{\skv@testoptb\skv@ordkey} -\skvrobustdef*\skv@ordkey#1{% - \skv@strippointers{#1}\skvcurrentkey - \skvexpanded{\skv@testopt{\skv@ordkey@a{\skvcurrentkey}}{^skv^}}% +\skvrobustdef*\skvordkey{\skv@testoptb{\skv@ordkey{e}}} +\skvrobustdef*\skvordkeys{\skv@testoptb{\skv@ordkeys{e}}} +% +% \skvgordkey[<pref>]{<fam>}{<key>}[<defa>]{<callback>} +% +% Global ordinary keys. So far, these are needed only by \skvgdisablekey. +% +\skvrobustdef*\skvgordkey{\skv@testoptb{\skv@ordkey{x}}} +\skvrobustdef*\skvgordkeys{\skv@testoptb{\skv@ordkeys{x}}} +\skvrobustdef*\skv@ordkey#1#2{% + \skv@strippointersfromkey{#2}% + \skvexpanded{\skv@testopt{\skv@ordkey@a{#1}{\skvcurrentkey}}{^skv^}}% } -\skvrobustdef*\skv@ordkey@a#1[#2]#3{% - \skvifstrcmpTF{#2}{^skv^}{}{\skv@definedefault{#1}{#2}}% - \skvcsedef{\skv@header#1.@cbk}{\unexpanded{#3}}% +\skvrobustdef*\skv@ordkey@a#1#2[#3]#4{% + \skvifstrcmpTF{#3}{^skv^}{}{\skv@definedefault{#2}{#3}}% + % The pointer '.hp' may be used to set a holder prefix for the key. + \skvxifinTF{\detokenize{.hp}}{\detokenize{#4}}{% + \def\skv@prova##1.hp##2##3\skv@ord@nil{% + \let\skv@gobble@or@iden\@iden + \edef\skv@hp{\unexpanded{##2}}% + \edef\skv@callback{\unexpanded{##1##3}}% + }% + \skv@prova#4\skv@ord@nil + }{% + \let\skv@gobble@or@iden\@gobble + \edef\skv@callback{\unexpanded{#4}}% + }% + \csname skvcs#1def\endcsname{\skv@header#2.@cbk}{% + % This can be called in #3 access the value of ordinary key. + % No prefix is used here, to reduce macro name: + \skv@gobble@or@iden{\skvcslet{\skv@hp#2}\noexpand\skvcurrentvalue}% + \skvexpandonce\skv@callback + }% } -\skvrobustdef*\skvordkeys{\skv@testoptb\skv@ordkeys} -\skvrobustdef*\skv@ordkeys#1{\skv@testopt{\skv@ordkeys@a{#1}}{^skv^}} -\skvrobustdef*\skv@ordkeys@a#1[#2]#3{% - \skvcommaparse{#1}\skv@tempa{% - \skvexpbracenext\skv@strippointers\skv@tempa\skvcurrentkey - \skvexpanded{\skv@ordkey@a{\skvcurrentkey}}[#2]{#3}% +\skvrobustdef*\skv@ordkeys#1#2{\skv@testopt{\skv@ordkeys@a{#1}{#2}}{^skv^}} +\skvrobustdef*\skv@ordkeys@a#1#2[#3]#4{% + \skvcommaparse{#2}\skv@prova{% + \skvexpbracenext\skv@strippointersfromkey\skv@prova + \skvexpbracenext{\skv@ordkey@a{#1}}\skvcurrentkey[#3]{#4}% }% } - % \skvvoidkey[<pref>]{<fam>}{<key>}[<defa>]{<callback>} % % A void key is an invalid key. A user who tries to set that key will @@ -2727,20 +3440,47 @@ % \skvrobustdef*\skvvoidkey{\skv@testoptb\skv@voidkey} \skvrobustdef*\skv@voidkey#1{% - \skv@strippointers{#1}\skvcurrentkey + \skv@strippointersfromkey{#1}% \skvexpanded{\skv@testopt{\skv@voidkey@a{\skvcurrentkey}}{^skv^}}% } \skvrobustdef*\skv@voidkey@a#1[#2]#3{% \skvifstrcmpTF{#2}{^skv^}{}{\skv@definedefault{#1}{#2}}% - % Simply inserting '#3' in the next definition will not work because - % of the possible parameter characters in #3: - \edef\skv@tempa##1##2{% - ##2% - \skv@err{Key '#1' of family '\skvcurrentprefix/\skvcurrentfamily' - \MessageBreak has been set invalid by its author}\noexpand\@ehd + \skvcsedef{\skv@header#1.@cbk}{% + \unexpanded{#3}\relax + \skv@err{Key '#1' of family '\skvcurrentpath' + \MessageBreak has been set invalid by its author}\noexpand\skv@ehd + }% +} +% \skvobsoletekey +% [<pref>]{<fam>}{<obsolete key>}{<new key>}[<defa>]{<callback>} +% +% 1. An obsolete key is a key that is no longer in use and has +% been replaced by a new key. A user who tries to set an obsolete +% key will automatically be told that the key is obsolete and that +% he/she should instead use the new key. +% 2. The author of an obsolete key can also use <callback> to set a +% message for the user. <callback> can be empty. +% 3. Pointers can be used on both <obsolete key> and <new key>. +% +\skvrobustdef*\skvobsoletekey{\skv@testoptb\skv@obsoletekey} +\skvrobustdef*\skv@obsoletekey#1#2{% + \skv@strippointersfromkey{#1}% + \skvexpanded{% + \skv@testopt{\skv@obsoletekey@a{\skvcurrentkey}{#2}}{^skv^}% + }% +} +\skvrobustdef*\skv@obsoletekey@a#1#2[#3]#4{% + \skvifstrcmpTF{#3}{^skv^}{}{\skv@definedefault{#1}{#3}}% + \skvcsedef{\skv@header#1.@cbk}{% + \unexpanded{#4}\relax + \noexpand\skv@warn{Key '\skvcurrentpath/#1' + \MessageBreak is now obsolete. Instead of using the obsolete + \MessageBreak key '#1', I will now set the new key + \MessageBreak '#2' with the value you have given for + \MessageBreak key '#1'. You can avoid this warning by + \MessageBreak using the new key '#2' instead of the + \MessageBreak obsolete key '#1'}\noexpand\skv@ehd }% - \skv@toksa\expandafter{\skv@tempa{##1}{#3}}% - \skvcsedef{\skv@header#1.@cbk}{\the\skv@toksa}% } %% Key names with parenthesized tokens. @@ -2760,9 +3500,7 @@ % \def\x##1{#1*##1}% % } % -% \skvpntkey[KV]{fam}{evaluate (1) as (2) using (3)}[% -% \x\y{\numexpr\x*2} -% ]{% +% \skvpntkey[KV]{fam}{evaluate (1) as (2) using (3)}[\x\y{\numexpr\x*2}]{% % \edef\x#2{#3}% % } % @@ -2772,8 +3510,8 @@ % \skvrobustdef*\skvpntkey{\skv@testoptb\skv@pntkey} \skvrobustdef*\skv@pntkey#1{% - \skv@strippointers{#1}\skvcurrentkey - \skvexpbracenext\skv@extractpntkey\skvcurrentkey\skvcurrentkey + \skv@strippointersfromkey{#1}% + \skvexpbracenext\skv@extractpntkey@atdefkey\skvcurrentkey\skvcurrentkey \skvexpanded{\skv@testopt{\skv@pntkey@a{\skvcurrentkey}}{^skv^}}% } \skvrobustdef*\skv@pntkey@a#1[#2]#3{% @@ -2800,15 +3538,17 @@ % When the key's value has doubled hash characters, xkeyval's definition % of \skv@cmdkey fails: \skvrobustdef*\skv@cmdkey#1#2[#3]#4{% - \skv@strippointers{#2}\skvcurrentkey + \skv@strippointersfromkey{#2}% \skvifdefboolTF{skv@st}{\skv@definedefault\skvcurrentkey{#3}}{}% % This is to allow the key name to be expanded before possibly zapping % spaces in key name: \edef\skv@prova{#1\skvcurrentkey}% \edef\skv@prova{\expandafter\skv@zapornot\expandafter {\expandafter\skv@zapsw\expandafter}\expandafter{\skv@prova}}% - \skvcslet{\skv@header\skvcurrentkey.@hp}\skv@prova - \skvcsedef{\skv@header\skvcurrentkey.@cbk}{\unexpanded{#4}}% + \skvcsedef{\skv@header\skvcurrentkey.@cbk}{% + \skvcslet{\skv@prova}\noexpand\skvcurrentvalue + \unexpanded{#4}% + }% } % \skvcmdkeys[<pref>]{<fam>}[<mp>]{<keys>}[<defa>]{<callback>} \skvrobustdef*\skvcmdkeys{% @@ -2825,6 +3565,107 @@ }% } +%% List processor keys. +% +% \skvlistkey[<pref>]{<fam>}[<mp>]{<key>}[<defa>]{<callback>} +% +\skvrobustdef*\skv@getlistkeyparser#1{% + \begingroup + \let\skv@prova\undefined + \skvxifinTF{\detokenize{\listsep}}{\detokenize{#1}}{% + \skvxifinTF{\detokenize{\listparser}}{\detokenize{#1}}{% + \skv@err{I find both \noexpand\listsep and \noexpand\listparser in the + \MessageBreak callback of key '\skvcurrentfullkey'}\skv@ehd + }{% + \def\skv@prova{\listsep}% + }% + }{% + \skvxifinTF{\detokenize{\listparser}}{\detokenize{#1}}{% + \def\skv@prova{\listparser}% + }{}% + }% + \skvifdefTF\skv@prova{% + % Hide the parameter characters in #1 here: + \edef\skv@provc{\unexpanded{#1}}% + \def\skv@provb##1{% + \def\skv@provb####1##1####2####3\skv@listparser@nil{% + \skvifblankTF{####2}{% + \def\skv@listparser{,}% + }{% + \edef\skv@listparser{\skvtrimspace{####2}}% + }% + \edef\skv@callback{\skvtrimspace{####1}\skvtrimspace{####3}}% + }% + \expandafter\skv@provb\skv@provc\skv@listparser@nil + }% + \expandafter\skv@provb\expandafter{\skv@prova}% + }{% + \def\skv@listparser{,}% + \edef\skv@callback{\skvtrimspace{#1}}% + }% + \skvexpanded{\endgroup + \skvcmdexit\skv@listparser\skvcmdexit\skv@callback + }% +} +\skvnewlet\skvstopprocessinglistkey\skvbreakloop +\skvrobustdef*\skvlistkey{% + \def\skv@zapsw{01}% + \skv@testoptd\skv@listkey{list}% +} +\skvrobustdef*\skvzlistkey{% + \def\skv@zapsw{00}% + \skv@testoptd\skv@listkey{list}% +} +\skvrobustdef*\skv@listkey#1#2[#3]#4{% + \skv@strippointersfromkey{#2}% + \skvifdefboolTF{skv@st}{\skv@definedefault\skvcurrentkey{#3}}{}% + % This is to allow the key name to be expanded before possibly zapping + % spaces in key name: + \edef\skv@provb{#1\skvcurrentkey}% + \edef\skv@provb{\expandafter\skv@zapornot\expandafter + {\expandafter\skv@zapsw\expandafter}\expandafter{\skv@provb}}% + \skv@getlistkeyparser{#4}% + % If there are more parameters in #4 than ####1, the next step + % will raise an error: + \skvxifinTF{\detokenize{##2}}{\skvoxdetok\skv@callback}{% + \skv@err{A listkey can't have more than one + \MessageBreak parameter character}\skv@ehd + }{% + \def\skv@prova{\skvcsdef{\skv@header\skvcurrentkey.@auxcbk}####1}% + \expandafter\skv@prova\expandafter{\skv@callback}% + }% + \let\do\noexpand + \skvcsedef{\skv@header\skvcurrentkey.@cbk}{% + \skvcslet{\skv@provb}\do\skvcurrentvalue + \edef\do\skv@prova{\do\unexpanded{####1}}% + \do\skvstripouterbraces{2}\do\skv@prova + % 1. \skvprocesslist processes an empty list. + % 2. You can call \skvlistcount when processing listkeys, since + % \skvprocesslist initializes and increments it. + \do\skvprocesslist*{\skv@listparser}\do\skv@prova\do\skv@prova{% + \do\csname\skv@header\skvcurrentkey.@auxcbk% + \do\expandafter\endcsname\do\expandafter{\do\skv@prova}% + }% + }% + % A listkey must have a 1-parameter argument. We use the following + % definition to enforce this requirement: + \skvcsdef{\skv@header\skvcurrentkey.@listkey}{}% +} +% \skvlistkeys[<pref>]{<fam>}[<mp>]{<keys>}[<defa>]{<callback>} +\skvrobustdef*\skvlistkeys{% + \def\skv@zapsw{01}% + \skv@testoptd\skv@listkeys{list}% +} +\skvrobustdef*\skvzlistkeys{% + \def\skv@zapsw{00}% + \skv@testoptd\skv@listkeys{list}% +} +\skvrobustdef*\skv@listkeys#1#2[#3]#4{% + \skvcommaparse{#2}\skv@tempa{% + \skvexpanded{\skv@listkey{#1}{\skv@tempa}}[#3]{#4}% + }% +} + %% Choice keys: % % The skeyval package allows holder-macro prefixes {<mp>} for choice keys. @@ -2855,8 +3696,7 @@ \if#1}\fi \skvstripouterbraces{2}\skv@prova \edef\skv@altlista{% - \skvxonce\skv@altlista\ifx\skv@altlista\@empty\else,\fi - \skvxonce\skv@prova + \skvaddlist,\skv@altlista\skvxonce\skv@prova }% \edef\reserved@a{% \skvnoexpandcs{\skvoxdetok\skv@prova @skvch}% @@ -2868,7 +3708,7 @@ \expandafter\skv@provc\skv@prova.do=.do=\skv@choice@nil }% \ifx\skv@altlista\@empty - \skv@err{No nominations (state pattern) for choice key}\@ehd + \skv@err{No nominations (state pattern) for choice key}\skv@ehd \def\skv@altlistb{}% \fi \skvexpanded{\endgroup @@ -2895,7 +3735,7 @@ \edef\skv@prova{\unexpanded{##2}}% \ifx\skv@prova\skv@nnil \skv@err{No state pattern match found for key - \MessageBreak '\skvcurrentkey'}\@ehd + \MessageBreak '\skvcurrentkey'}\skv@ehd \toks@{}% \fi }% @@ -2911,7 +3751,7 @@ \skvrobustdef*\skv@choicekey@a[#1]#2{% \skvxifinTF{\skv@hashchar}{\detokenize{#2}}{% \skv@err{Hash character '\skv@hashchar' not allowed - \MessageBreak in key name}\@ehd + \MessageBreak in key name}\skv@ehd }{% \edef\skv@currlist{\unexpanded{#2}}% \edef\skv@hp{\skvtrimspace{#1}}% @@ -2927,13 +3767,13 @@ \skvtfor\skv@prova:=#1\do{% \skvexpbracenext\skvifescapedTF\skv@prova{}{% \skv@err{Token '\skvoxdetok\skv@prova' of bin of - \MessageBreak choice key isn't escaped}\@ehd + \MessageBreak choice key isn't escaped}\skv@ehd }% }% \fi \skvifblankTF{#2}{% \skv@err{No nominations (state pattern) for - \MessageBreak choice keys '\skv@currlist'}\@ehd + \MessageBreak choice keys '\skv@currlist'}\skv@ehd }{% \skvifboolTF{skv@st}{% \skv@preparenominations{00}{#2}% @@ -2982,15 +3822,17 @@ } \skvrobustdef*\skv@choicekey@g{% \skvcommaparse*\skv@currlist\skv@prova{% - \skvexpbracenext\skv@strippointers\skv@prova\skvcurrentkey + \skvexpbracenext\skv@strippointersfromkey\skv@prova \ifx\skv@default\skv@rej\else \skvexpanded{% \noexpand\skv@definedefault {\skvxonce\skvcurrentkey}{\skvxonce\skv@default}% }% \fi - \skvcsedef{\skv@header\skvcurrentkey.@hp}{\skv@hp\skvcurrentkey}% - \skvcsedef{\skv@header\skvcurrentkey.@cbk}{\the\skv@toksa}% + \skvcsedef{\skv@header\skvcurrentkey.@cbk}{% + \skvcslet{\skv@hp\skvcurrentkey}\noexpand\skvcurrentvalue + \the\skv@toksa + }% }% } @@ -3024,7 +3866,7 @@ } % \skv@boolkeys{<mp>}{<key>}[<default>] \skvrobustdef*\skv@boolkey#1#2[#3]{% - \skv@strippointers{#2}\skvcurrentkey + \skv@strippointersfromkey{#2}% \skvexpanded{% \ifskv@pl\skv@boolkey@b\else\skv@boolkey@a\fi {\skvcurrentkey}{#1\skvcurrentkey}% @@ -3094,7 +3936,7 @@ \skvrobustdef*\skv@boolkeys@b#1#2#3#4#5{\skv@boolkeys@c{#1}{#2}{#3}{#4}{#5}} \skvrobustdef*\skv@boolkeys@c#1#2#3#4#5{% \skvcommaparse{#1}\skv@tempa{% - \skvexpbracenext\skv@strippointers\skv@tempa\skvcurrentkey + \skvexpbracenext\skv@strippointersfromkey\skv@tempa \skvexpanded{% \skvifstrcmpTF{#5}{^skv^}{% \skv@boolkey@a{\skvcurrentkey}% @@ -3145,15 +3987,14 @@ }% \ifnum\@tempcnta=\tw@\else \skv@err{Number of bi-keys isn't 2: - \MessageBreak ||\skv@currlist||}\@ehd + \MessageBreak ||\skv@currlist||}\skv@ehd \fi \skvexpanded{% \ifskv@pl\skv@biboolkeys@b\else\skv@biboolkeys@a\fi {\skv@currlist}% }{#1}{#3}% } -% \skv@bilboolkeys@a{<key1,key2>}{<mp>}{<default>} -% {<callback1>}{<callback2>} +% \skv@bilboolkeys@a{<key1,key2>}{<mp>}{<default>}{<callback1>}{<callback2>} \skvrobustdef*\skv@biboolkeys@a#1#2#3#4#5{% \skv@biboolkeys@c{#1}{#2}{#3}{#4}{#5}{^skv^}% } @@ -3172,7 +4013,7 @@ \edef\skv@tempd{\unexpanded{#5}}% \edef\skv@tempe{\unexpanded{#6}}% \toks@{}\def\skv@provd{}% - \let\\\noexpand + \let\nx\noexpand \def\@do##1##2{% \skvifcsname\skv@header##1.@##2\then \edef\skv@provd{% @@ -3186,12 +4027,12 @@ \def\skv@provc##1##2##3##4{% \skvsettogtrue{\skv@header bicallerid/##3}% \skvxonce\@elt - \\\skvifxTF\\\skvcurrentvalue\\\skv@truetoks{% - \\\skviftogTF{\skv@header bicallerid/##4}{}{% + \nx\skvifxTF\nx\skvcurrentvalue\nx\skv@truetoks{% + \nx\skviftogTF{\skv@header bicallerid/##4}{}{% \skvsetkeys[##1]{##2}{##4=false}% }% }{% - \\\skviftogTF{\skv@header bicallerid/##4}{}{% + \nx\skviftogTF{\skv@header bicallerid/##4}{}{% \skvsetkeys[##1]{##2}{##4=true}% }% }% @@ -3218,14 +4059,16 @@ }% }% \def\skv@prova##1,##2\skv@nil{% - \skv@strippointers{##1}\skv@tempa - \skv@strippointers{##2}\skv@tempb + \skv@strippointersfromkey{##1}% + \let\skv@tempa\skvcurrentkey + \skv@strippointersfromkey{##2}% + \let\skv@tempb\skvcurrentkey \skvexpanded{% - \let\\\@elt\\\skv@tempc - \\\skv@provb{\skvcurrentprefix}{\skvcurrentfamily}% + \let\nx\@elt\nx\skv@tempc + \nx\skv@provb{\skvcurrentprefix}{\skvcurrentfamily}% {\skv@tempa}{\skv@tempb}% - \let\\\@elt\\\skv@tempd - \\\skv@provb{\skvcurrentprefix}{\skvcurrentfamily}% + \let\nx\@elt\nx\skv@tempd + \nx\skv@provb{\skvcurrentprefix}{\skvcurrentfamily}% {\skv@tempb}{\skv@tempa}% }% }% @@ -3260,6 +4103,10 @@ \def\skv@zapsw{00}% \skv@t@stopta{\skv@testoptd\skv@boolkeys{}}% } +% \skvbitogkeys[<pref>]{<fam>}[<mp>]{<key1,key2>}[<defa>] +% {<callback.for.key1>}{<callback.for.key2>} +% \skvbitogkeys+[<pref>]{<fam>}[<mp>]{<key1,key2>}[<defa>] +% {<callback.for.key1>}{<callback.for.key2>}{<fallback>} \skvrobustdef*\skvbitogkeys{% \def\skv@typetogkey{00}% \def\skv@zapsw{01}% @@ -3270,126 +4117,211 @@ \def\skv@zapsw{00}% \skv@t@stopta{\skv@testoptd\skv@biboolkeys{}}% } +\skvrobustdef*\skvSignalkeyPresetException#1{% + \edef\skv@signalpreseterr{\unexpanded{#1}}% +} +\skvSignalkeyPresetException{% + \@latex@error{% + Key '\skvcurrentfullkey' + \MessageBreak is a signal key. It shouldn't have + \MessageBreak been preset. Presetting signal keys + \MessageBreak does lead to cyclic key setting + }\skv@ehd +} -% Style keys +% Declare prefix and family and then define/set keys on them (without +% the need to give prefix and family). This can be handy if all the keys +% in a project have the same prefix and family. % -% \skvappendstyles[<pref>]{<fam>}{<keys>}{<styles>}[<defa>]{<callback>} -% \skvprependstyles[<pref>]{<fam>}{<keys>}{<styles>}[<defa>]{<callback>} +% Example: % -% 1. Style keys will be created if they didn't exist. If they existed, -% (a) their default values will be overwritten if the option [<defa>] -% appears in the above syntax; (b) their callbacks will be updated with -% <callback> and <styles>. +% \skvsetprefix{KV} +% \skvsetfamily{fam} +% \skvdefineordkey{key1}[default]{\def\x##1{##1*#1}} +% \skvprocesskeys{key1=value1} +% +\skvrobustdef*\skvsetprefix{\def\skv@currpref} +\skvrobustdef*\skvsetfamily{\def\skv@currfam} +\skvrobustdef*\skv@defineonmeta#1{% + \ifdefined\skv@currpref\else + \let\skv@currpref\skvdefaultprefix + \fi + \skvexpanded{\noexpand#1[\skv@currpref]{\skv@currfam}}% +} +\skvrobustdef*\skvdefineordkey{\skv@defineonmeta\skvordkey} +\skvrobustdef*\skvdefineordkeys{\skv@defineonmeta\skvordkeys} +\skvrobustdef*\skvdefinecmdkey{\skv@defineonmeta\skvcmdkey} +\skvrobustdef*\skvdefinecmdkeys{\skv@defineonmeta\skvcmdkeys} +\skvrobustdef*\skvdefineboolkey{\skv@defineonmeta\skvboolkey} +\skvrobustdef*\skvdefineboolkeys{\skv@defineonmeta\skvboolkeys} +\skvrobustdef*\skvdefinebiboolkeys{\skv@defineonmeta\skvbiboolkeys} +\skvrobustdef*\skvdefinetogkey{\skv@defineonmeta\skvtogkey} +\skvrobustdef*\skvdefinetogkeys{\skv@defineonmeta\skvtogkeys} +\skvrobustdef*\skvdefinechoicekey{\skv@defineonmeta\skvchoicekey} +\skvrobustdef*\skvdefinechoicekeys{\skv@defineonmeta\skvchoicekeys} +\skvrobustdef*\skvprocesskeys{\skv@defineonmeta\skvsetkeys} + +% Signal-slot keys: +% +% \skvappendslots[<pref>]{<fam>}{<signal.keys>}{<slots>} +% [<signal default>]{<signal callback>} +% \skvprependslots[<pref>]{<fam>}{<signal.keys>}{<slots>} +% [<signal default>]{<signal callback>} +% +% 1. <slots> must pre-exist. If slot key is undefined, then the signal-slot +% system isn't useful here since the slot will serve no purpose. % % 2. If desired, use pointers/handlers .expanded, .expand once, .expand twice -% on values of styles. +% on values of <slots>. +% +% 3. Here, it helps to consider <keys> as parents (or signals or +% subjects) and <slots> as children (or slots or observers). +% +% 4. <signal.keys> can't be preset, to avoid cyclic setting of keys. +% Consider the following, for a signal key in the preset list: +% +% set any key on a path -> preset 'signal' +% -> set 'slot' -> preset 'signal'. +% +% In the attempt to set a slot key, the preset list (that includes +% the signal key) will be instantiated. % % Example: % % \skvordkeys[KV]{fam}{keya,keyb}{\def\x##1{#1*##1}} -% \skvappendstyles[KV]{fam}{keyd,keye}{keya=.expanded{\vala},keyb=valb} +% \skvappendslots[KV]{fam}{keyd,keye}{keya=.expanded{\vala},keyb=valb} % [def-d&e]{\def\y##1{#1*##1}} % -\skvrobustdef*\skvappendstyles{% +\skvrobustdef*\skvappendslots{% \def\skv@type{app}% - \def\skvexpanderpointer{}% - \skv@testoptb\skv@appendstyles + \let\skvexpanderpointer\@iden + \skv@testoptb\skv@appendslots } -\skvnewlet\skvstylekeys\skvappendstyles -\skvrobustdef*\skvprependstyles{% +\skvrobustdef*\skvprependslots{% \def\skv@type{prep}% - \def\skvexpanderpointer{}% - \skv@testoptb\skv@appendstyles + \let\skvexpanderpointer\@iden + \skv@testoptb\skv@appendslots } -\skvrobustdef*\skvappendstylesexpanded{% +\skvrobustdef*\skvappendslotsexpanded{% \def\skv@type{app}% \def\skvexpanderpointer{.expanded}% - \skv@testoptb\skv@appendstyles + \skv@testoptb\skv@appendslots } -\skvnewlet\skvstylekeysexpanded\skvappendstylesexpanded -\skvrobustdef*\skvprependstylesexpanded{% +\skvrobustdef*\skvprependslotsexpanded{% \def\skv@type{prep}% \def\skvexpanderpointer{.expanded}% - \skv@testoptb\skv@appendstyles + \skv@testoptb\skv@appendslots } -\skvrobustdef*\skv@appendstyles#1#2{% - \skv@testopt{\skv@appendstyles@a{#1}{#2}}{^skv^}% +\skvrobustdef*\skv@appendslots#1#2{% + \skv@testopt{\skv@appendslots@a{#1}{#2}}{^skv^}% } -% #2: styles, #3: default, #4: callback -\skvrobustdef*\skv@appendstyles@a#1#2[#3]#4{% +% #1=signal keys, #2=slot keys, #3=signal default, #4=signal callback +\skvrobustdef*\skv@appendslots@a#1#2[#3]#4{% \skvcommaparse{#1}\skv@prova{% - \skvexpbracenext\skv@strippointers\skv@prova\skvcurrentkey + \skvexpbracenext\skv@strippointersfromkey\skv@prova \skvexpanded{% \skvifstrcmpTF{#3}{^skv^}{}{% + % If the signal aready exists, the default value will be + % overridden: \skv@definedefault{\skvcurrentkey}{\unexpanded{#3}}% }% - \skv@appendstyles@b{\skvcurrentkey}\unexpanded{{#2}{#4}}% + \skv@appendslots@b{\skvcurrentkey}\unexpanded{{#2}{#4}}% }% }% } -% \skv@appendstyles@b{<parent.key>}{<styles>}{<parent.key.callback>} -\skvrobustdef*\skv@appendstyles@b#1#2#3{% - \def\skv@stylelist{}% +% \skv@appendslots@b{<signal>}{<slots>}{<signal.callback>} +\skvrobustdef*\skv@appendslots@b#1#2#3{% + \def\skv@slotlist{}% \skvkvparse{#2}\skv@prova{% - \ksv@kvosplit\skv@prova{% + \skv@okvsplit\skv@prova{% \skvxifstrcmpTF{#1}{##1}{% - \skv@err{Linking key '##1' to itself}\@ehd + \skv@err{Linking key '##1' to itself}\skv@ehd }{% + % If slot key is undefined, then the signal-slot system isn't + % useful, since the slot won't be able to do anything with the + % emitted signal. \skvifcsdefTF{\skv@header##1.@cbk}{}{% - \skv@err{Style key '##1' is undefined}\@ehd + \skv@err{Slot key '\skvcurrentpath/##1' + \MessageBreak is undefined}\skv@ehd }% }% - \edef\skv@stylelist{% - \skvaddlist,\skv@stylelist\unexpanded{##1}=% - \skvexpandonce\skvexpanderpointer{\unexpanded{##2}}% + \edef\skv@slotlist{% + \skvaddlist,\skv@slotlist\unexpanded{##1}=% + \skvexpanderpointer{\unexpanded{##2}}% }% }% }% + \edef\skv@elt{% + % Signal keys shouldn't be preset, to avoid cyclic setting of keys. + % See note above. + \noexpand\skvifdefboolTF{skv@inprepo}{% + \noexpand\skv@signalpreseterr + }{% + \noexpand\skvsetkeys[\skvcurrentprefix]% + {\skvcurrentfamily}{\skvexpandonce\skv@slotlist}% + }% + }% + % The signal key might already exists, especially when calling + % \skvaddslots: \edef\elt{% \skvifcsdefTF{\skv@header#1.@cbk} - {\skvxpandcsonce{\skv@header#1.@cbk}}{}% - }% - \edef\skv@elt{% - \noexpand\skvexpanded{\noexpand\skvsetkeys[\skvcurrentprefix]% - {\skvcurrentfamily}{\skvexpandonce\skv@stylelist}}% + {\skvexpandcsonce{\skv@header#1.@cbk}}{}% }% \skvcsedef{\skv@header#1.@cbk}{% \skvxifstrcmpTF{\skv@type}{prep}{% - \skvexpandonce\skv@elt\unexpanded{#3}\skvexpandonce\elt + \skvexpandonce\skv@elt\skvtrimspace{#3}\skvexpandonce\elt }{% - \skvexpandonce\elt\unexpanded{#3}\skvexpandonce\skv@elt + \skvexpandonce\elt\skvtrimspace{#3}\skvexpandonce\skv@elt }% }% } % -% \skvaddstyles[<pref>]{<fam>}{<keys>}{<prepend>}{<append>}[<defa>]{<callback>} +% \skvaddslots[<pref>]{<fam>}{<signals>}{<prepended.slots>} +% {<appended.slots>}[<signal.default>]{<signal.callback>} % -% Example: +% Slot keys are observer keys that receive signals from signal +% (ie, subject) keys. +% +% Examples: % \skvordkeys[KV]{fam}{keya1,keyb1,keya2,keyb2}{\def\x##1{#1*##1}} -% \skvaddstyles[KV]{fam}{keyd,keye}{keya1=vala,keyb1=valb} +% \skvaddslots[KV]{fam}{keyd,keye}{keya1=vala,keyb1=valb} % {keya2=vala,keyb2=.expanded{\valb}}[def-d&e]{\def\y##1{#1*##1}} % -\skvrobustdef*\skvaddstyles{% - \def\skvexpanderpointer{}% - \skv@testoptb\skv@addstyles +% \skvordkeys{graph}{avertices,bvertices}[6]{\def\x##1{#1+##1}} +% \skvaddslots{graph}{vertices}{avertices=4}{bvertices=8}[6] +% {\def\y##1{#1*##1}} +% \skvsetkeys{graph}{vertices=6} +% +\skvrobustdef*\skvaddslots{% + \let\skvexpanderpointer\@iden + \skv@testoptb\skv@addslots } -\skvrobustdef*\skv@addstyles#1#2#3{% - \skv@testopt{\skv@addstyles@a{#1}{#2}{#3}}{^skv^}% +\skvrobustdef*\skv@addslots#1#2#3{% + \skv@testopt{\skv@addslots@a{#1}{#2}{#3}}{^skv^}% } -% #2: prepended styles -% #3: appended styles -% #4: default -% #5: callback -\skvrobustdef*\skv@addstyles@a#1#2#3[#4]#5{% +% \skv@addslots@a{<signals>}{<prepended slots>}{<appended slots>} +% [<signal default>]{<signal callback>} +\skvrobustdef*\skv@addslots@a#1#2#3[#4]#5{% \skvexpanded{% - \skvprependstyles[\skvcurrentprefix]{\skvcurrentfamily}% + \skvprependslots[\skvcurrentprefix]{\skvcurrentfamily}% \unexpanded{{#1}{#2}[#4]{#5}}% - \skvappendstyles[\skvcurrentprefix]{\skvcurrentfamily}% + \skvappendslots[\skvcurrentprefix]{\skvcurrentfamily}% \unexpanded{{#1}{#3}[#4]{#5}}% }% } - -%% Checking the admissible values of keys: +\skvnewcastcommands{% + \skvslotkeys=\skvappendslots,\skvstylekeys=\skvappendslots, + \skvprependstyles=\skvprependslots, + \skvappendstylesexpanded=\skvappendslotsexpanded, + \skvprependstylesexpanded=\skvprependslotsexpanded, + \skvaddstyles=\skvaddslots, + \skvobserverkeys=\skvappendslots, + \skvprependobservers=\skvprependslots, + \skvappendobserversexpanded=\skvappendslotsexpanded, + \skvprependobserversexpanded=\skvprependslotsexpanded, + \skvaddobservers=\skvaddslots +} +% Checking the admissible values of keys: % \skvrobustdef*\skvcheckchoice{\skv@testopta{\skv@testopt\skv@checkchoice{}}} \skvrobustdef*\skv@checkchoice[#1]#2#3{% @@ -3434,7 +4366,7 @@ \ifskv@pl \skvappendtomacro\skv@tempa{\@secondoftwo}% \else - \skv@err{Value '\detokenize{#2}' is not allowed}\@ehd + \skv@err{Value '\detokenize{#2}' is not allowed}\skv@ehd \skvappendtomacro\skv@tempa{\@gobble}% \fi }% @@ -3453,7 +4385,7 @@ \ifskv@pl \edef\skv@tempb{\skv@prova\@secondoftwo}% \else - \skv@err{Value '\detokenize{#3}' is not allowed}\@ehd + \skv@err{Value '\detokenize{#3}' is not allowed}\skv@ehd \edef\skv@tempb{\skv@prova\@gobble}% \fi \else @@ -3476,12 +4408,14 @@ \skvrobustdef*\skv@checkchoice@e#1\skv@nil,{\@firstofone} % \skvifkeydefTF[<prefs>]{<fams>}{key}{<true>}{<false>} +% % 1. The search will stop as soon as the key is found in one combination % of prefixes/families. % 2. The prefix and header created here may be needed in #5 and #6. Hence % we put entry prefix and header on stack before commencing the search. -\skvrobustdef*\skvifkeydefTF{\skv@testopt{\skv@ifkeyundef0}\skv@defaultpref} -\skvrobustdef*\skvifkeydefFT{\skv@testopt{\skv@ifkeyundef1}\skv@defaultpref} +% +\skvrobustdef*\skvifkeydefTF{\skv@testopt{\skv@ifkeyundef0}\skvdefaultprefix} +\skvrobustdef*\skvifkeydefFT{\skv@testopt{\skv@ifkeyundef1}\skvdefaultprefix} \skvrobustdef*\skv@ifkeyundef#1[#2]#3#4#5#6{% \skvpushstate\skv@keystate\skv@keydepth \edef\skv@prefs{#2}% @@ -3494,6 +4428,7 @@ \skvcommaparse*\skv@prefs\skv@prova{% \skv@makeprefix\skv@prova \skv@ifk@yundef + % Break outer loop as needed: \ifskv@kf\skvbreakloop\fi }% \skvexpanded{% @@ -3510,8 +4445,7 @@ \noexpand\@firstoftwo \fi }% - }% - {#5}{#6}% + }{#5}{#6}% \skvpopstate\skv@keystate\skv@keydepth } \skvrobustdef*\skv@ifk@yundef{% @@ -3525,13 +4459,27 @@ % \skvifkeyinfamiliesTF[<prefs>]{<fams>}{key}{<true>}{<false>} % % The search will be done on all combinations of prefixes/families. The -% callback <true> or <false> will be executed for all the combinations. +% callback <true> or <false> will be executed for ALL the combinations. % \skvrobustdef*\skvifkeyinfamiliesTF{% - \skv@testopt{\skv@ifkeyinfamilies0}\skv@defaultpref + \skv@testopt{\skv@ifkeyinfamilies0}\skvdefaultprefix +} +% \skvdoonallpathsfound[<prefs>]{<fams>}{key}{<true>} +\skvrobustdef*\skvdoonallpathsfound{% + \skv@testopt\skv@doonallpathsfound\skvdefaultprefix +} +\skvrobustdef*\skv@doonallpathsfound[#1]#2#3#4{% + \skv@ifkeyinfamilies0[#1]{#2}{#3}{#4}{}% +} +% \skvdoonallpathsnotfound[<prefs>]{<fams>}{key}{<false>} +\skvrobustdef*\skvdoonallpathsnotfound{% + \skv@testopt\skv@doonallpathsnotfound\skvdefaultprefix +} +\skvrobustdef*\skv@doonallpathsnotfound[#1]#2#3#4{% + \skv@ifkeyinfamilies0[#1]{#2}{#3}{}{#4}% } \skvrobustdef*\skvifkeyinfamiliesFT{% - \skv@testopt{\skv@ifkeyinfamilies1}\skv@defaultpref + \skv@testopt{\skv@ifkeyinfamilies1}\skvdefaultprefix } \skvrobustdef*\skv@ifkeyinfamilies#1[#2]#3#4#5#6{% \skvpushstate\skv@keystate\skv@keydepth @@ -3572,6 +4520,7 @@ \skvnewdef*\skvifkeyincurrentfamilyTF#1{% \skvifcsdefTF{\skvcurrentpath/\skvtrimspace{#1}.@cbk}% } +\skvnewlet\skvifkeyoncurrentpathTF\skvifkeyincurrentfamilyTF % \skvifonekeyinfamilyTF{<prefix>/<family>}{<keys>} % Given a list of keys, test if at least one of them is defined. % Example: \edef\x{\skvifonekeyinfamilyTF{KV/fam}{keya,keyb,keyc}{T}{F}}. @@ -3592,10 +4541,49 @@ {#1}% } +% \skvgetdefinedkeys[<pref>]{<fams>}{<keys>} +% +% 1. Get keys defined on the given paths. +% 2. Remove any redundant star (*) and plus (+) suffix on +% \skvgetdefinedkeys. +\skvrobustdef*\skvgetdefinedkeys{% + \skv@testopta{\skv@testopt\skv@getdefinedkeys\skvdefaultprefix}% +} +\skvrobustdef*\skv@getdefinedkeys[#1]#2#3{% + \begingroup + \skv@makeprefix{#1}% + \def\skv@tempa{}% + \skvcommaparse{#2}\skvcurrentfamily{% + \skv@makeheader\skvcurrentfamily + % Prepare to take defined keys outside the group: + \skvxifinTF{\skvoxdetok\skv@header}{\skvoxdetok\skv@tempa}{}{% + \edef\skv@tempa{% + \skvexpandonce\skv@tempa + \noexpand\skvcsexit{\skvcurrentpath.@definedkeys}% + }% + }% + \skvcommaparse{#3}\skvcurrentkey{% + \skvifcsdefFT{\skv@header\skvcurrentkey.@cbk}{}{% + \skvletcs\skv@prova{\skvcurrentpath.@definedkeys}% + \skvifdefTF\skv@prova{% + \skvxifinTF{,\skvoxdetok\skvcurrentkey,}{,\skvoxdetok\skv@prova,}{}{% + \skvcsedef{\skvcurrentpath.@definedkeys}{\skv@prova,\skvcurrentkey}% + }% + }{% + \skvcsedef{\skvcurrentpath.@definedkeys}{\skvcurrentkey}% + }% + }% + }% + }% + \skvexpanded{\endgroup\skv@tempa}% +} + % \skvvalueof{<pref>}{<family>}{<key>} \skvnewdef*\skvvalueof#1#2#3{\skvcsuse{#1/#2/#3.@value}} +% \skvvalueofkey{<pref>/<family>/<key>} +\skvnewdef*\skvvalueofkey#1{\skvcsuse{#1.@value}} -% When <pref> isn't given, the following will use 'KV' for <pref>. +% When <pref> isn't given, the following will use 'default KV' for <pref>. % \skvprintvalue[<pref>]{<family>}{<key>} \skvrobustdef*\skvprintvalue{\skv@testoptb\skv@printvalue} \skvrobustdef*\skv@printvalue#1{\skvcsuse{\skv@header#1.@value}} @@ -3612,30 +4600,43 @@ % \skvconveyinikv[<pref>]{<family>}<cmd> \skvrobustdef*\skvconveyinikv{\skv@testoptb\skv@conveyinikv} -\skvrobustdef*\skv@conveyinikv#1{\skvletcs#1{\skv@header.@inikv}} +\skvrobustdef*\skv@conveyinikv#1{\skvletcs#1{\skvcurrentpath.@inikv}} % \skvkeyslet[<pref>]{<family>}{<list>} -% <list> -> <new keyname>=<old keyname> +% +% <list> -> {<newkey1>,<newkey2>,...,<newkey-n>}={<oldkey>} +% +% Note: <oldkey> must be only one key, to avoid letting one newkey +% to two oldkeys. +% \skvrobustdef*\skvkeyslet{\skv@testoptb\skv@keyslet} -\skvnewlet\skvkeyinheritance\skvkeyslet -\skvnewlet\skvkeylet\skvkeyslet +\skvnewlet\skvkeyinherit\skvkeyslet \skvrobustdef*\skv@keyslet#1{% - \skvletcs\skv@inikv{\skv@header.@inikv}% + \skvletcs\skv@inikv{\skvcurrentpath.@inikv}% \skvifdefFT\skv@inikv{}{% - \expandafter\skv@getkeynames\expandafter{\skv@inikv}\skv@inikeys + \skvexpbracenext\skv@getnamesofkeys\skv@inikv\skv@inikeys + }% + \def\skv@keyslet@do@a##1=##2=##3\skv@nil{% + \skvifinTF{,}{##2}{% + \skv@err{There more than one old key:\MessageBreak '##2'}\skv@ehd + }{% + \skvcommaparse{##1}\skv@prova{% + \skvexpbracenext\skv@keyslet@do@b\skv@prova{##2}% + }% + }% }% - \def\skv@k@yslet##1=##2=##3\skv@nil{% - \skvifcsdefFT{\skv@header##2.@cbk}{% - \skv@err{Key '\skvcurrentpath/##2' is undefined}\@ehd + \def\skv@keyslet@do@b##1##2{% + \skvifnamedefFT{\skv@header##2.@cbk}{% + \skv@err{Key '\skvcurrentpath/##2'\MessageBreak is undefined}\skv@ehd }{% - \skvifcsdefTF{\skv@header##1.@cbk}{% - \skv@err{Key '\skvcurrentpath/##1' is already defined}\@ehd + \skvifnamedefTF{\skv@header##1.@cbk}{% + \skv@err{Key '\skvcurrentpath/##1' is already defined}\skv@ehd }{}% }% - \skvcommaloop{cbk,ndv,fbv}\skv@prova{% + \skvcommaloop{cbk,ndv,gnv,fbv,gfv}\skv@prova{% \skvcsletcs{\skv@header##1.@\skv@prova}{\skv@header##2.@\skv@prova}% }% - \skvifcsdefTF{\skv@header##2.@defa}{% + \skvifnamedefTF{\skv@header##2.@defa}{% \edef\skvcurrentkey{##2}% \skv@getdefault\skvcurrentprefix\skvcurrentfamily\skvcurrentkey \skvcurrentvalue @@ -3648,27 +4649,28 @@ }% \skvifdefFT\skv@inikv{}{% \skvxifinFT{,\detokenize{##2},}{,\skvoxdetok\skv@inikeys,}{}{% - \skvcsedef{\skv@header.@inikv}{% - \expandafter\skvaddlist\expandafter - ,\csname\skv@header.@inikv\endcsname + \skvcsedef{\skvcurrentpath.@inikv}{% + \skvcsaddlist,{\skvcurrentpath.@inikv}% ##1\ifskv@swa=\skvexpandonce\skvcurrentvalue\fi }% }% }% \skvcommaloop{ignoredkeys,needini}\skv@prova{% - \skvletcs\skv@tempa{\skv@header.@\skv@prova}% + \skvletcs\skv@tempa{\skvcurrentpath.@\skv@prova}% \skvifdefFT\skv@tempa{}{% \skvxifinFT{,\detokenize{##2},}{,\skvoxdetok\skv@tempa,}{}{% - \skvcsedef{\skv@header.@\skv@prova}{\skvaddlist,\skv@tempa##1}% + \skvcsedef{\skvcurrentpath.@\skv@prova}{% + \skvaddlist,\skv@tempa##1% + }% }% }% }% }% \skvkvparse{#1}\skv@prova{% - \expandafter\skv@k@yslet\skv@prova==\skv@nil + \expandafter\skv@keyslet@do@a\skv@prova==\skv@nil }% \let\do\skvundef - \do\skv@k@yslet\do\skv@inikv\do\skv@inikeys + \do\skv@keyslet@do\do\skv@inikv\do\skv@inikeys } \skvrobustdef*\skv@disabledkeywarning#1{% @@ -3685,42 +4687,53 @@ \MessageBreak earlier \ifskv@latex in \noexpand\documentclass or \string\usepackage\fi}% } -\skvrobustdef*\skvdisabledkeysmessagetype#1{% +% A key may be disabled long before \skvmessagetypefordisabledkey +% is called. +\skvrobustdef*\skvmessagetypefordisabledkey#1{% \edef\skv@prova{\skvtrimspace{#1}}% \def\skv@provb##1{% \def\skv@provb####1##1####2####3\@nil{% \ifcase####2\relax - \let\skv@disabledmsg\skv@disabledkeywarning + \let\skv@disabledkeymsg\skv@disabledkeywarning \or - \let\skv@disabledmsg\skv@disabledkeywarning + \let\skv@disabledkeymsg\skv@disabledkeywarning \or - \let\skv@disabledmsg\skv@disabledkeyerror + \let\skv@disabledkeymsg\skv@disabledkeyerror \or - \let\skv@disabledmsg\@gobble + \let\skv@disabledkeymsg\@gobble \else - \skv@err{Invalid message type '#1' for disabled keys}\@ehd + \skv@err{Invalid message type '#1' for disabled keys}\skv@ehd \fi }% \skv@provb warn{0}warning{1}error{2}nothing{3}##1{10}\@nil }% \expandafter\skv@provb\expandafter{\skv@prova}% } +\skvnewlet\skvdisabledkeysmessagetype\skvmessagetypefordisabledkey \skvdisabledkeysmessagetype{warn} -\skvrobustdef*\skvdisablekeys{\skv@testoptb\skv@disablekeys} +\skvrobustdef*\skvdisablekeys{% + \def\skv@tempa{\skv@ordkey@a{e}}% + \skv@testoptb\skv@disablekeys +} +\skvrobustdef*\skvgdisablekeys{% + \def\skv@tempa{\skv@ordkey@a{x}}% + \skv@testoptb\skv@disablekeys +} \skvrobustdef*\skv@disablekeys#1{% - \skvcommaparse{#1}\skv@tempa{% - \skvifcsdefTF{\skv@header\skv@tempa.@cbk}{}{% - \skv@err{Key '\skv@tempa' is undefined: - \MessageBreak couldn't be disabled}\@ehd - }% - \skvifcsdefTF{\skv@header\skv@tempa.@defa}{% - \edef\skv@tempb{\noexpand\skv@ordkey{\skv@tempa}[]}% + \skvcommaparse{#1}\skv@prova{% + \skvifcsdefTF{\skv@header\skv@prova.@cbk}{% + \skvifcsdefTF{\skv@header\skv@prova.@defa}{% + \edef\skv@provb{\noexpand\skv@tempa{\skv@prova}[]}% + }{% + \edef\skv@provb{\noexpand\skv@tempa{\skv@prova}[^skv^]}% + }% + \expandafter\skv@provb\expandafter{\expandafter + \skv@disabledkeymsg\expandafter{\skv@prova}}% }{% - \edef\skv@tempb{\noexpand\skv@ordkey{\skv@tempa}}% + \skv@err{Key '\skv@prova' is undefined: + \MessageBreak couldn't be disabled}\skv@ehd }% - \expandafter\skv@tempb\expandafter{\expandafter\skv@disabledmsg - \expandafter{\skv@tempa}}% }% } @@ -3730,13 +4743,13 @@ % % \skvpresetkeys[<pref>]{<fam>}{<keys>} % \skvgpresetkeys[<pref>]{<fam>}{<keys>} -\skvrobustdef*\skvpresetkeys{\skv@testopt\skv@presetkeys\skv@defaultpref} +\skvrobustdef*\skvpresetkeys{\skv@testopt\skv@presetkeys\skvdefaultprefix} \skvrobustdef*\skv@presetkeys[#1]#2#3{\skvpreposetkeys[#1]{#2}{#3}{}} -\skvrobustdef*\skvgpresetkeys{\skv@testopt\skv@gpresetkeys\skv@defaultpref} +\skvrobustdef*\skvgpresetkeys{\skv@testopt\skv@gpresetkeys\skvdefaultprefix} \skvrobustdef*\skv@gpresetkeys[#1]#2#3{\skvgpreposetkeys[#1]{#2}{#3}{}} -\skvrobustdef*\skvpostsetkeys{\skv@testopt\skv@postsetkeys\skv@defaultpref} +\skvrobustdef*\skvpostsetkeys{\skv@testopt\skv@postsetkeys\skvdefaultprefix} \skvrobustdef*\skv@postsetkeys[#1]#2#3{\skvpreposetkeys[#1]{#2}{}{#3}} -\skvrobustdef*\skvgpostsetkeys{\skv@testopt\skv@gpostsetkeys\skv@defaultpref} +\skvrobustdef*\skvgpostsetkeys{\skv@testopt\skv@gpostsetkeys\skvdefaultprefix} \skvrobustdef*\skv@gpostsetkeys[#1]#2#3{\skvgpreposetkeys[#1]{#2}{}{#3}} \skvrobustdef*\skvpreposetkeys{\skv@clfalse\skv@testoptb\skv@preposetkeys} \skvrobustdef*\skvgpreposetkeys{\skv@cltrue\skv@testoptb\skv@preposetkeys} @@ -3745,10 +4758,10 @@ \skvifblankTF{#2}{}{\skv@pr@posetkeys{#2}{postset}}% } \skvrobustdef*\skv@pr@posetkeys#1#2{% - \skvifcsdefFT{\skv@header.@#2}{% + \skvifcsdefFT{\skvcurrentpath.@#2}{% \skvnormalize{csv}{,}{#1}\skv@tempa \ifskv@cl\expandafter\global\fi - \expandafter\def\csname\skv@header.@#2\expandafter + \expandafter\def\csname\skvcurrentpath.@#2\expandafter \endcsname\expandafter{\skv@tempa}% }{% % Don't change \skv@filtermergelist to \skvfiltermergelist: @@ -3765,12 +4778,11 @@ \skv@cltrue\skv@testoptb\skv@removepresetkeys } \skvrobustdef*\skv@removepresetkeys#1{% - \skvifcsdefTF{\skv@header.@preset}{% + \skvifcsdefTF{\skvcurrentpath.@preset}{% \expandafter\skv@filterremoveelements\csname\skv@header .@preset\endcsname{#1}\skv@getkeyname }{% - \skv@err{No preset keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skv@err{No preset keys defined for '\skvcurrentpath'}\skv@ehd }% } % \skvundefpresetkeys[<pref>]{<fam>} @@ -3781,12 +4793,11 @@ \skv@cltrue\skv@testoptb\skv@undefpresetkeys } \skvrobustdef*\skv@undefpresetkeys{% - \skvifcsdefFT{\skv@header.@preset}{% - \skv@err{No preset keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skvifcsdefFT{\skvcurrentpath.@preset}{% + \skv@err{No preset keys defined for '\skvcurrentpath'}\skv@ehd }{% \ifskv@cl\expandafter\global\fi - \skvcsundef{\skv@header.@preset}% + \skvcsundef{\skvcurrentpath.@preset}% }% } @@ -3799,12 +4810,11 @@ \skv@cltrue\skv@testoptb\skv@removepostsetkeys } \skvrobustdef*\skv@removepostsetkeys#1{% - \skvifcsdefTF{\skv@header.@postset}{% + \skvifcsdefTF{\skvcurrentpath.@postset}{% \expandafter\skv@filterremoveelements\csname\skv@header .@postset\endcsname{#1}\skv@getkeyname }{% - \skv@err{No postset keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skv@err{No postset keys defined for '\skvcurrentpath'}\skv@ehd }% } % \skvundefpostsetkeys[<pref>]{<fam>} @@ -3815,12 +4825,11 @@ \skv@cltrue\skv@testoptb\skv@undefpostsetkeys } \skvrobustdef*\skv@undefpostsetkeys{% - \skvifcsdefFT{\skv@header.@postset}{% - \skv@err{No postset keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skvifcsdefFT{\skvcurrentpath.@postset}{% + \skv@err{No postset keys defined for '\skvcurrentpath'}\skv@ehd }{% \ifskv@cl\expandafter\global\fi - \skvcsundef{\skv@header.@postset}% + \skvcsundef{\skvcurrentpath.@postset}% }% } @@ -3837,12 +4846,11 @@ \skv@r@movepreposetkeys{#2}{postset}% } \skvrobustdef*\skv@r@movepreposetkeys#1#2{% - \skvifcsdefTF{\skv@header.@#2}{% + \skvifcsdefTF{\skvcurrentpath.@#2}{% \expandafter\skv@filterremoveelements\csname\skv@header .@#2\endcsname{#1}\skv@getkeyname }{% - \skv@err{No preset keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skv@err{No preset keys defined for '\skvcurrentpath'}\skv@ehd }% } % \skvundefpreposetkeys[<pref>]{<fam>} @@ -3853,18 +4861,18 @@ \skv@cltrue\skv@testoptb\skv@undefpreposetkeys } \skvrobustdef*\skv@undefpreposetkeys{% - \skvifcsdefFT{\skv@header.@preset}{% - \skv@err{No preset keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skvifcsdefFT{\skvcurrentpath.@preset}{% + \skv@err{No preset keys defined for '\skvcurrentpath'}\skv@ehd }{% \ifskv@cl\expandafter\global\fi - \skvcsundef{\skv@header.@preset}% + \skvcsundef{\skvcurrentpath.@preset}% \ifskv@cl\expandafter\global\fi - \skvcsundef{\skv@header.@postset}% + \skvcsundef{\skvcurrentpath.@postset}% }% } -%% Note about the absence of '(g)save-value-keys': +%% Note about the absence of \skvsavevaluekeys (save-value-keys): +% % All keys have their values saved in the macro '<header>.@value'. % The value can be accessed via \skvgetvalue of \skvconveyvalue. When % needed, the value can be taken outside a local group by using \global @@ -3878,9 +4886,9 @@ \skv@cltrue\skv@testoptb\skv@needvaluekeys } \skvrobustdef*\skv@needvaluekeys#1{% - \skvcommaparse{#1}\skv@tempa{% + \skvcommaparse{#1}\skv@prova{% \ifskv@cl\expandafter\global\fi - \skvcsdef{\skv@header\skv@tempa.@ndv}{}% + \skvcsdef{\skv@header\skv@prova.@ndv}{}% }% } % \skvremoveneedvaluekeys[<pref>]{<fam>}{<keys>} @@ -3891,9 +4899,9 @@ \skv@cltrue\skv@testoptb\skv@removeneedvaluekeys } \skvrobustdef*\skv@removeneedvaluekeys#1{% - \skvcommaparse{#1}\skv@tempa{% + \skvcommaparse{#1}\skv@prova{% \ifskv@cl\expandafter\global\fi - \skvcsundef{\skv@header\skv@tempa.@ndv}% + \skvcsundef{\skv@header\skv@prova.@ndv}% }% } @@ -3905,9 +4913,9 @@ \skv@cltrue\skv@testoptb\skv@forbidvaluekeys } \skvrobustdef*\skv@forbidvaluekeys#1{% - \skvcommaparse{#1}\skv@tempa{% + \skvcommaparse{#1}\skv@prova{% \ifskv@cl\expandafter\global\fi - \skvcsdef{\skv@header\skv@tempa.@fbv}{}% + \skvcsdef{\skv@header\skv@prova.@fbv}{}% }% } % \skvremoveforbidvaluekeys[<pref>]{<fam>}{<keys>} @@ -3918,12 +4926,51 @@ \skv@cltrue\skv@testoptb\skv@removeforbidvaluekeys } \skvrobustdef*\skv@removeforbidvaluekeys#1{% - \skvcommaparse{#1}\skv@tempa{% + \skvcommaparse{#1}\skv@prova{% \ifskv@cl\expandafter\global\fi - \skvcsundef{\skv@header\skv@tempa.@fbv}% + \skvcsundef{\skv@header\skv@prova.@fbv}% + }% +} +% \skvoptionkeys[<pref>]{<fam>}{<keys>} +\skvrobustdef*\skvoptionkeys{% + \skv@clfalse\skv@testoptb{\skv@optionkeys{}}% +} +\skvrobustdef*\skvgoptionkeys{% + \skv@cltrue\skv@testoptb{\skv@optionkeys{}}% +} +% \skvnonoptionkeys[<pref>]{<fam>}{<keys>} +\skvrobustdef*\skvnonoptionkeys{% + \skv@clfalse\skv@testoptb{\skv@optionkeys{non}}% +} +\skvrobustdef*\skvgnonoptionkeys{% + \skv@cltrue\skv@testoptb{\skv@optionkeys{non}}% +} +\skvrobustdef*\skv@optionkeys#1#2{% + \skvcommaparse{#2}\skv@prova{% + \ifskv@cl\expandafter\global\fi + \skvcsdef{\skv@header\skv@prova.@#1opt}{}% + }% +} +% \skvremoveoptionkeys[<pref>]{<fam>}{<keys>} +\skvrobustdef*\skvremoveoptionkeys{% + \skv@clfalse\skv@testoptb{\skv@removeoptionkeys{}}% +} +\skvrobustdef*\skvgremoveoptionkeys{% + \skv@cltrue\skv@testoptb{\skv@removeoptionkeys{}}% +} +% \skvremovenonoptionkeys[<pref>]{<fam>}{<keys>} +\skvrobustdef*\skvremovenonoptionkeys{% + \skv@clfalse\skv@testoptb{\skv@removenonoptionkeys{non}}% +} +\skvrobustdef*\skvgremovenonoptionkeys{% + \skv@cltrue\skv@testoptb{\skv@removenonoptionkeys{non}}% +} +\skvrobustdef*\skv@removeoptionkeys#1#2{% + \skvcommaparse{#2}\skv@prova{% + \ifskv@cl\expandafter\global\fi + \skvcsundef{\skv@header\skv@prova.@#1opt}% }% } - % Save the default/initial values of keys: % \skvsaveinitialvaluekeys[<pref>]{<fam>}{<keys>} \skvrobustdef*\skvsaveinitialvaluekeys{% @@ -3934,14 +4981,14 @@ \skv@cltrue\skv@testoptb\skv@saveinitialvaluekeys } \skvrobustdef*\skv@saveinitialvaluekeys#1{% - \skvifcsdefFT{\skv@header.@needini}{% + \skvifcsdefFT{\skvcurrentpath.@needini}{% \edef\skv@tempa{\unexpanded{#1}}% \skvcsvnormalize\skv@tempa \ifskv@cl\expandafter\global\fi - \skvcsedef{\skv@header.@needini}{\skvexpandonce\skv@tempa}% + \skvcsedef{\skvcurrentpath.@needini}{\skvexpandonce\skv@tempa}% }{% \expandafter\skv@filtermergelist\csname - \skv@header.@needini\endcsname{#1}\skv@getkeyname + \skvcurrentpath.@needini\endcsname{#1}\skv@getkeyname }% } % \skvremovesaveinitialvaluekeys[<pref>]{<fam>}{<keys>} @@ -3953,12 +5000,11 @@ \skv@cltrue\skv@testoptb\skv@removesaveinitialvaluekeys } \skvrobustdef*\skv@removesaveinitialvaluekeys#1{% - \skvifcsdefFT{\skv@header.@needini}{% - \skv@err{No save-initial keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skvifcsdefFT{\skvcurrentpath.@needini}{% + \skv@err{No save-initial keys defined for '\skvcurrentpath'}\skv@ehd }{% \expandafter\skv@filterremoveelements\csname - \skv@header.@needini\endcsname{#1}\skv@getkeyname + \skvcurrentpath.@needini\endcsname{#1}\skv@getkeyname }% } % \skvundefsaveinitialvaluekeys[<pref>]{<fam>} @@ -3970,11 +5016,10 @@ \skv@cltrue\skv@testoptb\skv@undefsaveinitialvaluekeys } \skvrobustdef*\skv@undefsaveinitialvaluekeys{% - \skvifcsdefFT{\skv@header.@needini}{% - \skv@err{No save-initial keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skvifcsdefFT{\skvcurrentpath.@needini}{% + \skv@err{No save-initial keys defined for '\skvcurrentpath'}\skv@ehd }{% - \csname skv\ifskv@cl g\fi csundef\endcsname{\skv@header.@needini}% + \csname skv\ifskv@cl g\fi csundef\endcsname{\skvcurrentpath.@needini}% }% } @@ -3983,14 +5028,14 @@ \skvrobustdef*\skvignorekeys{\skv@clfalse\skv@testoptb\skv@ignorekeys} \skvrobustdef*\skvgignorekeys{\skv@cltrue\skv@testoptb\skv@ignorekeys} \skvrobustdef*\skv@ignorekeys#1{% - \skvifcsdefTF{\skv@header.@ignoredkeys}{% + \skvifcsdefTF{\skvcurrentpath.@ignoredkeys}{% \expandafter\skv@filtermergelist\csname - \skv@header.@ignoredkeys\endcsname{#1}\skv@getkeyname + \skvcurrentpath.@ignoredkeys\endcsname{#1}\skv@getkeyname }{% \edef\skv@tempa{\unexpanded{#1}}% \skvcsvnormalize[,]\skv@tempa \ifskv@cl\expandafter\global\fi - \skvcsedef{\skv@header.@ignoredkeys}{\skvexpandonce\skv@tempa}% + \skvcsedef{\skvcurrentpath.@ignoredkeys}{\skvexpandonce\skv@tempa}% }% } % \skvremoveignorekeys[<pref>]{<fam>}{<keys>} @@ -4002,12 +5047,11 @@ \skv@cltrue\skv@testoptb\skv@removeignorekeys } \skvrobustdef*\skv@removeignorekeys#1{% - \skvifcsdefFT{\skv@header.@ignoredkeys}{% - \skv@err{No ignore keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skvifcsdefFT{\skvcurrentpath.@ignoredkeys}{% + \skv@err{No ignore keys defined for '\skvcurrentpath'}\skv@ehd }{% \expandafter\skv@filterremoveelements\csname - \skv@header.@ignoredkeys\endcsname{#1}\skv@getkeyname + \skvcurrentpath.@ignoredkeys\endcsname{#1}\skv@getkeyname }% } % \skvundefignorekeys[<pref>]{<fam>} @@ -4019,22 +5063,16 @@ \skv@cltrue\skv@testoptb\skv@undefignorekeys } \skvrobustdef*\skv@undefignorekeys{% - \skvifcsdefFT{\skv@header.@ignoredkeys}{% - \skv@err{No ignore keys defined for - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \skvifcsdefFT{\skvcurrentpath.@ignoredkeys}{% + \skv@err{No ignore keys defined for '\skvcurrentpath'}\skv@ehd }{% \csname skv\ifskv@cl g\fi csundef\endcsname - {\skv@header.@ignoredkeys}% + {\skvcurrentpath.@ignoredkeys}% }% } - -% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -% To add (2012/08/08): -% \skvoptionkeys -% \skvnotoptionkeys -% \skvnewlet\skvnonoptionkeys\skvnotoptionkeys -%--------------------------------------------------------------- - +% +% Adding to the callback of existing keys. +% % \skvaddkeycode[<pref>]{<fam>}{<key>}{<precode>}{<postcode>} \skvrobustdef*\skvaddkeycode{\skv@testoptb\skv@addkeycode} \skvrobustdef*\skv@addkeycode#1#2#3{% @@ -4063,251 +5101,263 @@ \skvcsedef{\skv@header\skvcurrentkey.@cbk}{\skvtrimspace{#3}}% }% } - -% Initialize remaining-keys to empty, for the listed prefixes and families: -% \skvinitializermkeys{<prefixes>}{<families>} -\skvrobustdef*\skvinitializermkeys{% - \skv@clfalse\skv@testst\skv@initializermkeys -} -\skvrobustdef*\skvginitializermkeys{% - \skv@cltrue\skv@testst\skv@initializermkeys -} -\skvrobustdef*\skv@initializermkeys#1#2{% - \skv@usetempst{#1}\skv@tempa - \skv@usetempst{#2}\skv@tempb - \skvcommaparse*\skv@tempa\skv@tempa{% - \skv@makeprefix\skv@tempa - \skvcommaparse*\skv@tempb\skv@tempb{% - \skv@makeheader\skv@tempb - \skvcslet{\skv@header.@rmkeys}\@empty - \ifskv@cl\skvglobalizecs{\skv@header.@rmkeys}\fi - }% - }% -} - -% \skvgetrmkeys[<pref>]{<fam>}<cmd> -\skvrobustdef*\skvgetrmkeys{\skv@clfalse\skv@testoptb\skv@getrmkeys} -\skvrobustdef*\skvggetrmkeys{\skv@cltrue\skv@testoptb\skv@getrmkeys} -\skvrobustdef*\skv@getrmkeys#1{% - \skvifcsdefTF{\skv@header.@rmkeys}{% - \skvletcs#1{\skv@header.@rmkeys}% - \ifskv@cl\global\let#1=#1\fi - }{% - \skv@err{No 'rmkeys' for family - '\skvcurrentprefix/\skvcurrentfamily'}\@ehd - }% -} \skvrobustdef*\skvsetkeys{% + \skv@viarootofsetkeystrue \skv@testopta{\skv@testoptc\skv@setkeys@a}% } -% \skv@setkeys@a[<ignore.list>]{<kvlist>} +\skvrobustdef*\skvsetrmkeys{% + \skv@viarootofsetkeystrue + \skv@testopta{\skv@testoptc\skv@setrmkeys}% +} +\skvrobustdef*\skv@setrmkeys[#1]{% + % Only one prefix is allowed here. \skv@testoptc has created + % \skvcurrentprefix and \skv@fams. + \skvifdefTF\skv@rmkeys{% + \skvexpbracenext{\skv@setkeys@a[#1]}\skv@rmkeys + }{}% +} +% \skv@setkeys@a[<ignored.list>]{<kvlist>} \skvrobustdef*\skv@setkeys@a[#1]#2{% % \skvexecuteoptions calls \skv@setkeys@a. So this is the place for % \skv@insettrue: \skv@insettrue % \skv@testoptc has created \skvcurrentprefix and \skv@fams. - \ifskv@intry\else\skvafterfi - \skv@getkeynames{#2}\skv@naa - \fi + \skvifdefboolTF{skv@intry}{}{% + \skv@getnamesofkeys{#2}\skv@currentnames + }% % Both #1 and #2 will be normalized in \skv@setkeys@b. \skv@setprepokeys{#1}{preset}% \skv@setkeys@b{#2}{#1}% \skv@setprepokeys{#1}{postset}% \ifnum\skv@setkeysdepth=\skvz@ \skv@insetfalse + \skv@viarootofsetkeysfalse \fi - % Don't set \let\CurrentOption\@empty here. + % Don't do \let\CurrentOption\@empty here. +} +\skvnewlet\skv@sav@setkeys@a\skv@setkeys@a +\skvrobustdef*\skv@badsetkeysinpreset[#1]#2{% + \skv@err{% + \noexpand\skvsetkeys or \noexpand\skvsetrmkeys can't be nested in a preset + \MessageBreak key's callback: this will cause a cyclic call + \MessageBreak to \noexpand\skvsetkeys or \noexpand\skvsetrmkeys + }\skv@ehd } \skvrobustdef*\skv@setprepokeys#1#2{% - \skv@prepotrue + \skv@inprepotrue + \let\skv@setkeys@a\skv@badsetkeysinpreset + % Preposet keys doesn't use \skv@fams in \skv@setkeys@d; it + % branches off to \skv@setkeys@e. Hence the following loop is in + % order. \skvecommaloop*\skv@fams\skvcurrentfamily{% \skv@makeheader\skvcurrentfamily - \skvifcsdefFT{\skv@header.@#2}{}{% - \skv@toksa\expandafter\expandafter\expandafter - {\csname\skv@header.@#2\endcsname}% - \skvexpandtwoargs\skv@setkeys@b{\the\skv@toksa}% - {\skvexpandonce\skv@naa\ifx\skv@naa\@empty\else,\fi - \unexpanded{#1}}% + \skvletcs\reserved@a{\skvcurrentpath.@#2}% + \skvifdefFT\reserved@a{}{% + \skvexpandtwoargs\skv@setkeys@b{\skvexpandonce\reserved@a}% + {\skvaddlist,\skv@currentnames\unexpanded{#1}}% }% }% - \skv@prepofalse + \let\skv@setkeys@a\skv@sav@setkeys@a + \skv@inprepofalse } - +% \skv@setkeys@b{<kvlist>}{<ignored.list>} +% % \skv@keydepth is called in places other than by \skvsetkeys. Hence we % need an independent \skv@setkeysdepth here. -% \skv@setkeys@b{<kvlist>}{<ignore.list>} +% \skvrobustdef*\skv@setkeys@b#1#2{% % \skv@setprepokeys calls \skv@setkeys@b. So this is the place to % advance \skv@setkeysdepth. \skvgadvanceno\skv@setkeysdepth\@ne - \ifskv@st - \ifnum\skv@setkeysdepth=\@ne - \skvinitializermkeys*\skvcurrentprefix\skv@fams - \fi - \fi \ifnum\skv@setkeysdepth>\skv@stackdepthlimit\relax \skv@err{\noexpand\skvsetkeys is nested too deeply. - \MessageBreak Maybe there has been infinite reentry}\@ehd + \MessageBreak Maybe there has been infinite reentry}\skv@ehd \fi % \skv@na can't be anywhere else, not in \skv@setkeys@a. \edef\skv@na{\unexpanded{#2}}% \skvifemptyTF\skv@na{}{\skvcsvnormalize\skv@na}% - \edef\skv@tempa{\unexpanded{#1}}% - \skvifemptyTF\skv@tempa{}{\skvkvnormalize\skv@tempa}% - \def\skv@setkeys@c##1={% - \skvxifinTF{(}{\detokenize{##1}}{% - \skvxifinTF{)}{\detokenize{##1}}{% + \skvkvparse{#1}\CurrentOption{% + \skv@processvalueaslistfalse + % Expand the key name twice, in case the key and its value + % are hidden in a macro. A maverick might do just that. + \expandafter\expandafter\expandafter + \skv@setkeys@c\CurrentOption=\skv@novalue=\skv@setkeys@nil + }% + \skvgadvanceno\skv@setkeysdepth\m@ne +} +\skvrobustdef*\skv@setkeys@c#1={% + \skvxifinTF{(}{\detokenize{#1}}{% + \skvxifinTF{)}{\detokenize{#1}}{% + % A pntkey can't carry pointers: + \edef\skvcurrentkey{\unexpanded{#1}}% + \let\skv@tkey\skvcurrentkey + \skv@strippointersfromkey*\skvcurrentkey + \skv@strippointersfromvalue*\skvcurrentkey + \ifx\skvcurrentvalue\skv@tkey + \skv@extractpntkey@atsetkey{#1}% \def\skv@ispntkey{00}% - \skv@extr@ctpntkey{##1}\skvcurrentkey\skvcurrentvalue \ifx\skvcurrentvalue\@empty \skvnovaluetrue \else \skvnovaluefalse \fi - }{% - \skv@err{Key value has '(' but no ')'} - {The value of a parenthesized key must have both opening - '(' and closing ')'}% - }% + \else + \skv@err{A parenthesized key can't have pointers}\skv@ehd + \fi }{% - \def\skv@ispntkey{01}% - \skv@g@tkeyname##1=\skv@nil\skvcurrentkey + \skv@err{Key value has '(' but no ')'} + {The value of a parenthesized key must have both opening + \MessageBreak parenthesis '(' and closing ')'.}% }% - \def\skv@prova####1=####2\skv@nil{% - \skvifcondTF\if\skv@ispntkey\fi{}{% - \edef\skvcurrentvalue{\skvexpandonce{\@gobble####1}}% - \ifx\skvcurrentvalue\skv@novaluetoks - \skvnovaluetrue - \def\skvcurrentvalue{}% - \else - \skvnovaluefalse - \fi - \skvexpbracenext\skvifbracedTF\skvcurrentvalue{% - \skvvaluebracedtrue - }{% - % Strip and use pointers from key value: - \skvexpbracenext\skv@strippointers\skvcurrentvalue - \skvcurrentvalue - }% + }{% + \def\skv@ispntkey{01}% + \skv@g@tkeyname#1=\skv@getname@nil\skvcurrentkey + }% + % ##1=value: + \def\skv@prova##1=##2\skv@setkeys@nil{% + \skvifplaswTF\skv@ispntkey{% + % \skv@extractpntkey@atsetkey would have extracted key name and + % value for the pntkey. + }{% + \edef\skvcurrentvalue{\skvexpandonce{\@gobble##1}}% + \ifx\skvcurrentvalue\skv@novaluetoks + \skvnovaluetrue + \def\skvcurrentvalue{}% + \else + \skvnovaluefalse + \fi + \skvexpbracenext\skvifbracedTF\skvcurrentvalue{% + \skvvaluebracedtrue + }{% + \skvvaluebracedfalse + \skv@strippointersfromvalue*\skvcurrentvalue }% - \ifx\skvcurrentkey\@empty - \ifx\skvcurrentvalue\@empty\else - \skv@err{Current key is nil, but you have a value for it: - \MessageBreak\skvoxdetok\skvcurrentvalue}\@ehd - \fi + }% + \ifx\skvcurrentkey\@empty + \ifx\skvcurrentvalue\@empty\else + \skv@err{Current key is nil, but you have a value for it: + \MessageBreak\skvoxdetok\skvcurrentvalue}\skv@ehd \fi + \fi + \skvifdefboolTF{skv@processvalueaslist}{% + % You can use the pointer '.process list' on the current value to + % signify that the value be processed as a list, in the + % manner of a list key. This scheme is costlier than defining the + % key as a listkey, using \skvlistkey, but it is more versatile. + % This allows any key to accept and process a value that is a list, + % irrespective of its argument pattern. + \skv@processvalueaslist + }{% \edef\CurrentOption{% \skvcurrentkey - \ifx\skvcurrentvalue\@empty\else\skvafterfi - =\skvxonce\skvcurrentvalue - \fi + \ifx\skvcurrentvalue\@empty\else=\skvxonce\skvcurrentvalue\fi }% \skv@setkeys@d }% - \skv@prova.% }% - \skvcommaloop*\skv@tempa\CurrentOption{% - \skvvaluebracedfalse - % Expand the key name twice, in case the key and its value - % are hidden in a macro. A maverick might do just that. - \expandafter\expandafter\expandafter - \skv@setkeys@c\CurrentOption=\skv@novalue=\skv@nil + \skv@prova.% +} +\skvrobustdef*\skv@processvalueaslist{% + \skvpushstate\skv@keystate\skv@keydepth + \skvifemptyTF\skvcurrentvalue{% + \let\CurrentOption\skvcurrentkey + \skv@setkeys@d + }{% + \skvcommaparse*\skvcurrentvalue\skvcurrentvalue{% + \edef\CurrentOption{% + \skvcurrentkey + \ifx\skvcurrentvalue\@empty\else=\skvxonce\skvcurrentvalue\fi + }% + \skv@setkeys@d + }% }% - \skvgadvanceno\skv@setkeysdepth\m@ne + \skvpopstate\skv@keystate\skv@keydepth } - \skvrobustdef*\skv@setkeys@d{% - \skv@cnta\@ne - \skvletcs\skv@tempa{\skv@header.@ignoredkeys}% + \begingroup + \skv@swatrue + \skvxifinTF{,\skvcurrentkey,}{,\skv@na,}{\skv@swafalse}{}% + \skvletcs\skv@tempa{\skvcurrentpath.@ignoredkeys}% \skvifdefTF\skv@tempa{% - \skvxifinTF{,\skvcurrentkey,}{,\skv@tempa,}{% - \skv@cnta\skvz@ - }{% - \skvxifinTF{,\skvcurrentkey,}{,\skv@na,}{\skv@cnta\skvz@}{}% - }% - }{% - \skvxifinTF{,\skvcurrentkey,}{,\skv@na,}{\skv@cnta\skvz@}{}% - }% - \skvifnumTF\skv@cnta=\skvz@{}{% + \skvxifinTF{,\skvcurrentkey,}{,\skv@tempa,}{\skv@swafalse}{}% + }{}% + \skvaftergroupifboolFT skv@swa\endgroup{}{% \skv@kffalse - \skvifdefboolTF{skv@prepo}{% + \skvifdefboolTF{skv@inprepo}{% \skv@setkeys@e }{% - \skvifdefboolTF{skv@intry}{% - \skv@setkeys@e + \skvifdefboolTF{skv@pl}{% + % Set the key in all families in which it exists. + \skvecommaloop*\skv@fams\skvcurrentfamily{% + \skv@makeheader\skvcurrentfamily + \skv@setkeys@e + }% }{% - \skvifdefboolTF{skv@pl}{% - \skvecommaloop*\skv@fams\skvcurrentfamily{% - \skv@makeheader\skvcurrentfamily - \skv@setkeys@e - % If we don't save rm keys here, the family may change before - % we get to the next call of \skv@setkeys@f: - \ifskv@kf\else - \ifskv@st - \expandafter\expandafter\expandafter\skv@setkeys@f - \fi - \fi - }% - }{% - \skvcommaloop*\skv@fams\skvcurrentfamily{% - \skv@makeheader\skvcurrentfamily - \skv@setkeys@e - \ifskv@kf\skvbreakloop\fi - }% + % Stop searching as soon as the key is found in one family. + \skvcommaloop*\skv@fams\skvcurrentfamily{% + \skv@makeheader\skvcurrentfamily + \skv@setkeys@e + \ifskv@kf\skvbreakloop\fi }% }% }% \skvifdefboolTF{skv@kf}{% \skvifdefboolTF{skv@inpox}{% - \ifx\skv@userclassorpackage\skv@documentclass\skvafterfi - \expandafter\skv@useoption\expandafter{\CurrentOption}% + \ifskv@inclass\skvafterfi + \expandafter\skv@removeoption\expandafter{\CurrentOption}% \fi }{}% }{% \skvifdefboolTF{skv@inpox}{% - \skvifcsdefTF{\skv@header.@famhandler}{% + \skvifcsdefTF{\skvcurrentpath.@famhandler}{% \begingroup \let\elt\skvexpandonce \skvexpanded{\endgroup - \skvnoexpandcs{\skv@header.@famhandler}% + \skvnoexpandcs{\skvcurrentpath.@famhandler}% {\elt\skvcurrentprefix}{\elt\skvcurrentfamily}% {\elt\skvcurrentkey}{\elt\skvcurrentvalue}% }% }{% - \skvifcsdefTF{skv@dox@\@currname @\@currext}{% - \skvcsuse{skv@dox@\@currname @\@currext}% + \skvifcsdefTF{skv@dox@\@currname.\@currext}{% + \skvcsuse{skv@dox@\@currname.\@currext}% }{% - \ifx\@currext\@clsextension\else\skvafterfi - \let\CurrentOption\skvcurrentkey\@unknownoptionerror + \ifx\@currext\@clsextension\else + \skv@err{% + Unknown option '\skvcurrentfullkey' + \MessageBreak for \@cls@pkg\space'\@currname' + }{% + The option '\skvcurrentfullkey' + \MessageBreak was not declared in \@cls@pkg\space'\@currname'. + \MessageBreak Perhaps you misspelled its name. + \MessageBreak Try typing <return> to proceed. + }% \fi }% }% }{% - \skvifdefboolTF{skv@intry}{% - % Continue in remaining families. When all the families have - % been searched and the key isn't found, toggle 'intry' false - % and raise error. + \skvifdefboolTF{skv@st}{% + \skv@setkeys@f }{% - \skvifdefboolTF{skv@st}{% - \ifskv@pl - % In this case we've already saved any rm keys. - \relax + \skvifcsdefTF{\skvcurrentpath.@famhandler}{% + \begingroup + \let\elt\skvexpandonce + \skvexpanded{\endgroup + \skvnoexpandcs{\skvcurrentpath.@famhandler}% + {\elt\skvcurrentprefix}{\elt\skvcurrentfamily}% + {\elt\skvcurrentkey}{\elt\skvcurrentvalue}% + }% + }{% + % \ifskv@viarootofsetkeys is true, then \skvsetkeys is nested + % in the callback of a .try key. In that case, throw the exception: + \ifskv@intry + \ifskv@viarootofsetkeys + \skv@err{Key '\skvcurrentfullkey' + \MessageBreak is undefined}\skv@ehd + \fi \else - \expandafter\skv@setkeys@f + \skv@err{Key '\skvcurrentfullkey' + \MessageBreak is undefined}\skv@ehd \fi - }{% - \skvifcsdefTF{\skv@header.@famhandler}{% - \begingroup - \let\elt\skvexpandonce - \skvexpanded{\endgroup - \skvnoexpandcs{\skv@header.@famhandler}% - {\elt\skvcurrentprefix}{\elt\skvcurrentfamily}% - {\elt\skvcurrentkey}{\elt\skvcurrentvalue}% - }% - }{% - \skv@err{Key '\skvcurrenttriple' is undefined} - {I have come across an undefined key '\skvcurrentkey'.}% - }% }% }% }% @@ -4320,14 +5370,28 @@ }{% \skv@kftrue \ifskv@intry\skv@successtrue\fi + \ifskv@inpox + \skvifcsname\skv@header\skvcurrentkey.@nonopt\then + \skv@err{Key '\skvcurrenttriple' + \MessageBreak is a non-option key but it has appeared + \MessageBreak as a class or package option}\skv@ehd + \fi + \else + \skvifcsname\skv@header\skvcurrentkey.@opt\then + \skv@err{Key '\skvcurrenttriple' + \MessageBreak is an option key but it has appeared + \MessageBreak outside class or package option list}\skv@ehd + \fi + \fi \ifskvnovalue \skvifcsdefTF{\skv@header\skvcurrentkey.@ndv}{% - \skv@err{Key '\skvcurrenttriple' requires - \MessageBreak a user value}{Key value needed.}% + \skv@err{Key '\skvcurrenttriple' + \MessageBreak requires a user value. + \MessageBreak Maybe it's a signal key}\skv@ehd }{% \skvifcsdefTF{\skv@header\skvcurrentkey.@defa}{% - \skv@getdefault\skvcurrentprefix\skvcurrentfamily\skvcurrentkey - \skvcurrentvalue + \skv@getdefault\skvcurrentprefix\skvcurrentfamily + \skvcurrentkey\skvcurrentvalue % Check if the default value is braced: \skvexpbracenext\skvifbracedFT\skvcurrentvalue{}{% \skvvaluebracedtrue @@ -4335,103 +5399,61 @@ }{% \skv@err{No value specified for key \MessageBreak'\skvcurrenttriple' - \MessageBreak and no default value}\@ehd + \MessageBreak and no default value}\skv@ehd }% }% \else \skvifcsdefTF{\skv@header\skvcurrentkey.@fbv}{% \skv@err{Key '\skvcurrenttriple' doesn't - \MessageBreak accept a user value}{Key value forbidden.}% + \MessageBreak accept a user value: key value forbidden.}\skv@ehd }{}% \fi \skvifemptyTF\skvcurrentvalue{}{% \expandafter\skv@replacepointers\expandafter{\skvcurrentvalue}% }% - % Use argument type to possibly expand the argument: - \def\do##1##2##3{% - \skvifcsdefTF{\skv@header\skvcurrentkey.@##1arg}{% - {\noexpand##2}% - {\skvexpandcsonce{\skv@header\skvcurrentkey.@##1arg}}% - }{% - ##3% - }% - }% - % Get key's argument and its expander type: - \edef\skv@prova{% - % This ordering is important: - \do{xx}{\@firstofone}{% - \do{x2}{\skvexpandtwice}{% - \do{x1}{\skvexpandonce}{% - \do{x0}{\unexpanded}{% - \do{}{\unexpanded}{{\noexpand\unexpanded}{####1}}% - }% - }% - }% - }% - }% - \def\skv@provb##1##2\skv@arg@nil{% - \edef\skv@temparg{\unexpanded{##2}}% - \skvstripouterbraces{2}\skv@temparg - % Apply expander ##1: - \edef\skvcurrentvalue{\expandafter##1\expandafter{\skvcurrentvalue}}% - % Strip outer braces of weird arguments, so that the argument can be - % grabbed by the, possibly multiparametered, callback function: - \ifx\skv@temparg\skv@simplearg\else\skvafterfi + \skvletcs\skv@callback{\skv@header\skvcurrentkey.@cbk}% + \skv@getargpattern + % 1. Strip outer braces of \skvcurrentvalue, so that the argument can be + % grabbed by the, possibly multi-parametered, callback function. + % 2. The argument has been obtained from possible explicit definition + % of the argument. But if the obtained argument is simple, then the + % argument in the key's call maybe more complex: + \ifx\skv@argpattern\skv@simplearg\else + \ifcsname\skv@header\skvcurrentkey.@listkey\endcsname + \skv@err{A listkey must have a one-parameter argument}\skv@ehd + \else \skvstripouterbraces{2}\skvcurrentvalue \skvvaluebracedfalse \fi - }% - \expandafter\skv@provb\skv@prova\skv@arg@nil + \fi \skvcslet{\skv@header\skvcurrentkey.@value}\skvcurrentvalue - \skvifcsdefTF{\skv@header\skvcurrentkey.@hp}{% - \skvexpanded{\skvcslet{\skvexpandcsonce - {\skv@header\skvcurrentkey.@hp}}}\skvcurrentvalue - }{}% \skvpushstate\skv@keystate\skv@keydepth - \skvletcs\skv@prova{\skv@header\skvcurrentkey.@cbk}% \expandafter\expandafter\expandafter\def\expandafter\expandafter - \expandafter\skv@tempcbk\expandafter\skv@temparg\expandafter - \skeyvaleov\expandafter{\skv@prova}% - \ifx\skv@temparg\skv@simplearg\skvafterelsei - \expandafter\skv@tempcbk\expandafter{\skvcurrentvalue}\skeyvaleov - \else\skvafterfi - \expandafter\skv@tempcbk\skvcurrentvalue\skeyvaleov - \fi + \expandafter\skv@prova\expandafter\skv@argpattern\expandafter + \skeyvaleov\expandafter{\skv@callback}% + \skvifxTF\skv@argpattern\skv@simplearg{% + \expandafter\skv@prova\expandafter{\skvcurrentvalue}\skeyvaleov + }{% + \expandafter\skv@prova\skvcurrentvalue\skeyvaleov + }% \skvpopstate\skv@keystate\skv@keydepth }% } % Save rm keys: \skvrobustdef*\skv@setkeys@f{% - \edef\skv@prova{% - \skvcurrentkey - \ifskvnovalue\else\skvafterfi - =\skvexpandonce\skvcurrentvalue - \fi - }% \skvexpanded{% - \skvmergelist\skvnoexpandcs{\skv@header.@rmkeys}% - {\skvexpandonce\skv@prova}% + \skvmergelist\noexpand\skv@rmkeys{\skvexpandonce\CurrentOption}% % The boolean \ifdirkeys@saveunknownkeys is, by default, false. % The default value of \dirkeys@unknownkeysmacro is \skvfaillist. - \ifdirkeys@saveunknownkeys - \skvmergelist\skvexpandonce\dirkeys@unknownkeysmacro - {{\skvcurrentprefix}/{\skvcurrentfamily}/% - {\skvexpandonce\skv@prova}}% + \ifindirectkeys + \ifdirkeys@saveunknownkeys + \skvmergelist\skvexpandonce\dirkeys@unknownkeysmacro + {{\skvcurrentprefix}/{\skvcurrentfamily}/% + {\skvexpandonce\CurrentOption}}% + \fi \fi }% } -\skvrobustdef*\skvsetrmkeys{\skv@testopta{\skv@testoptc\skv@setrmkeys}} -\skvrobustdef*\skv@setrmkeys[#1]{% - % Only one prefix is allowed. \skv@testoptc has created - % \skvcurrentprefix and \skv@fams. - \skvcommaloop*\skv@fams\skv@tempa{% - \skv@makeheader\skv@tempa - \skvletcs\skv@prova{\skv@header.@rmkeys}% - \skvifdefTF\skv@prova{% - \skvexpandbracenext{\skv@setkeys@a[#1]}\skv@prova - }{}% - }% -} % \skv@getdefault{<pref>}{<fam>}{<key>}{<return.macro>} \skvrobustdef*\skv@getdefault#1#2#3#4{% \begingroup @@ -4468,14 +5490,14 @@ % \skv@testoptc has created \skvcurrentprefix and \skv@fams. \skvcommaloop*\skv@fams\skv@tempa{% \skv@makeheader\skv@tempa - \skvletcs\skv@tempa{\skv@header.@inikv}% + \skvletcs\skv@tempa{\skvcurrentpath.@inikv}% \skvifdefFT\skv@tempa{% \skv@err{No 'save initial value' keys defined in family - \MessageBreak'\skvcurrentprefix/\skvcurrentfamily'}\@ehd + \MessageBreak'\skvcurrentpath'}\skv@ehd }{% - % '\skv@header.@poxkeys' is the list of keys that have been + % '\skvcurrentpath.@poxkeys' is the list of keys that have been % instantiated as current pacakge options. - \skvletcs\skv@tempc{\skv@header.@poxkeys}% + \skvletcs\skv@tempc{\skvcurrentpath.@poxkeys}% \skvifdefFT\skv@tempc{% \edef\skv@tempe{% \skvexpandonce\skv@tempe @@ -4486,11 +5508,10 @@ % Filter pox (instantiated package/article options) list members: \def\skv@tempd{}% \skvcommaloop*\skv@tempa\skv@tempa{% - \expandafter\skv@g@tkeyname\skv@tempa=\skv@nil\skv@tempb + \expandafter\skv@g@tkeyname\skv@tempa=\skv@getname@nil\skv@tempb \skvxifinTF{,\skvoxdetok\skv@tempb,}{,\skvoxdetok\skv@tempc,}{}{% \edef\skv@tempd{% - \skvexpandonce\skv@tempd\ifx\skv@tempd\@empty\else,\fi - \skvexpandonce\skv@tempa + \skvaddlist,\skv@tempd\skvexpandonce\skv@tempa }% }% }% @@ -4517,7 +5538,7 @@ % Examples: % % \skvdefinekeys*+[KVA]{fam1,fam2}[thp@]{% -% .initialize after define=true, +% .initialize keys after define=true, % .save initial values, % .prepend to every key name=X@, % .ord/{keya,keyb}/{default-a}, @@ -4542,64 +5563,75 @@ % they've been defined. Leave this as ordinary keys, not zbool keys, % since the key names contain dot (.). Zapping the spaces in the % key name will not lead to a boolean of the \ifhp@key: + \skvordkey[SKV]{definekeys}{.initialize}[true]{% \skvifboolvalT{#1}{% \csname skvdfk@initialize#1\endcsname }% } + % Save default values as a kv list in macro <header>.@needini: \skvordkey[SKV]{definekeys}{.save initial values}[true]{% \skvifboolvalT{#1}{% \csname skvdfk@saveinitialvalues#1\endcsname }% } -\skvrobustdef*\skvdfkinitialize{\skvdfk@initializetrue} -\skvrobustdef*\skvdfksaveinitialvalues{\skvdfk@saveinitialvaluestrue} -\skvrobustdef*\skvsetupdefinekeys#1{% - \skvsetkeys[SKV]{definekeys}{#1}% +\skvordkey[SKV]{definekeys}{.parser}[,]{% + \skvifntypeTF{#1}{% + \def\skvdfk@parser{#1}% + \skvstripouterbraces{2}\skvdfk@parser + }{% + \skv@err{Parser '#1' is invalid; must be a single character}\@ehd + }% } +\skvrobustdef*\skvsetdefinekeysparser{\def\skvdfk@parser} +\skvsetdefinekeysparser{,} +\skvrobustdef*\skvsetupdefinekeys#1{\skvsetkeys[SKV]{definekeys}{#1}} + \skvsetupdefinekeys{.initialize=false,.save initial values=false} -\skvrobustdef*\skvdfkkeytypelet#1{% +\skvrobustdef*\skvtypecastfordefinekeys#1{% + \begingroup + \def\skv@tempa{}% \skvkvparse{#1}\skv@prova{% - \skvexpbracenext\skv@kvsplit\skv@prova{% - \skvifcsdefTF{skvdfk@typealias@##1}{% - \skv@err{Key type alias '##1' already defined}\@ehd - }{% - \skvifstrcmpTF{##2}{^skv^}{% - \skv@err{Key type alias '##1' has no master}\@ehd + \skv@okvsplit\skv@prova{% + \def\skv@keytypecast####1{% + \skvifcsdefTF{skvdfk@typealias@####1}{% + \skv@err{Key type alias '####1' already defined}\skv@ehd }{% - \skvcsdef{skvdfk@typealias@##1}{##2}% + \skvifstrcmpTF{##2}{^skv^}{% + \skv@err{Key type alias '####1' has no master}\skv@ehd + }{% + \edef\skv@tempa{% + \skvexpandonce\skv@tempa + \skvcsdef{skvdfk@typealias@####1}{##2}% + }% + }% }% }% + \skvcommaparse{##1}\skv@prova{% + \expandafter\skv@keytypecast\expandafter{\skv@prova}% + }% }% }% + \expandafter\endgroup\skv@tempa } -\skvdfkkeytypelet{% - .singleton=.choice, +\skvtypecastfordefinekeys{% + {.singleton,.state pattern}=.choice, .exec code=.exec, - .arg=.argx0,.args=.argx0, - .arg expanded once=.argx1, - .arg expanded twice=.argx2, + {.arg,.args}=.argx0, + .arg expand once=.argx1, + .arg expand twice=.argx2, .arg expanded=.argxx, - .initialize keys after define=.initialize, - .initialize after define=.initialize, - .initialize keys=.initialize, - .save initial values=.saveini, - .save initial values of keys=.saveini, - .prepend to key name=.preptokey, - .prepend to every key name=.preptokey, - .append to key name=.apptokey, - .append to every key name=.apptokey, - .prepend to callback=.preptocode, - .prepend to every callback=.preptocode, - .append to callback=.apptocode, - .append to every callback=.apptocode, - .exec after define=.afterdef, - .after define=.afterdef, -} - -\skvnewdef*\skv@keyparser{,} + {.initialize keys after define,.initialize after define, + .initialize keys}=.initialize, + {.save initial values,.save initial values of keys}=.saveini, + {.prepend to key name,.prepend to every key name}=.preptokey, + {.append to key name,.append to every key name}=.apptokey, + {.prepend to callback,.prepend to every callback}=.preptocode, + {.append to callback,.append to every callback}=.apptocode, + {.exec after define,.after define}=.afterdef, +} \skvnewdef*\skvdfk@afterdefine@hook{} \skvrobustdef*\skvafterdefinekeys{% \skvgappendtomacro\skvdfk@afterdefine@hook @@ -4608,21 +5640,23 @@ \skvifstar{% \skv@sttrue \skvifplus - {\skv@pltrue\skvdfk@testoptb#1}{\skv@plfalse\skvdfk@testoptb#1}% + {\skv@pltrue\skvdfk@testoptb#1} + {\skv@plfalse\skvdfk@testoptb#1}% }{% \skv@stfalse \skvifplus - {\skv@pltrue\skvdfk@testoptb#1}{\skv@plfalse\skvdfk@testoptb#1}% + {\skv@pltrue\skvdfk@testoptb#1} + {\skv@plfalse\skvdfk@testoptb#1}% }% } \skvrobustdef*\skvdfk@testoptb#1{% - \skv@testopt{\skvdfk@t@stoptb{#1}}\skv@defaultpref + \skv@testopt{\skvdfk@t@stoptb{#1}}\skvdefaultprefix } \skvrobustdef*\skvdfk@t@stoptb#1[#2]#3{% \skvxifinTF{,}{\detokenize{#2}}{% \skv@err{Only one prefix is allowed when calling \MessageBreak \noexpand\skvdefinekeys or similar commands, - \MessageBreak but you gave '#2'}\@ehd + \MessageBreak but you gave '#2'}\skv@ehd }{% % The prefix and families here deserve separate names, to avoid % confusing them with those required for setting the keys of the @@ -4639,6 +5673,7 @@ \skv@testopt#1{userhp@}% }% } +\skvrobustdef*\skvedefinekeysifdefinable{\skvedefinekeys*} % \skvedefinekeys has no stack, since everything is done in a local group. % It is \skvmakekeys that has a stack. \skvrobustdef*\skvedefinekeys{% @@ -4660,13 +5695,13 @@ \def\iftypeis##1\then{% \ifnum\skv@strcmp{\skvoxdetok\skv@type}{\detokenize{##1}}=\skvz@ }% - \def\skv@prependtoeverykeyname{}% - \def\skv@appendtoeverykeyname{}% - \def\skv@prependtoeverycallback{}% - \def\skv@appendtoeverycallback{}% + \def\do##1{\def##1{}}% + \do\skv@prependtoeverykeyname\do\skv@appendtoeverykeyname + \do\skv@prependtoeverycallback\do\skv@appendtoeverycallback + % Take \skvindeftrue outside the current scope: + \def\skv@accumulateonfams{\skvindeftrue}% \edef\skv@hp{#1}% \skvdespacecontent\skv@hp - \def\skv@accumulateonfams{}% \skv@makeprefix\skvdfk@pref \edef\skvdfk@currlist{\skvkeepdoubleslashnormalize{#2}}% \def\skv@definekeys@b##1{% @@ -4697,21 +5732,23 @@ % 1. No need to reinitialize \skvdfk@afterdefine@hook here. Any changes % done within the exited group haven't survived outside the group. % 2. Don't call \skvdfk@initializefalse and \skvdfk@saveinitialvaluesfalse - % here while in \directkeys: this is reentered for each path. - \ifskvindirkeys\else + % here while in \directkeys: \skvdefinekeys is reentered for each path. + % \ifskvdfk@initialize and \ifskvdfk@saveinitialvalues are in the + % stack of \directkeys + \ifindirectkeys\else \skvdfk@initializefalse\skvdfk@saveinitialvaluesfalse \fi } \skvrobustdef*\skv@definekeys@c#1{% \edef\skv@igkeys{% - \skvifcsname\skv@header.@ignoredkeys\then - \skvexpandcsonce{\skv@header.@ignoredkeys}% + \skvifcsname\skvcurrentpath.@ignoredkeys\then + \skvexpandcsonce{\skvcurrentpath.@ignoredkeys}% \fi }% \def\skv@splita##1/##2/{\skv@splitb##1/##2/.}% \def\skv@splitb##1/##2/##3/##4/##5/##6/##7/##8/##9\skv@split@nil{% \skvxifinTF{\skv@hashchar}{\detokenize{##2}}{% - \skv@err{Key name(s) '\detokenize{##2}' contain hash character}\@ehd + \skv@err{Key name(s) '\detokenize{##2}' contain hash character}\skv@ehd }{% % In case we have, eg, .exec=\def\x{?} instead of .exec/\def\x{?}: \skvxifinTF{=}{\detokenize{##1}}{% @@ -4725,7 +5762,7 @@ }% }% \skvifcsname skvdfk@typealias@\skv@type\then - \edef\skv@type{\skvcsuse{skvdfk@typealias@\skv@type}}% + \edef\skv@type{\@nameuse{skvdfk@typealias@\skv@type}}% \fi \edef\skv@default{\skvexpandonce{\@gobble##3}}% % To avoid mixing parameter characters in \skv@prova: @@ -4741,13 +5778,13 @@ }{% \if\skv@checkkeyexist \skvifcsname\skv@header##2.@cbk\then - \skv@err{Key '\skvcurrenttriple' already exists}\@ehd + \skv@err{Key '\skvcurrenttriple' already exists}\skv@ehd \fi \fi \if\skv@ischoice \skv@ifcmdnut\skv@itemfour{% \skv@err{Empty nominations (state pattern) for - \MessageBreak choice key '##2'}\@ehd + \MessageBreak choice key '##2'}\skv@ehd }{}% \fi \edef\skvdfk@keys{\skvaddlist,\skvdfk@keys##2}% @@ -4805,7 +5842,7 @@ }% }% }% - \skvexpanded{\skvparselist{\skv@keyparser}}{#1}\skv@prova{% + \skvexpanded{\skvparselist{\skvdfk@parser}}{#1}\skv@prova{% \expandafter\skv@splita\skv@prova /^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^\skv@split@nil }% @@ -4832,7 +5869,7 @@ } \skvrobustdef*\skv@definekeys@d#1{% \skvxifinFT{,#1,}{,\skv@validtypes,}{% - \skv@err{Invalid key type '#1' in \string\skvdefinekeys}\@ehd + \skv@err{Invalid key type '#1' in \string\skvdefinekeys}\skv@ehd }{% \@tempswatrue \iftypeis.exec\then @@ -4897,9 +5934,8 @@ \do\skv@isboolorchoice\do\skv@ischoice\do\skv@needhp\do\skv@isarg \skvifinTF{,#1,}{,.choice,.choice*,}{% \skvstripouterbraces{2}\skv@default - \def\skv@ischoice{00}% - \def\skv@isboolorchoice{00}% - \def\skv@needhp{00}% + \def\do##1{\def##1{00}}% + \do\skv@ischoice\do\skv@isboolorchoice\do\skv@needhp }{% \skvifinTF{,#1,}{,.bool,.zbool,.tog,.ztog,}{% \def\skv@isboolorchoice{00}% @@ -4914,8 +5950,8 @@ }% }% }% - \skvcommaprocess*\skv@itemtwo\skv@tempa{% - \skvexpbracenext\skv@strippointers\skv@tempa\skvcurrentkey + \skvcommaloop*\skv@itemtwo\skv@tempa{% + \skv@strippointersfromkey*\skv@tempa \edef\skvcurrentkey{% \skv@prependtoeverykeyname\skvcurrentkey \skv@appendtoeverykeyname @@ -4930,14 +5966,14 @@ }% }% }{% - \skvifinFT{,#1,} - {,.preptokey,.apptokey,.preptocode,.apptocode,}{}{% + \skvifinFT{,#1,}{,.preptokey,.apptokey,.preptocode,.apptocode,}{}{% \let\skv@tempa\skv@itemtwo - \skvexpbracenext\skv@strippointers\skv@itemtwo\skv@itemtwo + \skv@strippointersfromkey*\skv@itemtwo + \let\skv@itemtwo\skvcurrentkey \ifx\skv@tempa\skv@itemtwo\else \skv@err{The token ||\skvoxdetok\skv@itemtwo|| \MessageBreak shouldn't contain pointers for the - given key type or requested action}\@ehd + given key type or requested action}\skv@ehd \fi }% }% @@ -4946,7 +5982,9 @@ % % Assigning arguments within \skvdefinekeys: % -% Eg, .arg/{key1,key2}/{#1/#2} +% Eg, using the type .arg: +% +% .arg/{key1,key2}/{#1/#2} % \skvrobustdef*\skvdfk@definearg#1#2#3{% \begingroup @@ -5000,23 +6038,23 @@ .ord/{.define in all families,.in all families}/true/ \edef\skvmk@inallfams{0\skvifstrcmpTF{#1}{true}{0}{1}} , - .ord/.prefix/\skv@defaultpref/ + .ord/.prefix/\skvdefaultprefix/ \skviflacus#1\then - \let\skvmk@pref\skv@defaultpref + \let\skvmk@pref\skvdefaultprefix \else \edef\skvmk@pref{#1}% \skvstripouterbraces{2}\skvmk@pref \fi , - .ord/{.holder prefix,.hp}/userhp@/\edef\skvmk@hp{#1}, - .ord/{.family,.families}/\@nil/ + .ord/{.family,.families}/\skv@nil/ \skviflacus#1\then - \skv@err{Key family is empty\on@line}\@ehd + \skv@err{Key family is empty\on@line}\skv@ehd \else \edef\skvmk@fams{#1}% \skvstripouterbraces{2}\skvmk@fams \fi , + .ord/{.holder prefix,.hp}/userhp@/\edef\skvmk@hp{#1} } % Default settings for keys of \skvmakekeys. Presetting keys will be @@ -5024,10 +6062,9 @@ % necessary to include all the complements in the preset list, but doing % this will be inefficient. \skvsetkeys[SKV]{makekeys}{% - .prefix,.family=^skv^,.hp,.new=false,.define in all families=false, + .prefix,.family,.hp,.new=false,.define in all families=false, .endlinechar=13,.initialize=false,.save initial values=false } - \skvrobustdef*\skvmakekeys{\skv@testopt\skv@makekeys{}} \skvrobustdef*\skv@makekeys[#1]#2{% \skvpushfunctions\skvmakekeys{% @@ -5036,8 +6073,8 @@ \do\ifskvdfk@saveinitialvalues }\skv@makekeysdepth \skvsetkeys[SKV]{makekeys}{#1}% - \ifx\skvmk@fams\@nnil - \skv@err{No family specified for \string\skvmakekeys}\@ehd + \ifx\skvmk@fams\skv@nnil + \skv@err{No family specified for \string\skvmakekeys}\skv@ehd \fi % The following \begingroup is ended in \skv@definekeys: \begingroup @@ -5060,7 +6097,7 @@ \skvrobustdef*\skv@getinnoval#1{% \begingroup - \skv@kvosplit{#1}{% + \skv@okvsplit{#1}{% \edef\skv@provb{\detokenize{##2}}% \skvifxTF\skv@provb\@empty{% \def\skv@ival{???}% @@ -5106,7 +6143,7 @@ % \skvsetkeys[KV]{fam}{unknownkey=val} % \skvrobustdef*\skvunknownkeyhandler{% - \skv@testopt\skv@unknownkeyhandler\skv@defaultpref + \skv@testopt\skv@unknownkeyhandler\skvdefaultprefix } % For each prefix and family, this will define the functions % \<prefix>/<family>/.@famhandler of 4 parameters (prefix, family, @@ -5116,7 +6153,7 @@ \skv@makeprefix\skv@tempa \skvcommaloop{#2}\skv@tempb{% \skv@makeheader\skv@tempb - \skvcsdef{\skv@header.@famhandler}##1##2##3##4{#3}% + \skvcsdef{\skvcurrentpath.@famhandler}##1##2##3##4{#3}% }% }% } @@ -5138,38 +6175,40 @@ .ord/{.set in all families,.in all families}/true/ \edef\skvuk@inallfams{\skvifstrcmpTF{#1}{true}{00}{01}} , - .ord/.prefix/\skv@defaultpref/ + .ord/.prefix/\skvdefaultprefix/ \skviflacus#1\then - \let\skvuk@pref\skv@defaultpref + \let\skvuk@pref\skvdefaultprefix \else \edef\skvuk@pref{#1}% \skvstripouterbraces{2}\skvuk@pref \fi , - .ord/{.family,.families}/\@nil/ + .ord/{.family,.families}/\skv@nil/ \skviflacus#1\then - \skv@err{Key family is empty\on@line}\@ehd + \skv@err{Key family is empty\on@line}\skv@ehd \else \edef\skvuk@fams{#1}% \skvstripouterbraces{2}\skvuk@fams \fi , - .ord/{.path,paths}/\@nil/ + .ord/{.path,paths}/\skv@nil/ \skvifblankTF{#1}{% - \skv@err{Key family is empty\on@line}\@ehd + \skv@err{Key family is empty\on@line}\skv@ehd }{% - \edef\skvuk@paths{#1}% - \skvstripouterbraces{2}\skvuk@paths - \skvexpbracenext\skv@slashsplit\skvuk@paths{% - \skvsetkeys[SKV]{usekeys}{.prefix=##1,.family=##2}% - }% + \edef\skv@tempa{#1}% + \ifx\skv@tempa\skv@nnil + \skv@err{No path specified for \string\skvusekeys}\skv@ehd + \else + \skvstripouterbraces{2}\skv@tempa + \skv@splitpath@a\skv@tempa\skvuk@pref\skvuk@fams + \fi }% , } % Default settings for keys of \skvusekeys: \skvsetkeys[SKV]{usekeys}{% - .prefix,.family=^skv^,.set in all families=false,.save rm=false% + .prefix,.family,.set in all families=false,.save rm=false% } \skvrobustdef*\skvusekeys{\skv@testopt\skv@usekeys{}} @@ -5178,8 +6217,8 @@ \do\skvuk@fams\do\skvuk@pref\do\skvuk@inallfams\do\skvuk@saverm }\skv@usekeysdepth \skvsetkeys[SKV]{usekeys}{#1}% - \ifx\skvuk@fams\@nnil - \skv@err{No family specified for \string\skvusekeys}\@ehd + \ifx\skvuk@fams\skv@nnil + \skv@err{No family specified for \string\skvusekeys}\skv@ehd \fi \skvexpanded{% \noexpand\skvsetkeys\if\skvuk@saverm*\fi\if\skvuk@inallfams+\fi @@ -5190,14 +6229,15 @@ %++++++++++ Utilities for handlers of the macro \directkeys +++++++++++% -\skvnewlet\handlereov\relax +\skvnewlet\skvhandlereov\relax % Undefine \dirkeys@handler@, in case a handler function is called % without the handler name. Handler functions usually require % 'dirkeys@handler@<handler.name>'. -\skvcsundef{dirkeys@handler@} +\skvundef\dirkeys@handler@ +\skvrobustdef*\skvsetdirectkeysparser{\def\dirkeys@parser} +\skvsetdirectkeysparser{,} \skvrobustdef*\directkeys{\skv@testst\skv@dirkeys@parse@a} -\skvnewlet\dirkeys\directkeys \skvrobustdef*\skv@dirkeys@parse@a{% \begingroup \ifskv@tempst\endlinechar\m@ne\fi @@ -5206,121 +6246,121 @@ \skvrobustdef*\skv@dirkeys@parse@b#1{% \endgroup \skvpushstate\skv@dirkeys@state\dirkeys@depth - \skvindirkeystrue - % Note 1: Initialise all lists to empty. This note is referred to - % somewhere: don't delete its number. - \def\dirkeys@prefixlist{}% - \def\dirkeys@familylist{}% + \indirectkeystrue + \def\dirkeys@pathlist{}% \def\dirkeys@holderprefixtoks{}% \dirkeys@saveunknownkeysfalse \skvdfk@initializefalse \skvdfk@saveinitialvaluesfalse \edef\skv@tempa{\unexpanded{#1}}% \skvstripouterbraces{2}\skv@tempa + % Normalize with respect to equality (=) and comma (,), since + % \skvkvnormalize can't normalize with respect to \dirkeys@parser + % that isn't comma (,). \skvparselist will normalize with respect + % to \dirkeys@parser: \skvkvnormalize\skv@tempa \def\skv@dirkeys@split##1=##2=##3\dirkeys@nil{% \edef\skv@tempa{\unexpanded{##2}}% \skvstripouterbraces{2}\skv@tempa \skvdespacecontent\skv@tempa - % Get the first token, to test if it's \dirkeys. If it is, then + % Get the first token, to test if it's \directkeys. If it is, then % we have a nested \dirkeys: - \expandafter\skvifxTF\skv@car##1x\car@nil\dirkeys{% + \expandafter\skvifxTF\skv@car##1x\car@nil\directkeys{% \skvifemptyTF\skv@tempa{% ##1\relax }{% \skv@err{Something wrong with use of \string\dirkeys: - \MessageBreak equals ('=') found after \string\dirkeys}\@ehd + \MessageBreak equals ('=') found after \string\dirkeys}\skv@ehd }% }{% \skv@ensurehandlerdot{##1}% \skvifcsdefTF{dirkeys@handler@##1}{% \csname dirkeys@handler@##1\expandafter\endcsname - \skv@tempa\handlereov + \skv@tempa\skvhandlereov }{% - \skv@err{Unknown handler '\detokenize{##1}'\MessageBreak - in command \string\dirkeys, or no '=' sign}\@ehd + \skv@err{Unknown handler '\detokenize{##1}' + \MessageBreak in command \string\directkeys, or no '=' sign + \MessageBreak after handler name}\skv@ehd }% }% }% - \skvexpanded{\skvdolist*{\skv@keyparser}}\skv@tempa\skv@tempa{% + % Normalize with respect to \dirkeys@parser: + \skvexpanded{\skvparselist*{\dirkeys@parser}}\skv@tempa\skv@tempa{% \expandafter\skv@dirkeys@split\skv@tempa==\dirkeys@nil }% - \skvindirkeysfalse + \indirectkeysfalse \skvpopstate\skv@dirkeys@state\dirkeys@depth } -\skvrobustdef*\dirkeys@setdefaultroot{% - \ifx\dirkeys@familylist\@empty +\skvrobustdef*\dirkeys@setdefaultpath{% + \ifx\dirkeys@pathlist\@empty \ifskv@inopt - \edef\dirkeys@familylist{\@currname.\@currext}% + \edef\dirkeys@pathlist{% + \noexpand\skv@pathdo{KV}{\@currname.\@currext}% + }% \else - \skv@err{No key's family can be empty}\@ehd + \skv@err{No key can have empty or nil path/family}\skv@ehd \fi \fi - \ifx\dirkeys@prefixlist\@empty - \let\dirkeys@prefixlist\skv@defaultpref - \fi \ifx\dirkeys@holderprefixtoks\@empty \def\dirkeys@holderprefixtoks{user@}% \fi } -\skvrobustdef*\dirkeys@getrootlist{% - \def\skv@rootlist{}% - \def\do##1##2{% - \edef\skv@rootlist{% - \skvexpandonce\skv@rootlist - \noexpand\skv@doonroot{##1}{##2}% - }% - }% - \dirkeys@getcurrentroots\do +\skvnewnumbers[skv@]{pathdepth} +\skvrobustdef*\skv@pushpathdo{% + \edef\skv@pathdepth{\the\numexpr\skv@pathdepth+1}% + \skvcslet{skv@pathdo@\romannumeral\skv@pathdepth}\skv@pathdo +} +\skvrobustdef*\skv@poppathdo{% + \skvletcs\skv@pathdo{skv@pathdo@\romannumeral\skv@pathdepth}% + \edef\skv@pathdepth{\the\numexpr\skv@pathdepth-1}% } -\skvrobustdef*\dirkeys@getcurrentroots#1{% +\skvrobustdef*\dirkeys@dodefinekeys#1#2{% \begingroup - \dirkeys@setdefaultroot + % #2 may contain parameter characters that may be confused with + % ##1 and ##2 below. Hence we put it in the macro \skv@tempb. + % Note: Ignored keys are omitted by \skvdefinekeys. + \edef\skv@tempb{\unexpanded{#2}}% \def\skv@tempa{}% - \skvcommaloop*\dirkeys@prefixlist\skv@prova{% - \skvcommaloop*\dirkeys@familylist\skv@provb{% - \edef\skv@tempa{\skvexpandonce\skv@tempa - \unexpanded{#1}{\skv@prova}{\skv@provb}}% + \def\skv@pathdo##1##2{% + \edef\skv@tempa{% + \skvexpandonce\skv@tempa + \skvdefinekeys#1[##1]{##2}% + [\dirkeys@holderprefixtoks]{\skvexpandonce\skv@tempb}% }% }% + \dirkeys@pathlist \expandafter\endgroup\skv@tempa } - -\skvrobustdef*\dirkeys@dodefinekeys#1{% +% \dirkeys@definetypekeys{<type>}{<star.or.empty>}{<keylist>} +\skvrobustdef*\dirkeys@definetypekeys#1#2#3{% \begingroup - % #1 may contain parameter characters that may be confused with - % ##1 and ##2 below. Hence we put it in the macro \skv@tempb. - % Note: Ignored keys are omitted by \skvdefinekeys. - \edef\skv@tempb{\unexpanded{#1}}% \def\skv@tempa{}% - \def\do##1##2{% + \skvexpanded{\skvparselist{\skvdfk@parser}}{#3}\skv@prova{% \edef\skv@tempa{% \skvexpandonce\skv@tempa - \skvdefinekeys\ifskv@handlerswa*\fi[##1]{##2}% - [\dirkeys@holderprefixtoks]{\skvexpandonce\skv@tempb}% + \ifx\skv@tempa\@empty\else\skvdfk@parser\fi + .#1/\skvexpandonce\skv@prova }% }% - \dirkeys@getcurrentroots\do - \expandafter\endgroup\skv@tempa + \skvexpanded{\endgroup + \dirkeys@dodefinekeys{#2}{\skvexpandonce\skv@tempa}% + }% } -\skvrobustdef*\dirkeys@dosetkeys#1#2{% +\skvrobustdef*\dirkeys@setkeys#1#2#3#4{% \begingroup % #1 may contain parameter characters that may be confused with % ##1 and ##2 below. Hence we put it in the macro \skv@tempb: - \edef\skv@tempb{\unexpanded{#1}}% + \edef\skv@tempb{\unexpanded{#4}}% \def\skv@tempa{}% - \def\do##1##2{% + \def\skv@pathdo##1##2{% \edef\skv@tempa{% \skvexpandonce\skv@tempa - #2\ifdirkeys@saveunknownkeys*\else\ifskv@handlerswa*\fi\fi + #3\ifdirkeys@saveunknownkeys*\else#1\fi [##1]{##2}[\skvcsuse{##1/##2/.@ignoredkeys}]% - % #1 may contain unbalanced conditionals; hence the need for - % \skvifdefboolTF here. When setting 'rm keys', then no - % key list is needed here. - \skvifdefboolTF{skv@handlerswb}{}{{\skvexpandonce\skv@tempb}}% + \skvifstrcmpTF{#2}{rm}{}{{\skvexpandonce\skv@tempb}}% }% }% - \dirkeys@getcurrentroots\do + \dirkeys@pathlist \expandafter\endgroup\skv@tempa } @@ -5330,16 +6370,13 @@ \begingroup \def\skv@tempd{}% % ##1=prefix, ##2=family - \def\do##1##2{% + \def\skv@pathdo##1##2{% \def\skv@tempb{}% \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% \skvcommaparse{#1}\skv@tempa{% \skvxifinTF{,\skvoxdetok\skv@tempa,}{,\skvoxdetok\skv@igkeys,}{}{% - \edef\skv@tempb{% - \skvexpandonce\skv@tempb\ifx\skv@tempb\@empty\else,\fi - \skvexpandonce\skv@tempa - }% + \edef\skv@tempb{\skvaddlist,\skv@tempb\skvexpandonce\skv@tempa}% }% }% \edef\skv@tempd{% @@ -5349,47 +6386,30 @@ }% }% }% - \dirkeys@getcurrentroots\do + \dirkeys@pathlist \expandafter\endgroup\skv@tempd } % \dirkeys@dolistedkeys@b{<callback>} \skvrobustdef*\dirkeys@dolistedkeys@b#1{% \begingroup - % ##1=prefix, ##2=family \def\skv@tempa{}% - \def\do##1##2{% + % ##1=prefix, ##2=family + \def\skv@pathdo##1##2{% \edef\skv@tempa{% \skvexpandonce\skv@tempa \unexpanded{\skv@makeprefix{##1}\skv@makeheader{##2}#1}% }% }% - \dirkeys@getcurrentroots\do + \dirkeys@pathlist \expandafter\endgroup\skv@tempa } -\skvrobustdef*\skv@getexpander#1{% - \begingroup - \edef\skv@prova{\skvtrimspace{#1}}% - \def\skv@provb##1{% - \def\skv@provb####1##1####2####3\skv@nil{% - \endgroup - % Don't use \let for the next definition: - \def\skvexpander{####2}% - \ifx\skvexpander\@nnil - \skv@err{Unknown expansion type '\detokenize{##1}'}\@ehd - \fi - }% - \skv@provb x0{\unexpanded}x1{\skvexpandonce}x2{\skvexpandtwice}% - xx{\@iden}##1{\@nil}\skv@nil - }% - \expandafter\skv@provb\expandafter{\skv@prova}% -} \skvrobustdef*\skv@getmaintoks#1#2{% \def\skv@prova##1#2##2#2##3\skv@nil{% \edef\skvcurrentmaintoks{\skvtrimspace{##1}}% \skvstripouterbraces{2}\skvcurrentmaintoks \ifx\skvcurrentmaintoks\@empty - \skv@err{No main key in '\detokenize{#1}'}\@ehd + \skv@err{No main key in '\detokenize{#1}'}\skv@ehd \fi \edef\skvcurrentsub{\unexpanded{##2}}% \ifx\skvcurrentsub\skv@novaluetoks @@ -5402,16 +6422,15 @@ \skv@prova#1#2\skv@novalue#2\skv@nil } -% Pushing and popping prefix, family or holder prefix. +% Pushing and popping path or holder prefix. % -\skvnewnumbers[dirkeys@meta]{prefixdepth,familydepth,hpdepth} +\skvnewnumbers[dirkeys@meta]{pathdepth,hpdepth} \skvrobustdef*\dirkeys@pushmeta#1{% - \skvifcase\skvifstrcmpTF{#1}% - {prefix}{\def\@elt{prefixlist}}% - {family}{\def\@elt{familylist}}% - {hp}{\def\@elt{holderprefixtoks}}% + \skvifcasse{#1} + case{path}{\def\@elt{pathlist}} + case{hp}{\def\@elt{holderprefixtoks}} \elsedo - \skv@err{Unknown meta type '#1'}\@ehd + \skv@err{Unknown meta type '#1'}\skv@ehd \endif \skvaftercs\skvgadvanceno{dirkeys@meta#1depth}\@ne \edef\skv@elt{\skvrom\csname dirkeys@meta#1depth\endcsname}% @@ -5419,11 +6438,10 @@ } \skvrobustdef*\dirkeys@popmeta#1{% \skvifcase\skvifstrcmpTF{#1}% - {prefix}{\def\@elt{prefixlist}}% - {family}{\def\@elt{familylist}}% + {path}{\def\@elt{pathlist}}% {hp}{\def\@elt{holderprefixtoks}}% \elsedo - \skv@err{Unknown meta type '#1'}\@ehd + \skv@err{Unknown meta type '#1'}\skv@ehd \endif \edef\skv@elt{\skvrom\csname dirkeys@meta#1depth\endcsname}% \skvcsletcs{dirkeys@\@elt}{dirkeys@\@elt @meta@\skv@elt}% @@ -5432,8 +6450,8 @@ % Assigning admissible values to keys. The handlers here are: % -% .state pattern, .state pattern expanded, .state pattern expanded once, -% .state pattern expanded twice. +% .state pattern, .state pattern expanded, .state pattern expand once, +% .state pattern expand twice. % % \dirkeys@savechoice{<list>}{<expander.type>} % @@ -5448,7 +6466,6 @@ % \skvrobustdef*\dirkeys@savechoice#1#2{% \begingroup - \dirkeys@getrootlist \def\skv@tempd{}% \edef\skv@tempa{\unexpanded{#1}}% \skvcsvnormalize[/]\skv@tempa @@ -5460,7 +6477,7 @@ \skvrobustdef*\dirkeys@s@vechoice#1#2{% \skv@getmaintoks{#1}{/}% \skvkvnormalize\skvcurrentsub - \def\skv@doonroot##1##2{% + \def\skv@pathdo##1##2{% \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% \skvcommaparse*\skvcurrentmaintoks\skv@tempb{% @@ -5490,11 +6507,11 @@ }% }% }% - \skv@rootlist + \dirkeys@pathlist } % \dirkeys@executechoice{<expansion.type>}{<curr.value>}{<choices.and.cbks>} \skvrobustdef*\dirkeys@executechoice#1#2#3{% - \skv@getexpander{#1}% + \skv@getexpander@b{#1}% \edef\skv@prova{\skvexpander{#2}}% \skvdespacecontent\skv@prova \def\do##1##2##3\skv@nil{% @@ -5503,7 +6520,7 @@ ##2% }{% \skvifblankTF{##3}{% - \skv@err{No choice match found for key '\skvcurrentkey'}\@ehd + \skv@err{No choice match found for key '\skvcurrentkey'}\skv@ehd }{% \do##3\skv@nil }% @@ -5512,81 +6529,91 @@ \do#3\skv@nil } +% Slot/style keys represent a limited signal-slot (or subject-observer) +% concept from Java. +% % The handlers here are: % -% .style, .style expanded, .style expanded once, .style expanded twice. +% .slot, .slot value expanded, .slot expand once, .slot expand twice, +% .prepend slot, .prepend slot value expanded, .prepend slot expand once, +% .prepend slot expand twice, .append slot, .append slot value expanded, +% .append slot expand once, .append slot expand twice % % Note that the handlers are preceded by 'append' or 'prepend'. % -% \dirkeys@savestyle{<list>}{<append.or.prepend>}{<expander.type>} +% \dirkeys@saveslots{<list>}{<append.or.prepend>}{<expander.type>} % % 1. <list> has the form % -% {<main key1>,...,<main key-n>}/{<style1=val1>,...,<style-n=val-n>} +% {<signal key1>,...,<signal key-n>}/{<slot1=val1>,...,<slot-n=val-n>} % ,..., -% {<main key1>,...,<main key-n>/{<style1=val1>,...,<style-n=val-n>} +% {<signal key1>,...,<signal key-n>/{<slot1=val1>,...,<slot-n=val-n>} % -% 2. Here the styles are linked with each main key. When the main key is -% set, the associated styles will be set with the given values. +% 2. Here the slots are linked with each signal key. When the signal key is +% set, the associated slots will be set with the given values. % % 3. Examples: % -% a) The following example means that keyc and keyd are representations -% for the actions on their right (ie, for setting 'keya=\someright, -% keyb=\keybval') when keyc or keyd is set. The values of keya and -% keyb will be expanded twice before the keys are set: +% a) The following example means that keyc and keyd are signals +% (representations for the actions on their right, ie, for setting +% the slots 'keya=\someright, keyb=\keybval' when keyc or keyd is set). +% The values of keya and keyb will be expanded twice before the +% keys are set: % -% .append style expand twice={keyc,keyd}/{keya=\someright,keyb=\keybval}. +% .append slot expand twice={keyc,keyd}/{keya=\someright,keyb=\keybval}. % % b) In the following example, #1 will be the value of keye and/or keyf % when they're set. The values of keye and keyf will be fully expanded % before they're assigned to keyc and keyd: % -% .prepend style expanded={keye,keyf}/{keyc=#1,keyd=#1} +% .prepend slot value expanded={keye,keyf}/{keyc=#1,keyd=#1} % -\skvrobustdef\dirkeys@savestyle#1#2#3{% +\skvrobustdef*\dirkeys@saveslots#1#2#3{% \begingroup - \dirkeys@getrootlist - \skv@getexpander{#3}% + \skv@getexpander@b{#3}% \def\skv@tempd{}% \edef\skv@tempa{\unexpanded{#1}}% \skvcsvnormalize[/]\skv@tempa \skvcommaparse*\skv@tempa\skv@tempa{% - \skvexpbracenext\dirkeys@s@vestyle\skv@tempa{#2}% + \skvexpbracenext\dirkeys@s@veslots\skv@tempa{#2}% }% \expandafter\endgroup\skv@tempd } -\skvrobustdef\dirkeys@s@vestyle#1#2{% +\skvrobustdef*\dirkeys@s@veslots#1#2{% \skv@getmaintoks{#1}{/}% \skvcsvnormalize\skvcurrentmaintoks \skvkvnormalize\skvcurrentsub - \def\skv@doonroot##1##2{% + \def\skv@pathdo##1##2{% \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% - \skvcommaloop*\skvcurrentmaintoks\skv@maintoks{% - \skvxifinTF{,\skv@maintoks,}{,\skv@igkeys,}{}{% - \skvifcsdefTF{##1/##2/\skv@maintoks.@cbk}{}{% - % Link keys should always be set with a value. If they were - % undefined before being designated as a link key, then - % clearly they should have no default. + \skvcommaloop*\skvcurrentmaintoks\skv@signalkey{% + \skvxifinTF{,\skv@signalkey,}{,\skv@igkeys,}{}{% + \skvifcsdefTF{##1/##2/\skv@signalkey.@cbk}{}{% + % Signal keys should always be set with a value. If they were + % undefined before being designated as a signal key, then + % clearly they should have no default. The empty callback will + % later be replaced by signal emitters to the slots. \edef\skv@tempd{% \skvexpandonce\skv@tempd - \skvordkey[##1]{##2}{.need value{\skv@maintoks}}{}% + \skvordkey[##1]{##2}{.need value{\skv@signalkey}}{}% }% }% - \def\skv@stylelist{}% + % Insert expanders in the sub list: + \def\skv@slotlist{}% \skvcommaloop*\skvcurrentsub\skv@tempa{% - \skv@kvosplit\skv@tempa{% - \skvxifstrcmpTF{\skv@maintoks}{####1}{% - \skv@err{Linking key '####1' to itself}\@ehd + \skv@okvsplit\skv@tempa{% + \skvxifstrcmpTF{\skv@signalkey}{####1}{% + \skv@err{Linking key '####1' to itself}\skv@ehd }{% + % Slot keys must always be predefined, otherwise the signal + % will be useless: \skvifcsdefTF{##1/##2/####1.@cbk}{}{% - \skv@err{Style key '####1' is undefined}\@ehd + \skv@err{Slot key '####1' is undefined}\skv@ehd }% }% \skvxifinTF{,####1,}{,\skv@igkeys,}{}{% - \edef\skv@stylelist{% - \skvaddlist,\skv@stylelist\unexpanded{####1}=% + \edef\skv@slotlist{% + \skvaddlist,\skv@slotlist\unexpanded{####1}=% \skvexpandonce\skvexpander{\unexpanded{####2}}% }% }% @@ -5595,26 +6622,37 @@ }% \edef\skv@tempd{% \skvexpandonce\skv@tempd - % The styles contain value expanders \@firstofone, \unexpanded, etc. + % The slots contain value expanders \@firstofone, \unexpanded, etc. % They will be expanded by the next \skvexpanded when the main key % is set. - \skvifstrcmpTF{#2}{app}\skvappendkeycode\skvprependkeycode - [##1]{##2}{\skv@maintoks}% - {\skvexpanded{\skvsetkeys[##1]{##2}% - {\skvexpandonce\skv@stylelist}}}% + \skvifstrcmpTF{#2}{app}{\skvappendkeycode}{\skvprependkeycode}% + [##1]{##2}{\skv@signalkey}{% + % Signal keys shouldn't be preset, to avoid cyclic setting + % of keys. See note above. + \noexpand\skvifdefboolTF{skv@inprepo}{% + \noexpand\skv@signalpreseterr + }{% + % The following \skvexpanded works on expanders of slot values: + \skvexpanded{\skvsetkeys[##1]{##2}{\skvexpandonce\skv@slotlist}}% + }% + }% }% }% }% - \skv@rootlist + \dirkeys@pathlist } %% +++++++++++++++ Linking keys: % % The handlers here are: % -% .link, .link expanded, .link expanded once, .link expanded twice. +% .link, .link expanded, .link expand once, .link expand twice, +% .prepend link, .prepend link expanded, .prepend link expand once, +% .prepend link expand twice, +% .append link, .append link expanded, .append link expand once, +% .append link expand twice % -% \dirkeys@savestyle{<list>}{<append.or.prepend>}{<expander.type>} +% \dirkeys@savelinks{<list>}{<append.or.prepend>}{<expander.type>} % % 1. <list> has the form % @@ -5632,12 +6670,12 @@ % % This is equivalent to: % -% .style={{keyb,keyc}/keya=#1} +% .slot={{keyb,keyc}/keya=#1} OR .style={{keyb,keyc}/keya=#1} % % This will link keyb and keyc to keya, such that when keyb and % keyc are set, keya too will be set with their values. % -\skvrobustdef\dirkeys@savelink#1#2#3{% +\skvrobustdef*\dirkeys@savelinks#1#2#3{% \begingroup \def\skv@tempe{}% \edef\skv@tempa{\unexpanded{#1}}% @@ -5648,33 +6686,103 @@ \def\skv@tempd{}% \skvcommaparse*\skvcurrentsub\skv@tempb{% \edef\skv@tempd{% - \skvexpandonce\skv@tempd\ifx\skv@tempd\@empty\else,\fi - \skvexpandonce\skv@tempb=####1% + \skvaddlist,\skv@tempd\skvexpandonce\skv@tempb=####1% }% }% \edef\skv@tempe{% - \skvexpandonce\skv@tempe\ifx\skv@tempe\@empty\else,\fi + \skvaddlist,\skv@tempe {\skvexpandonce\skvcurrentmaintoks}/{\skvexpandonce\skv@tempd}% }% }% - \expandafter\endgroup\expandafter\dirkeys@savestyle + \expandafter\endgroup\expandafter\dirkeys@saveslots \expandafter{\skv@tempe}{#2}{#3}% } +% ++++++++++++ Storing values of keys: +% +% The handlers here are: +% +% .store value in, .store expanded value in, .store expanded once value in, +% .store expanded twice value in. +% +% \dirkeys@savestores{<list>}{<expander.type>} +% +% 1. <list> has the form +% +% <key-1>/<cmd-1>,...,<key-n>/<cmd-n> +% +% 2. Examples: +% +% .store expanded twice value in={keyc/\valc,keyd/\vald} +% +\skvrobustdef*\dirkeys@savestores#1#2{% + \begingroup + \skv@getexpander@b{#2}% + \def\skv@tempd{}% + \edef\skv@tempa{\unexpanded{#1}}% + \skvcsvnormalize[/]\skv@tempa + \skvcommaparse*\skv@tempa\skv@tempa{% + \skv@oslashsplit\skv@tempa{% + \skvifstrcmpTF{##2}{^skv^}{% + \skv@err{No holder commands for key(s) '\detokenize{##1}'}\skv@ehd + }{% + \skvcommaparse{##1}\skv@tempa{% + \skvexpbracenext\dirkeys@s@vestore\skv@tempa{##2}% + }% + }% + }% + }% + \expandafter\endgroup\skv@tempd +} +\skvrobustdef*\dirkeys@s@vestore#1#2{% + \def\skv@pathdo##1##2{% + \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% + \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% + \skvxifinTF{,#1,}{,\skv@igkeys,}{}{% + \skvifcsdefFT{##1/##2/#1.@cbk}{% + \skv@err{Key '#1' isn't defined + \MessageBreak on path '##1/##2'}\skv@ehd + }{% + \edef\skv@tempd{% + \skvexpandonce\skv@tempd + \skvprependkeycode[##1]{##2}{#1}{% + \skvletcs\noexpand\reserved@a{##1/##2/#1.@value}% + \edef\noexpand#2{% + % Don't use \skvcurrentvalue here, since this + % changes when .setkeys is nested: + \skvexpandonce\skvexpander{\noexpand\reserved@a}% + }% + }% + }% + }% + }% + }% + \dirkeys@pathlist +} + +\skvrobustdef*\dirkeys@keyslet#1{% + \def\skv@pathdo##1##2{% + \skv@makeprefix{##1}% + \skv@makeheader{##2}% + \skv@keyslet{#1}% + }% + \dirkeys@pathlist +} % #1: <key-1>=<arg-1>,...,<key-n>=<arg-n> % #2: <arg.expander.type> % \skvrobustdef*\dirkeys@assignarg#1#2{% \begingroup - % Don't take #1 inside \skv@doonroot because it contains parameters: + % Don't take #1 inside \skv@pathdo because it contains parameter + % characters: \edef\skv@tempd{\unexpanded{#1}}% \def\skv@tempe{}% \skvkvnormalize\skv@tempd - \def\skv@doonroot##1##2{% + \def\skv@pathdo##1##2{% \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% \skvcommaloop*\skv@tempd\skv@tempa{% - \skv@kvosplit\skv@tempa{% + \skv@okvsplit\skv@tempa{% \skvxifinTF{,####1,}{,\skv@igkeys,}{}{% \skvifcsdefTF{##1/##2/####1.@cbk}{% \skvifblankTF{####2}{}{% @@ -5685,13 +6793,14 @@ }% }% }{% - \skv@err{Key '####1' is undefined in family '##1/##2'}\@ehd + \skv@err{Key '####1' is undefined + \MessageBreak in family '##1/##2'}\skv@ehd }% }% }% }% }% - \dirkeys@getcurrentroots\skv@doonroot + \dirkeys@pathlist \expandafter\endgroup\skv@tempe } @@ -5710,48 +6819,47 @@ }% }{% \skv@err{No default value for key '\skvcurrentkey' - \MessageBreak in family '#1/#2'}\@ehd + \MessageBreak in family '#1/#2'}\skv@ehd }% }% \skvexpanded{\endgroup \skvsetkeys*+[#1]{#2}{\skvexpandonce\skv@defaultlist}% }% } - -\skvrobustdef*\dirkeys@dounknownkeyhandler#1{% +\skvrobustdef*\dirkeys@setunknownkeyhandler#1{% \begingroup - \def\skv@tempa{}\def\skv@tempb{}% - \def\do##1##2{% - \skvxifinTF{,##1,}{,\skv@tempa,}{}{% - \edef\skv@tempa{% + \edef\skv@tempa{\unexpanded{#1}}% + \def\skv@tempb{}% + \toks@{##1##2##3##4}% + \def\skv@pathdo##1##2{% + \skv@makeprefix{##1}% + \skv@makeheader{##2}% + \edef\skv@tempb{% + \skvexpandonce\skv@tempb\protected + \skvcsdef{\skvcurrentpath.@famhandler}\the\toks@{% \skvexpandonce\skv@tempa - \ifx\skv@tempa\@empty\else,\fi##1% - }% - }% - \skvxifinTF{,##2,}{,\skv@tempb,}{}{% - \edef\skv@tempb{% - \skvexpandonce\skv@tempb - \ifx\skv@tempb\@empty\else,\fi##2% }% }% }% - \dirkeys@getcurrentroots\do - \skvexpanded{\endgroup - \skvunknownkeyhandler\ifskv@handlerswa+\fi[\skv@tempa]{\skv@tempb}% - }{#1}% + \dirkeys@pathlist + \expandafter\endgroup\skv@tempb } %%++++++++++++++++++++++++++ Try setting keys +++++++++++++++++++++++%% % -% \skvtrysetkeys[<options>]{<keyvals>} -% .try set keys={<options>} +% \skvtrysetkeys[<paths>]{<keyvals>} +% +% \directkeys{ +% .try set keys={<options>}, where +% <options> includes <paths> and key-value list (see below). +% } % % Try to set a given key-value list on the paths given by the independent -% options '.prefix/.prefixes' and '.family/.families' of \skvtrysetkeys. If -% called within \directkeys (via the handler '.try set keys'), \skvtrysetkeys -% will ignore the paths that are currently prevailing within \directkeys. -% That is, within \directkeys, the handler '.try set keys' acts independent -% of local circumstances of \directkeys. +% <paths> of \skvtrysetkeys. If called within \directkeys (via the handler +% '.try set keys'), \skvtrysetkeys will ignore the paths that are currently +% prevailing within \directkeys. That is, within \directkeys, the handler +% '.try set keys' acts independent of local circumstances of \directkeys +% and uses its own paths from <options>. % % Save the known/found keys in the macro suggested by the option % <success list macro>. The user can inspect this macro to see the found @@ -5776,7 +6884,7 @@ % .try: % The maximum number of the sum of successful and unsuccessful % attempts that should be made to set a key in the given SFs. The -% default value of <try> is 12. +% default value of <try> is 100. % .upper goal/.max success: % The max. number of search families (SF) in which a given key should % be set/executed, if the key existed in those families. The number of @@ -5785,11 +6893,18 @@ % .lower goal/.min success: % The min. number of search families (SF) in which a given key should % be set/executed. For any key, if <hits> is less than <lower goal> -% an error will be flagged. -% .prefix/.prefixes: -% The prefixes in which the keys should be set (default=KV). -% .families/.family: -% Families to search. +% an error will be flagged. The default of this is 0, meaning that +% by default no error message will be returned if a key isn't found +% on any of the paths. +% .path/.paths: +% Paths to search <pref1>/<fam1>,...,<pref-n>/<fam-n>. +% .prefix +% The prefix to search (default: KV). The number of prefixes can't +% be more than 1. If you have multiple prefixes, then use the +% .paths key. The given prefix will be prepended to all the given +% families. +% .families/.family +% The families to search <fam1>,...,<fam-n>. % .ignore keys: % Ignored keys. These keys will not be set even if they are found. % .save known keys: @@ -5797,250 +6912,312 @@ % in a macro. % .save known keys in/success list macro/success list: % The macro into which to save known keys. Each known key is -% saved in the format: <pref>/<fam>/<key>. The user can +% saved in the format <pref>/<fam>/<key>. The user can % inspect this macro to see the found keys. The default macro is % \skvsuccesslist. -% -% NOTE: -% -% When the paths are many, the user has to be right in choosing the -% options '.try', '.upper goal' and '.lower goal', otherwise not enough paths -% will be searched. For example, if you want some 'keya' to be set on -% paths KV1/fam1, KV1/fam2, KV2/fam1, KV2/fam2, and you set '.try=2' or -% '.upper goal=2', then only 2 paths will be traversed; not the desired 4. +% .save unknown keys: +% The boolean that directs that unknown keys should be saved +% in a macro. +% .save unknown keys in/fail list macro/fail list: +% The macro into which to save unknown keys. Each unknown key is +% saved in the format <pref>/<fam>/<key>. The user can +% inspect this macro to see the unknown keys. The default macro is +% \skvfaillist. +% .path exception +% The user-supplied action (code) to take when a key hasn't been found +% on the curent path of the given paths. The default path exception +% is nil. +% .hits exception +% The user-supplied action (code) to take when the number of hits is +% less than preferred minimum success. This may specify retrying on +% some other paths. The default exception is an error message. +% +% NOTES: +% +% 1. When the paths are many, the user has to be right in choosing the +% options '.try', '.upper goal' and '.lower goal', otherwise not +% enough paths will be searched. For example, if you want some 'keya' +% to be set on paths KV1/fam1, KV1/fam2, KV2/fam1, KV2/fam2, and you +% set '.try=2' or '.upper goal=2', then only 2 paths will be traversed; +% not the desired 4. -\skvrobustdef*\dirkeys@trysetkeys#1{% - \begingroup - \@tempcnta\skvz@ - \def\skv@tempc{}% - \def\skv@tempd{}% - \def\skv@tempa##1={% - \begingroup - \let\bgroup\relax - \@ifnextchar\skv@orig@bgroup{% - \endgroup\@tempswatrue\skv@tempb##1=% - }{% - \endgroup\@tempswafalse\skv@tempb##1=% - }% - }% - \def\skv@tempb##1=##2=##3\skv@nil{% - \skvxifinTF{,##1,}{,.key values,.kv,.kv list,}{% - \advance\@tempcnta\@ne - \skvifnumTF\@tempcnta>\@ne{% - \skv@err{Multiple entries for key '.key values' or '.kv'}\@ehd - }{% - \edef\skv@tempd{\skvifstrcmpTF{##2}{^skv^}{}{\unexpanded{##2}}}% - }% - }{% - \edef\skv@tempc{% - \skvexpandonce\skv@tempc\ifx\skv@tempc\@empty\else,\fi - ##1% - \skvifstrcmpTF{##2}{^skv^}{}{% - =\if@tempswa{\fi\unexpanded{##2}\if@tempswa}\fi - }% - }% - }% - }% - \skvkvparse{#1}\skv@prova{% - \expandafter\skv@tempa\skv@prova=^skv^=\skv@nil - }% - \ifx\skv@tempd\@empty - \skv@err{No key-value pairs for handler '.try set keys'}\@ehd - \fi - \skvexpanded{\endgroup - \noexpand\skv@trysetkeys[\skvexpandonce\skv@tempc]% - {\skvexpandonce\skv@tempd}% - }% -} \skvedefinekeys[SKV]{skvtryset}[skvtry@]{% - .ord/{.try,.max attempt,.max attempts,.total}/12/ + .initialize keys after define, + .ord/{.try,.max attempt,.max attempts,.total}/100/ + \skvensureinteger{.max attempt}{#1}% \def\skvtry@maxattempts{#1}% \skvstripouterbraces{2}\skvtry@maxattempts \edef\skvtry@maxattempts{\number\skvtry@maxattempts}% - \skvensureinteger{.max attempt}\skvtry@maxattempts \ifnum\skvtry@maxattempts<\@ne \skv@err{The max. number of attempts ('try') - \MessageBreak can't be less than 1}\@ehd + \MessageBreak can't be less than 1}\skv@ehd \fi , .ord/{.upper goal,.max success,.max hits}/1/ + \skvensureinteger{upper goal}{#1}% \def\skvtry@maxsuccess{#1}% \skvstripouterbraces{2}\skvtry@maxsuccess \edef\skvtry@maxsuccess{\number\skvtry@maxsuccess}% - \skvensureinteger{upper goal}\skvtry@maxsuccess \ifnum\skvtry@maxsuccess<\@ne \skv@err{The max. number of successful attempts - \MessageBreak ('upper goal') can't be less than 1}\@ehd + \MessageBreak ('upper goal') can't be less than 1}\skv@ehd \fi , - .ord/{.min success,.lower goal,.goal}/1/ + .ord/{.min success,.lower goal,.goal}/0/ + \skvensureinteger{lower goal}{#1}% \def\skvtry@minsuccess{#1}% \skvstripouterbraces{2}\skvtry@minsuccess \edef\skvtry@minsuccess{\number\skvtry@minsuccess}% - \skvensureinteger{lower goal}\skvtry@minsuccess - \ifnum\skvtry@minsuccess<\@ne + \ifnum\skvtry@minsuccess<\skvz@ \skv@err{The min. number of successful attempts - \MessageBreak ('lower goal') can't be less than 1}\@ehd + \MessageBreak ('lower goal') can't be less than 0}\skv@ehd \fi , - .ord/{.prefix,.prefixes,.add prefix,.add prefixes}/\skv@defaultpref/ - \edef\skvtry@prefs{#1} - \skvstripouterbraces{2}\skvtry@prefs - \edef\skvtry@prefs{% - \skvifemptyTF\skvtry@prefs\skv@defaultpref\skvtry@prefs - }% - \ifskv@insa - \skvexpbracenext{\skvmergelist\skvtry@prefs}\dirkeys@prefixlist - \fi - \skvcsvnormalize\skvtry@prefs - , - .ord/{.family,.families,.add family,.add families}/\@nil/ - \edef\skvtry@fams{#1} - \skvstripouterbraces{2}\skvtry@fams - \ifx\skvtry@fams\@nnil\else - \skvstripouterbraces{2}\skvtry@fams + % #1=<pref1>/<fam1>,...,<pref-n>/<fam-n> + .ord/{.path,.paths,.add path,.add paths}/\skv@nil/{ + \edef\skv@tempa{#1}% + \skvstripouterbraces{2}\skv@tempa + \ifx\skv@tempa\skv@nnil\def\skv@tempa{}\fi + \ifx\skv@tempa\@empty\else + \skvcommaparse*\skv@tempa\skv@prova{% + \skv@splitpath@a\skv@prova\skv@tempa\skv@tempb + \edef\skv@prova{{\skv@tempa}{\skv@tempb}}% + \skvxifinTF{\skvoxdetok\skv@prova}{\skvoxdetok\skvtry@pathlist}{}{% + \edef\skvtry@pathlist{% + \skvexpandonce\skvtry@pathlist\noexpand\skvtry@pathdo\skv@prova + }% + }% + }% \ifskv@insa - \skvexpbracenext{\skvmergelist\skvtry@fams}\dirkeys@familylist + \begingroup + \def\skv@pathdo##1##2{% + \edef\skv@prova{\detokenize{{##1}{##2}}}% + \skvxifinTF{\skv@prova}{\skvoxdetok\skvtry@pathlist}{}{% + \edef\skvtry@pathlist{% + \skvexpandonce\skvtry@pathlist + \noexpand\skvtry@pathdo{##1}{##2}% + }% + }% + }% + \dirkeys@pathlist + \skvaftergroupdef\skvtry@pathlist\endgroup \fi - \skvcsvnormalize\skvtry@fams \fi + }, + % Prefix is used in making \skvtry@pathlist in .family: + .ord/{.prefix}/\skvdefaultprefix/ + \skv@ifoneprefix{#1}{% + \def\skvtry@pref{#1} + \skvstripouterbraces{2}\skvtry@pref + }{% + \skv@err{Only one prefix is allowed in '.try set keys'}\skv@ehd + } , - .ord/{.path,.paths,.add path,.add paths,.root,.roots}/\@nil/ - \edef\skv@tempa{\skvtrimspace{#1}} - \skvstripouterbraces{2}\skv@tempa - \ifcase0\ifx\skv@tempa\@nnil1\else - \ifx\skv@tempa\@empty1\fi\fi\relax\skvafterfi - \skvexpbracenext\skvtry@processpaths\skv@tempa + .ord/.prefixes// + \ifskvindef\else + \skv@err{Key '.prefixes' not defined; try '.paths'}\skv@ehd \fi , - .ord/{.ignore keys,.filter keys}// - \def\skvtry@igkeys{#1} - \skvstripouterbraces{2}\skvtry@igkeys + .ord/{.family,.families}/\skv@nil/ + \edef\skvtry@fams{#1} + \ifskvindef\else + \ifx\skvtry@fams\skv@nnil + \skv@err{No family specified for command + \MessageBreak\string\skvtrysetkeys or handler '.try set keys'}\skv@ehd + \fi + \fi + \skvstripouterbraces{2}\skvtry@fams + \skv@makepaths\skvtry@pref\skvtry@fams\skvtry@pathlist\skvtry@pathdo , - .ord/{.save known keys,.save success}/true/ - \def\skvtry@savesuccess{#1} - \skvstripouterbraces{2}\skvtry@savesuccess - \edef\skvtry@savesuccess{0\ifx\skvtry@savesuccess\skv@truetoks0\else1\fi} + .ord/{.ignore keys}// + \def\skvtry@igkeys{#1} + \ifx\skvtry@igkeys\@empty\else + \skvstripouterbraces{2}\skvtry@igkeys + \fi , .ord/{.save known keys in,.success list,.success list macro}/ \skvsuccesslist/ - \def\skvtry@successlistmacro{#1} - \skvstripouterbraces{2}\skvtry@successlistmacro + \skviflacus#1\then + \def\skvtry@knownkeyslistmacro{\skvsuccesslist}% + \else + \def\skvtry@knownkeyslistmacro{#1} + \fi + \skvstripouterbraces{2}\skvtry@knownkeyslistmacro + , + .ord/{.save unknown keys in,.fail list,.fail list macro}/ + \skvfaillist/ + \skviflacus#1\then + \def\skvtry@unknownkeyslistmacro{\skvfaillist}% + \else + \def\skvtry@unknownkeyslistmacro{#1} + \fi + \skvstripouterbraces{2}\skvtry@unknownkeyslistmacro + , + % Exception on each path, if key isn't found: + .ord/{.if any path fails,.if a path fails,.if path fails}// + \edef\skvtry@pathexception{\unexpanded{#1}} + \skvstripouterbraces{1}\skvtry@pathexception + , + % Exception to be triggered after all paths have been searched and the key + % isn't found: + .ord/{.if hits less than target,.if hits less than goal, + .if hits are less than goal}// + \edef\skvtry@hitsexception{\unexpanded{#1}} + \skvstripouterbraces{1}\skvtry@hitsexception , -} -\skvrobustdef*\skvtry@processpaths#1{% - \def\skvtry@prefs{}% - \def\skvtry@fams{}% - \def\skv@tempc##1/##2/##3\skv@nil{% - \def\skv@tempa{##1}% - \def\skv@tempb{##2}% - \skvstripouterbraces{2}\skv@tempa - \skvstripouterbraces{2}\skv@tempb - \edef\skvtry@prefs{% - \skvtry@prefs\ifx\skvtry@prefs\@empty\else,\fi\skv@tempa - }% - \edef\skvtry@fams{% - \skvtry@fams\ifx\skvtry@fams\@empty\else,\fi\skv@tempb - }% - }% - \skvcommaparse{#1}\skv@prova{% - \expandafter\skv@tempc\skv@prova//\skv@nil - }% - \ifskv@insa - \skvexpbracenext{\skvmergelist\skvtry@prefs}\dirkeys@prefixlist - \skvexpbracenext{\skvmergelist\skvtry@fams}\dirkeys@familylist - \fi - \skvcsvnormalize\skvtry@prefs - \skvcsvnormalize\skvtry@fams -} -\skvsetkeys[SKV]{skvtryset}{.try,.upper goal,.lower goal,.prefix, - .family=^skv^,.ignore keys,.save success,.success list macro } % \skvtrysetkeys[<options>]{<kvlist>} \skvrobustdef*\skvtrysetkeys{\skv@testopt\skv@trysetkeys{}} \skvrobustdef*\skv@trysetkeys[#1]#2{% \skvpushfunctions\skvtrysetkeys{% - \do\skvtry@fams\do\skvtry@prefs\do\skvtry@maxattempts + \do\skvtry@maxattempts\do\skvtry@hitsexception\do\skvtry@pathexception \do\skvtry@minsuccess\do\skvtry@maxsuccess\do\skvtry@igkeys - \do\skvtry@successlistmacro\do\skvtry@savesuccess - \do\CurrentOption\do\skv@tempsuccesslist - \do\skvcurrentkey\do\skvcurrentpath + \do\skvtry@knownkeyslistmacro\do\skv@tempknownkeys + \do\skvtry@unknownkeyslistmacro\do\skv@tempunknownkeys + \do\skv@triedlist\do\CurrentOption\do\skvtry@pref\do\skvtry@fams + \do\skvtry@pathlist\do\skv@pathdo\do\skvcurrentkey\do\skvcurrentpath \do\skvcurrentprefix\do\skvcurrentfamily }\skv@trysetkeysdepth + % Initialize \skvtry@pathlist; see the definition of the keys of + % \skvtrysetkeys above. + \def\skvtry@pathlist{}% \skvsetkeys[SKV]{skvtryset}{#1}% - \ifx\skvtry@fams\skv@rej - \skv@err{No families in which to 'try' to set keys}\@ehd + \ifx\skvtry@pathlist\@empty + \skv@err{No families in which to 'try' to set keys}\skv@ehd \fi - \skv@getkeynames{#2}\skv@naa - \expandafter\def\skvtry@successlistmacro{}% - \def\skv@tempsuccesslist{}% + % To avoid repeated computation of \skv@currentnames in \skv@setkeys@a + % for each key in the next loop: + \skv@getnamesofkeys{#2}\skv@currentnames + \expandafter\def\skvtry@knownkeyslistmacro{}% + \expandafter\def\skvtry@unknownkeyslistmacro{}% + \skvemptify{\skv@tempknownkeys,\skv@tempunknownkeys,\skv@triedlist}% \skv@intrytrue \skvcommaparse{#2}\CurrentOption{% - \expandafter\skv@g@tkeyname\CurrentOption=\skv@nil\skvcurrentkey - \skvxifinTF{,\skvcurrentkey,}{,\skvtry@igkeys,}{}{% + \expandafter\skv@g@tkeyname\CurrentOption=\skv@getname@nil\skvcurrentkey + \skvifemptyTF\skvtry@igkeys{% + \@firstofone + }{% + \skvxifinTF{,\skvcurrentkey,}{,\skvtry@igkeys,}{}% + }{% + % \skv@triedlist saves non-ignored list: + \edef\skv@triedlist{\skvaddlist,\skv@triedlist\skvcurrentkey}% \skvpushfunctions\skv@trysetkeys@istate{% - \do\CurrentOption\do\skvcurrentkey\do\skvcurrentpath - \do\skvcurrentprefix\do\skvcurrentfamily - \do\skv@attempts\do\skv@hits\do\skv@breakprefloop - \do\ifskv@success - }\skv@trysetkeysdepth@b + \do\CurrentOption\do\skvcurrentkey\do\skv@attempts + \do\skv@hits\do\skv@failedattempts\do\ifskv@success\do\skvtry@pathdo + }\skv@trysetkeysidepth \skv@successfalse - % Don't use \chardef here; it won't print in the error message - % if it wasn't incremented: - \def\skv@attempts{0}% - \def\skv@hits{0}% - \def\skv@breakprefloop{01}% - \skvcommaloop*\skvtry@prefs\skvcurrentprefix{% - \skvcommaloop*\skvtry@fams\skvcurrentfamily{% - \skvexpanded{% - % Don't use \skv@setkeys@a here: \skv@fams, etc. - % will be mixed up. - \skvsetkeys[\skvcurrentprefix]{\skvcurrentfamily}% - {\skvexpandonce\CurrentOption}% + \skvinizero{\skv@attempts,\skv@hits,\skv@failedattempts}% + \def\skvtry@pathdo##1##2{% + \edef\skv@fams{##2}% + \skv@makeprefix{##1}% + % \ifskv@st is 'false' because we always save unknown keys while + % in .try; and the branch for \ifskv@st is never taken when + % in .try (see \skv@setkeys@d). + \skv@stfalse\skv@plfalse\skv@viarootofsetkeysfalse + \skvexpbracenext{\skv@setkeys@a[]}\CurrentOption + \edef\skv@attempts{\the\numexpr\skv@attempts+1}% + \ifskv@success + \edef\skv@hits{\the\numexpr\skv@hits+1}% + \edef\skv@tempknownkeys{% + \skvaddlist,\skv@tempknownkeys\skvcurrenttriple }% - \edef\skv@attempts{\the\numexpr\skv@attempts+1}% - \ifskv@success - \edef\skv@hits{\the\numexpr\skv@hits+1}% - \if\skvtry@savesuccess - \edef\skv@tempsuccesslist{% - \skvaddlist,\skv@tempsuccesslist\skvcurrenttriple - }% - \fi - \fi - \ifnum\skv@hits<\skvtry@maxsuccess\relax - \ifnum\skv@attempts<\skvtry@maxattempts\relax\else - \skvbreakloop - \def\skv@breakprefloop{00}% - \fi - \else - \skvbreakloop - \def\skv@breakprefloop{00}% + \else + % \skv@failedattempts is currently unused. + \edef\skv@failedattempts{\the\numexpr\skv@failedattempts+1}% + \edef\skv@tempunknownkeys{% + \skvaddlist,\skv@tempunknownkeys\skvcurrenttriple + }% + \expandafter\expandafter\expandafter\skvtry@pathexception + \fi + \ifnum\skv@hits<\skvtry@maxsuccess\relax + \ifnum\skv@attempts<\skvtry@maxattempts\relax\else + \let\skvtry@pathdo\@gobbletwo \fi - }% - \if\skv@breakprefloop - \skvbreakloop + \else + \let\skvtry@pathdo\@gobbletwo \fi }% + \skvtry@pathlist \ifnum\skv@hits<\skvtry@minsuccess\relax - \skv@err{Success target '\skvtry@minsuccess' wasn't reached - \MessageBreak for key '\skvcurrentkey' by - \ifskv@insa'.search also set'\else - \noexpand\skvtrysetkeys\fi. - \MessageBreak Actual hits were '\skv@hits'}\@ehd + \ifx\skv@triedlist\@empty + \skv@err{Empty try list; all keys were probably ignored}\skv@ehd + \else + \ifx\skvtry@hitsexception\@empty + \skv@err{Success target '\skvtry@minsuccess' wasn't reached + \MessageBreak for key '\skvcurrentkey' by + \ifskv@insa'.search also set'\else + '.try set keys' or \noexpand\skvtrysetkeys\fi. + \MessageBreak Actual hits were '\skv@hits'}\skv@ehd + \else + \expandafter\expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\skvtry@hitsexception + \fi + \fi \fi - \skvpopfunctions\skv@trysetkeys@istate\skv@trysetkeysdepth@b + \skvpopfunctions\skv@trysetkeys@istate\skv@trysetkeysidepth }% }% - \expandafter\let\skvtry@successlistmacro\skv@tempsuccesslist + \ifx\skv@triedlist\@empty + \skv@warn{Empty try list in '.try set keys'; + \MessageBreak all keys were probably ignored}\skv@ehd + \fi + \expandafter\let\skvtry@knownkeyslistmacro\skv@tempknownkeys + \expandafter\let\skvtry@unknownkeyslistmacro\skv@tempunknownkeys \ifnum\skv@trysetkeysdepth=\@ne \skv@intryfalse\skv@insafalse \let\do\skvundef - \do\skv@breakprefloop\do\skv@attempts\do\skv@hits - \do\skv@tempsuccesslist + \do\skv@triedlist\do\skv@attempts\do\skv@hits\do\skv@failedattempts + \do\skv@tempknownkeys\do\skv@tempunknownkeys \fi \skvpopfunctions\skvtrysetkeys\skv@trysetkeysdepth } +% In \directkeys, \dirkeys@trysetkeys will be called instead of \skvtrysetkeys: +\skvrobustdef*\dirkeys@trysetkeys#1{% + \begingroup + \@tempcnta\skvz@ + \def\skv@tempc{}\def\skv@tempd{}% + % Prepare to preserve outer brace in key value: + \def\skv@tempa##1={% + \begingroup + \let\bgroup\relax + \@ifnextchar\skv@orig@bgroup{% + \endgroup\@tempswatrue\skv@tempb##1=% + }{% + \endgroup\@tempswafalse\skv@tempb##1=% + }% + }% + % Because of the need to preserve outer braces in key values, don't + % use \skv@kvsplit here. + \def\skv@tempb##1=##2=##3\skv@nil{% + \skvxifinTF{,##1,}{,.key values,.kv,.kv list,}{% + \advance\@tempcnta\@ne + \skvifnumTF\@tempcnta>\@ne{% + \skv@err{Multiple entries for key + \MessageBreak '.key values' or '.kv' or '.kv list'}\skv@ehd + }{% + \edef\skv@tempd{\skvifstrcmpTF{##2}{^skv^}{}{\unexpanded{##2}}}% + }% + }{% + \edef\skv@tempc{% + \skvaddlist,\skv@tempc##1% + \skvifstrcmpTF{##2}{^skv^}{}{% + =\if@tempswa{\fi\unexpanded{##2}\if@tempswa}\fi + }% + }% + }% + }% + \skvkvparse{#1}\skv@prova{% + \expandafter\skv@tempa\skv@prova=^skv^=\skv@nil + }% + \ifx\skv@tempd\@empty + \skv@err{No key-value pairs for handler '.try set keys'}\skv@ehd + \fi + \skvexpanded{\endgroup + \noexpand\skv@trysetkeys[\skvexpandonce\skv@tempc]% + {\skvexpandonce\skv@tempd}% + }% +} %%+++++++++++++++++++++++++ 'search also' set keys +++++++++++++++++++%% % @@ -6051,10 +7228,9 @@ % <options>. % % 1. The only difference between \skvsasetkeys and \skvtrysetkeys is that, -% when in \directkeys, the values of the options <prefix/prefixes> and -% <family/families> of \skvsasetkeys are added to the current -% active prefixes and families from the lists \dirkeys@prefixlist and -% \dirkeys@familylist. Outside of \directkeys, the commands +% when in \directkeys, the values of the option 'paths' of \skvsasetkeys +% are added to the current active paths from the lists +% \dirkeys@pathlist. Outside of \directkeys, the commands % \skvsasetkeys and \skvtrysetkeys are the same. % % 2. All the options of \skvtrysetkeys apply to \skvsasetkeys. @@ -6062,66 +7238,107 @@ \skvnewlet\skvsasetkeys\skvtrysetkeys \skvrobustdef*\dirkeys@sasetkeys#1{% \skv@insatrue - \skvifdefTF\dirkeys@familylist{}{\def\dirkeys@familylist{}}% - \skvifdefTF\dirkeys@prefixlist{}{\def\dirkeys@prefixlist{}}% \dirkeys@trysetkeys{#1}% } - -% \dirkeys@addorremoveroots{<list>}{<operator>} -\skvrobustdef*\dirkeys@addorremoveroots#1#2{% - \edef\skv@prova{\unexpanded{#1}}% - \skvcsvnormalize[/]\skv@prova - \def\skv@tempa{}\def\skv@tempb{}% - \skvcommaparse*\skv@prova\skv@prova{% - \skv@trimslashes\skv@prova - \skvexpbracenext\skv@slsplit\skv@prova{% - \skvifstrcmpTF{##2}{^skv^}{% - \let\skv@prova\skv@defaultpref - \def\skv@provb{##1}% - }{% - \def\skv@prova{##1}\def\skv@provb{##2}% - }% - \skvxifinTF{,\skv@prova,}{,\skv@tempa,}{}{% - \edef\skv@tempa{\skv@tempa\ifx\skv@tempa\@empty\else,\fi\skv@prova}% +% \dirkeys@addpaths{<paths>} +% Elements of <path> will have the form '{<pref>}/{<fam>}' +\skvrobustdef*\dirkeys@addpaths#1{% + \skv@formatpaths{#1}\dirkeys@pathlist +} +% \dirkeys@removepaths{<list>} +\skvrobustdef*\dirkeys@removepaths#1{% + \begingroup + \edef\skv@tempa{\unexpanded{#1}}% + \skvcsvnormalize[,]\skv@tempa + \skvcsvnormalize[/]\skv@tempa + \def\skv@tempb{}% + \def\skv@pathdo##1##2{% + \skvxifinTF{,\detokenize{##1/##2},}{,\skvoxdetok\skv@tempa,}{}{% + \edef\skv@tempb{% + \skvexpandonce\skv@tempb + \noexpand\skv@pathdo{##1}{##2}% }% - \skvxifinTF{,\skv@provb,}{,\skv@tempb,}{}{% - \edef\skv@tempb{\skv@tempb\ifx\skv@tempb\@empty\else,\fi\skv@provb}% + }% + }% + \dirkeys@pathlist + \let\dirkeys@pathlist\skv@tempb + \skvaftergroupdef\dirkeys@pathlist\endgroup +} +% \dirkeys@removefams{<list>} +\skvrobustdef*\dirkeys@removefams#1{% + \begingroup + \edef\skv@tempa{\unexpanded{#1}}% + \skvcsvnormalize\skv@tempa + \def\skv@tempb{}% + \def\skv@pathdo##1##2{% + \skvxifinTF{,\detokenize{##2},}{,\skvoxdetok\skv@tempa,}{}{% + \edef\skv@tempb{% + \skvexpandonce\skv@tempb + \noexpand\skv@pathdo{##1}{##2}% }% }% }% - \skv@clfalse - \skvexpbracenext{#2\dirkeys@prefixlist}\skv@tempa - \skvexpbracenext{#2\dirkeys@familylist}\skv@tempb + \dirkeys@pathlist + \let\dirkeys@pathlist\skv@tempb + \skvaftergroupdef\dirkeys@pathlist\endgroup +} +% \dirkeys@collectpaths{<pref.macro>}{<fam.macro>}{<ig.macro>} +% Collect current prefixes in <pref.macro>, families in <fam.macro> and +% ignored keys in <ig.macro>. +\skvrobustdef*\dirkeys@collectpaths#1#2#3{% + \begingroup + \skvemptify{#1,#2,#3}% + \def\skv@pathdo##1##2{% + \skvxifinTF{,##1,}{,#1,}{}{\edef#1{\skvaddlist,#1##1}}% + \skvxifinTF{,##2,}{,#2,}{}{\edef#2{\skvaddlist,#2##2}}% + \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% + \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% + \edef#3{\skvaddlist,#3\skv@igkeys}% + }% + \dirkeys@pathlist + \let\do\skvcmdexit + \skvexpanded{\endgroup\do#1\do#2\do#3}% } +% Remove leading and trailing slashes in #1. \skvrobustdef*\skv@trimslashes#1{% \begingroup - \skvxifinFT{\skvrelax/}{\skvrelax#1}{}{% - \def\do/##1\skv@nil{\def#1{##1}}% - \expandafter\do#1\skv@nil + \def\skv@tempa{% + \skvxifinFT{\skvrelax/}{\skvrelax#1}{}{% + \def\do/##1\skv@nil{\def#1{##1}}% + \expandafter\do#1\skv@nil + \skv@tempa + }% }% - \skvxifinFT{/\skvrelax}{#1\skvrelax}{}{% - \def\do##1/\skv@nil{\def#1{##1}}% - \expandafter\do#1\skv@nil + \skv@tempa + \def\skv@tempa{% + \skvxifinFT{/\skvrelax}{#1\skvrelax}{}{% + \def\do##1/\skv@nil{\def#1{##1}}% + \expandafter\do#1\skv@nil + \skv@tempa + }% }% + \skv@tempa \skvaftergroupdef#1\endgroup } -% \dirkeys@addtocodeorvalue{app/pre}{cbk/value}{<list>} +% \dirkeys@addtocodeorvalue{app.or.pre}{cbk.or.value}{<list>} +% <list> has the form <key1>={<value1>},...,<key-n>={<value-n>} \skvrobustdef*\dirkeys@addtocodeorvalue#1#2#3{% \begingroup - % Hid the list from the parameters of \do: + % Hid the list from the parameters of \skv@pathdo: \edef\skv@tempa{\unexpanded{#3}}% \def\skv@tempb{}% % ##1=prefix, ##2=family - \def\do##1##2{% + \def\skv@pathdo##1##2{% \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% \skvkvparse*\skv@tempa\skv@tempa{% - \expandafter\skv@kvsplit\expandafter{\skv@tempa}{% + \skv@okvsplit\skv@tempa{% \skvxifinTF{,\detokenize{####1},}{,\skvoxdetok\skv@igkeys,}{}{% \skvletcs\skv@prova{##1/##2/####1.@#2}% \skvifdefFT\skv@prova{% - \skv@err{Key '####1' isn't in family '##1/##2'}\@ehd + \skv@err{Key '####1' isn't in family + \MessageBreak '##1/##2'}\skv@ehd }{% \skvcsedef{##1/##2/####1.@#2}{% \skvifstrcmpTF{#1}{pre}{% @@ -6140,7 +7357,7 @@ }% }% }% - \dirkeys@getcurrentroots\do + \dirkeys@pathlist \skvexpanded{\endgroup\skv@tempb}% } @@ -6151,7 +7368,7 @@ \edef\skv@tempa{\unexpanded{#1}}% \def\skv@tempb{}% % ##1=prefix, ##2=family - \def\do##1##2{% + \def\skv@pathdo##1##2{% \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% \skvkvparse*\skv@tempa\skv@tempa{% @@ -6167,13 +7384,13 @@ \noexpand\skvcsexit{##1/##2/####1.@defa}% }% }{% - \skv@err{Key '####1' is not in family '##1/##2'}\@ehd + \skv@err{Key '####1' is not in family '##1/##2'}\skv@ehd }% }% }% }% }% - \dirkeys@getcurrentroots\do + \dirkeys@pathlist \skvexpanded{\endgroup\skv@tempb}% } @@ -6184,7 +7401,7 @@ \edef\skv@tempa{\unexpanded{#1}}% \def\skv@tempb{}% % ##1=prefix, ##2=family - \def\do##1##2{% + \def\skv@pathdo##1##2{% \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% \skvkvparse*\skv@tempa\skv@tempa{% @@ -6197,38 +7414,47 @@ \noexpand\skvcsexit{##1/##2/####1.@value}% }% }{% - \skv@err{Key '####1' isn't in family '##1/##2'}\@ehd + \skv@err{Key '####1' isn't in family '##1/##2'}\skv@ehd }% }% }% }% }% - \dirkeys@getcurrentroots\do + \dirkeys@pathlist \skvexpanded{\endgroup\skv@tempb}% } -% \dirkeys@inherit{value.or.cbk.or.defa}{<list>} -\skvrobustdef*\dirkeys@inherit#1#2{% +% \dirkeys@inheritproperty{value.or.cbk.or.defa}{<list>} +\skvrobustdef*\dirkeys@inheritproperty#1#2{% + \begingroup + \def\skv@tempb{}% % Hid the list from the parameters of \do: \edef\skv@tempa{\unexpanded{#2}}% % ##1=prefix, ##2=family - \def\do##1##2{% + \def\skv@pathdo##1##2{% \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% \skvkvparse*\skv@tempa\skv@tempa{% - \expandafter\skv@slsplit\expandafter{\skv@tempa}{% + \skv@oslashsplit\skv@tempa{% + % \skv@oslashsplit may return ^skv^ for ####1 or ####2, but + % this doesn't matter here, since they will show that the keys + % aren't defined. \skvxifinTF{,\detokenize{####1},}{,\skvoxdetok\skv@igkeys,}{}{% \ifcase\skvifcsdefTF{##1/##2/####1.@cbk}{0}{1}% \skvifcsdefTF{##1/##2/####2.@cbk}{0}{1}\relax - \skvcsletcs{##1/##2/####1.@#1}{##1/##2/####2.@#1}% + \edef\skv@tempb{% + \skvexpandonce\skv@tempb + \skvcsletcs{##1/##2/####1.@#1}{##1/##2/####2.@#1}% + }% \else - \skv@err{Key '####1' or '####2' isn't in family '##1/##2'}\@ehd + \skv@err{Key '####1' or '####2' isn't in family '##1/##2'}\skv@ehd \fi }% }% }% }% - \dirkeys@getcurrentroots\do + \dirkeys@pathlist + \expandafter\endgroup\skv@tempb } % \dirkeys@setbooleanhandler{<handler>}{<boolean>}{<bool.value>} @@ -6241,17 +7467,17 @@ \csname#2#3\endcsname }{% \skv@err{Invalid value '\detokenize{#3}' for handler '#1': - \MessageBreak its expects either 'true' or 'false'}\@ehd + \MessageBreak its expects either 'true' or 'false'}\skv@ehd }% }% }{% - \skv@err{No boolean '\detokenize{#2}'}\@ehd + \skv@err{No boolean '\detokenize{#2}'}\skv@ehd }% } \skvrobustdef*\skv@ensurehandlerdot#1{% \if.\skv@car@detok#1x\car@nil\else - \skv@err{A dot (.) must lead handler name '#1'}\@ehd + \skv@err{A dot (.) must lead handler name '#1'}\skv@ehd \fi } \skvrobustdef*\dirkeys@handlerloop#1{% @@ -6259,478 +7485,745 @@ \skvstripouterbraces{2}\skv@tempa \skvkvparse*\skv@tempa } - +\skvnewdef*\dirkeys@reservedhandlers{} +\skvrobustdef*\skv@reservedhandlererr{% + \skv@err{Handler '##1' is reserved. + \MessageBreak Reserved handlers can't be redefined whatsoever}\skv@ehd +} +\skvrobustdef*\dirkeys@defhandlers@aux#1{% + \skvxifinTF{,#1,}{,\dirkeys@reservedhandlers,}{% + \skv@reservedhandlererr + }{% + \ifskv@inreservedhandler + \edef\dirkeys@reservedhandlers{% + \dirkeys@reservedhandlers + \ifx\dirkeys@reservedhandlers\@empty\else,\fi#1% + }% + \fi + \edef\skv@collection{% + \skvexpandonce\skv@collection + \protected\skvcsdef{dirkeys@handler@#1}\skvxonce\skv@param{% + % We can call \skvcurrenthandler in \skv@body, but when the + % handler is cast into another handler, the inheriting handler + % will not be the one in \skvcurrenthandler. + \def\noexpand\skvcurrenthandler{#1}% + \skvexpandonce\skv@body + }% + }% + }% +} % \dirkeys@defhandlers{<flag>}{<list>} +% % <flag> indicates if we're in <new> (01) or <define> (00) handler. +% \skvrobustdef*\dirkeys@defhandlers#1#2{% - \dirkeys@handlerloop{#2}\skv@tempa{% - \skv@kvosplit\skv@tempa{% - \skv@ensurehandlerdot{##1}% - \skvifplaswTF{#1}{% - \skvcsdef{dirkeys@handler@##1}####1{##2}% + \begingroup + \def\skv@collection{}% + \def\skv@param{####1\skvhandlereov}% + \def\skv@defhandlers@do##1{% + \skv@ensurehandlerdot{##1}% + \skvifplaswTF{#1}{% + \dirkeys@defhandlers@aux{##1}% + }{% + \skvifcsdefTF{dirkeys@handler@##1}{% + \skv@err{Handler '##1' arealdy exists}\skv@ehd }{% - \skvifcsdefTF{dirkeys@handler@##1}{% - \skv@err{Handler '##1' arealdy exists}\@ehd - }{% - \skvcsdef{dirkeys@handler@##1}####1\handlereov{##2}% - }% + \dirkeys@defhandlers@aux{##1}% }% }% }% + \dirkeys@handlerloop{#2}\skv@prova{% + \skv@okvsplit\skv@prova{% + % Hide the parameter characters in body: + \edef\skv@prova{\unexpanded{##1}}% + \skvstripouterbraces{2}\skv@prova + \edef\skv@body{\unexpanded{##2}}% + \skvcommaparse*\skv@prova\skv@prova{% + \expandafter\skv@defhandlers@do\expandafter{\skv@prova}% + }% + }% + }% + \skvexpanded{\endgroup + \skvexpandonce\skv@collection + \skvcmdexit\dirkeys@reservedhandlers + }% } - +% \dirkeys@defnarghandlers{<flag>}{<list>} +% % Define handlers of more than one argument. This is slightly more % expensive than '.new handlers': -% \dirkeys@defnarghandlers{<flag>}{<list>} -% <flag> indicates if we're in <new> (01) or <define> (00) handler. +% +% <flag> indicates whether we're in <new> (01) or <define> (00) handler. +% \skvrobustdef*\dirkeys@defnarghandlers#1#2{% - \dirkeys@handlerloop{#2}\skv@tempa{% - \skv@kvosplit\skv@tempa{% - \skv@ensurehandlerdot{##1}% - \def\skv@tempa####1####2\handler@nil{% - % ####2 must be hidden in a macro for later use in defining the - % handler: - \edef\skv@prova{\unexpanded{####2}}% - \edef\skv@tempa{\skvgenerateparameters{1}{####1}\handlereov}% - \def\skv@provb{% - \edef\skv@tempb{\protected\def\skvnoexpandcs{dirkeys@handler@##1}}% - \expandafter\expandafter\expandafter\skv@tempb\expandafter - \skv@tempa\expandafter{\skv@prova}% - }% - \skvifplaswTF{#1}{% - \skv@provb + \begingroup + \def\skv@collection{}% + \def\skv@defhandlers@do##1{% + \skv@ensurehandlerdot{##1}% + \def\skv@prova####1####2\handler@nil{% + \edef\skv@param{\skvgenerateparameters{1}{####1}\skvhandlereov}% + \edef\skv@body{\unexpanded{####2}}% + \skvifplaswTF{#1}{% + \dirkeys@defhandlers@aux{##1}% + }{% + \skvifcsdefTF{dirkeys@handler@##1}{% + \skv@err{Handler '##1' arealdy exists}\skv@ehd }{% - \skvifcsdefTF{dirkeys@handler@##1}{% - \skv@err{Handler '##1' arealdy exists}\@ehd - }{% - \skv@provb - }% + \dirkeys@defhandlers@aux{##1}% }% }% - \skv@tempa##2\handler@nil + }% + \expandafter\skv@prova\skv@provb\handler@nil + }% + \dirkeys@handlerloop{#2}\skv@prova{% + \skv@okvsplit\skv@prova{% + \edef\skv@prova{\unexpanded{##1}}% + \skvstripouterbraces{2}\skv@prova + % Here \skv@body is in \skv@defhandlers@do. + \edef\skv@provb{\unexpanded{##2}}% + \skvcommaparse*\skv@prova\skv@prova{% + \expandafter\skv@defhandlers@do\expandafter{\skv@prova}% + }% }% }% + \skvexpanded{\endgroup + \skvexpandonce\skv@collection + \skvcmdexit\dirkeys@reservedhandlers + }% } - % \dirkeys@handlerlet{<flag>}{<kvlist>} -% <flag> is either 00 (for define) or 01 (for new handler). +% +% 1. <flag> is either 00 (for define) or 01 (for new handler). +% 2. <kvlist> has the form +% +% {<child handler list>}={<parent handler>} +% \skvrobustdef*\dirkeys@handlerlet#1#2{% - \dirkeys@handlerloop{#2}\skv@tempa{% - \skv@kvosplit\skv@tempa{% - \skvifcsdefFT{dirkeys@handler@##2}{% - \skv@err{Handler '##2' doesn't exist}\@ehd + \begingroup + \def\skv@collection{}% + \def\skv@handlerlet@do##1##2{% + \skvifblankTF{##1}{}{% + \skvxifinTF{,##1,}{,\dirkeys@reservedhandlers,}{% + \skv@reservedhandlererr }{% - \skvifblankTF{##1}{% - \skv@err{No child handler}\@ehd - }{% - \skvifplaswTF{#1}{}{% - \skvifcsdefFT{dirkeys@handler@##1}{}{% - \skv@err{Handler '##1' arealdy exists}\@ehd - }% + \ifskv@inreservedhandler + \edef\dirkeys@reservedhandlers{% + \dirkeys@reservedhandlers + \ifx\dirkeys@reservedhandlers\@empty\else,\fi##1% }% + \fi + \skvifplaswTF{#1}{}{% + \skvifnamedefFT{dirkeys@handler@##1}{}{% + \skv@err{Handler '##1' arealdy exists}\skv@ehd + }% + }% + \edef\skv@collection{% + \skvexpandonce\skv@collection \skvcsletcs{dirkeys@handler@##1}{dirkeys@handler@##2}% }% }% }% }% + \dirkeys@handlerloop{#2}\skv@tempa{% + \skv@okvsplit\skv@tempa{% + \skvifnamedefTF{dirkeys@handler@##2}{% + \skvcommaparse{##1}\skv@prova{% + \skvexpbracenext\skv@handlerlet@do\skv@prova{##2}% + }% + }{% + \skv@err{Handler '##2' doesn't exist}\skv@ehd + }% + }% + }% + \expandafter\endgroup\skv@collection } \skvrobustdef*\skvusehandler#1#2{% \skv@ensurehandlerdot{#1}% - \skvifcsdefTF{dirkeys@handler@#1}{% - \csname dirkeys@handler@#1\endcsname#2\handlereov + \skvifnamedefTF{dirkeys@handler@#1}{% + \csname dirkeys@handler@#1\endcsname#2\skvhandlereov }{% - \skv@err{Handler '#1' is undefined}\@ehd + \skv@err{Handler '#1' is undefined}\skv@ehd }% } % The macro that contains the default command in which unknown keys -% will be saved by some handlers of \dirkeys: +% will be saved by some handlers of \directkeys: \skvnewdef*\dirkeys@unknownkeysmacro{\skvfaillist} % Notes: -% 1. '.new handlers' must be defined outsied \dirkeys, since it is -% the one that defines every other handler. +% 1. '.new reserved handlers' must be defined outsied \directkeys, +% since we have used it here to defines every other handler. % 2. It defines definable handlers of one or more arguments. See also -% '.define handlers' later on (within the next call of \dirkeys). -\skvrobustcsdef*{dirkeys@handler@.new handlers}#1\handlereov{% +% '.define handlers' later on (within the next call of \directkeys). +% +\skvrobustcsdef*{dirkeys@handler@.new reserved handlers}#1\skvhandlereov{% + \skv@inreservedhandlertrue \dirkeys@defhandlers{01}{#1}% -} - -\dirkeys*{% - .new handlers={% - .exec code=#1, - .define handlers=\dirkeys@defhandlers{00}{#1}, - .define narg handlers=\dirkeys@defnarghandlers{00}{#1}, - .new narg handlers=\dirkeys@defnarghandlers{01}{#1}, - .kill handlers={% - \dirkeys@handlerloop{#1}\skv@tempa{% - \skvifcsdefTF{dirkeys@handler@\skv@tempa}{% - \skvcsundef{dirkeys@handler@\skv@tempa}% - }{% - \skv@err{Handler '\skv@tempa' is undefined}\@ehd - }% - }% + \skv@inreservedhandlerfalse +} +\directkeys*{% + % Defining new handlers that can't be overloaded: + .new reserved handlers={ + % '.new reserved handlers' and '.define reserved handlers' are the + % same thing since reserved handlers can't be overridden or overloaded. + {.new reserved handler,.define reserved handlers, + .define reserved handler}={ + \skvusehandler{.new reserved handlers}{#1} + }, + {.exec,.exec code}={#1}, + {.define handler,.define handlers}={ + \dirkeys@defhandlers{00}{#1} + }, + {.new handler,.new handlers}={ + \dirkeys@defhandlers{01}{#1} + }, + {.define narg handler,.define narg handlers}={ + \dirkeys@defnarghandlers{00}{#1} + }, + {.new narg handler,.new narg handlers}={ + \dirkeys@defnarghandlers{01}{#1} + }, + % See comment above about '.new reserved handlers': + {.new reserved narg handler,.new reserved narg handlers, + .define reserved narg handler,.define reserved narg handlers}={ + \skv@inreservedhandlertrue + \dirkeys@defnarghandlers{01}{#1} + \skv@inreservedhandlerfalse + }, + {.reserve handlers,.reserve handler}={ + \edef\skv@prova{\unexpanded{#1}}% + \skvstripouterbraces{2}\skv@prova + \skvcsvnormalize\skv@prova + \edef\dirkeys@reservedhandlers{ + \dirkeys@reservedhandlers + \ifx\dirkeys@reservedhandlers\@empty\else,\fi\skv@prova + } + }, + {.kill handler,.kill handlers}={ + \dirkeys@handlerloop{#1}\skv@tempa{ + \skvifcsdefTF{dirkeys@handler@\skv@tempa}{ + \skvcsundef{dirkeys@handler@\skv@tempa} + }{ + \skv@err{Handler '\skv@tempa' is undefined}\skv@ehd + } + } }, .use handler=\skvusehandler{#1}, - .handler let*=\dirkeys@handlerlet{00}{#1}, - .handler let=\dirkeys@handlerlet{01}{#1}, - .prefixes={% - \def\dirkeys@prefixlist{}% - \skvusehandler{.add prefixes}{#1}% - }, - .default prefix={% - \skvdefaultprefix{#1} - }, - .add prefixes={% - \skv@clfalse\skv@mergelist\dirkeys@prefixlist{#1}% - }, - .families={% - \def\dirkeys@familylist{}% - \skvusehandler{.add families}{#1}% - }, - .add families={% - \skv@clfalse\skv@mergelist\dirkeys@familylist{#1}% - }, - .roots={% - \def\dirkeys@prefixlist{}% - \def\dirkeys@familylist{}% - \skvusehandler{.add roots}{#1}% - }, - .add roots={% - \dirkeys@addorremoveroots{#1}\skvmergelist - }, - .ignore roots={% - \dirkeys@addorremoveroots{#1}\skvremoveelements - }, - .restore roots={% - \skvusehandler{.add roots}{#1}% - }, - .ignore prefixes=\skvremoveelements\dirkeys@prefixlist{#1}, - .restore prefixes=\skvmergelist\dirkeys@prefixlist{#1}, - .ignore families=\skvremoveelements\dirkeys@familylist{#1}, - .restore families=\skvmergelist\dirkeys@familylist{#1}, - .ignore keys={% - \def\skv@doonroot##1##2{% - \expandafter\skvmergelist - \csname##1/##2/.@ignoredkeys\endcsname{#1}% - }% - \dirkeys@getcurrentroots\skv@doonroot + % Allow override: + {.handler let*,.handlers let*,.let handler*,.let handlers*, + .force handler let}={ + \dirkeys@handlerlet{00}{#1} + }, + % Disallow override: + {.handler let,.handlers let,.let handler,.let handlers}={ + \dirkeys@handlerlet{01}{#1} + }, + % Let and reserved handlers: + {.handler let reserved,.handlers let reserved}={ + \skv@inreservedhandlertrue + \dirkeys@handlerlet{01}{#1} + \skv@inreservedhandlerfalse + }, + {.paths,.path,.change path,.change paths,.cd}={ + \def\dirkeys@pathlist{}\dirkeys@addpaths{#1} + }, + {.add path,.add paths}={ + \dirkeys@addpaths{#1} + }, + {.ignore path,.ignore paths}={ + \dirkeys@removepaths{#1} + }, + {.restore path,.restore paths}={ + \dirkeys@addpaths{#1} }, - .restore keys={% - \def\skv@doonroot##1##2{% + % Prefix is used in building \dirkeys@pathlist in '.family' handler. + % There must be only one current prefix. Use .path to submit multiple + % prefixes and families. + {.prefix,.change prefix}={ + \skv@ifoneprefix{#1}{ + \edef\dirkeys@pref{#1} + \skvstripouterbraces{2}\dirkeys@pref + }{ + \skv@err{List of prefixes isn't allowed for handler + \MessageBreak '.prefix' in \string\directkeys. You can use + \MessageBreak '.paths' to submit multiple prefixes and + \MessageBreak families}\skv@ehd + } + }, + % Since there can be only one prefix, you couldn't ignore it. + {.prefixes,.change prefixes,.ignore prefix,.ignore prefixes}={ + \skv@err{No handler '\skvcurrenthandler'}\skv@ehd + }, + % See .change path for .cd: + {.families,.family,.change family,.change families,.cf}={ + \edef\dirkeys@fams{#1} + \skvstripouterbraces{2}\dirkeys@fams + \def\dirkeys@pathlist{}% + \skv@makepaths\dirkeys@pref\dirkeys@fams\dirkeys@pathlist\skv@pathdo + }, + {.add family,.add families}={ + \edef\dirkeys@fams{#1} + \skvstripouterbraces{2}\dirkeys@fams + \skv@makepaths\dirkeys@pref\dirkeys@fams\dirkeys@pathlist\skv@pathdo + }, + {.ignore family,.ignore families}={ + \dirkeys@removefams{#1} + }, + {.restore family,.restore families}={ + \skvusehandler{.add family}{#1} + }, + {.ignore key,.ignore keys}={ + \skv@pushpathdo + \def\skv@pathdo##1##2{ + \expandafter\skvmergelist\csname##1/##2/.@ignoredkeys\endcsname{#1} + } + \dirkeys@pathlist + \skv@poppathdo + }, + {.restore key,.restore keys}={ + \skv@pushpathdo + \def\skv@pathdo##1##2{ \expandafter\skvremoveelements - \csname##1/##2/.@ignoredkeys\endcsname{#1}% - }% - \dirkeys@getcurrentroots\skv@doonroot - }, - .holder prefix=\def\dirkeys@holderprefixtoks{#1}, - .push prefixes=\dirkeys@pushmeta{prefix}, - .pop prefixes=\dirkeys@popmeta{prefix}, - .push families=\dirkeys@pushmeta{family}, - .pop families=\dirkeys@popmeta{family}, - .push paths=\dirkeys@pushmeta{prefix}\dirkeys@pushmeta{family}, - .pop paths=\dirkeys@popmeta{prefix}\dirkeys@popmeta{family}, - .push holder prefix=\dirkeys@pushmeta{hp}, - .pop holder prefix=\dirkeys@popmeta{hp}, - .save unknown keys={% + \csname##1/##2/.@ignoredkeys\endcsname{#1} + } + \dirkeys@pathlist + \skv@poppathdo + }, + {.holder prefix,.hp}={ + \def\dirkeys@holderprefixtoks{#1} + }, + % There is no need pushing prefix or family, since they're made + % into paths by their key callbacks. + {.push path,.push paths}={ + \dirkeys@pushmeta{path} + }, + {.pop path,.pop paths}={ + \dirkeys@popmeta{path} + }, + {.push holder prefix,.push hp}={ + \dirkeys@pushmeta{hp} + }, + {.pop holder prefix,.pop hp}={ + \dirkeys@popmeta{hp} + }, + .save unknown keys={ \dirkeys@setbooleanhandler - {.save unknown keys}{dirkeys@saveunknownkeys}{#1}% + {.save unknown keys}{dirkeys@saveunknownkeys}{#1} }, - .save unknown keys in={% - \skvifblankTF{#1}{}{% - \skvifescapedTF{#1}{% + .save unknown keys in={ + \skvifblankTF{#1}{% + \skv@err{Empty value for handler '.save unknown keys in'}\skv@ehd + }{ + \skvifescapedTF{#1}{ \dirkeys@saveunknownkeystrue - \def\dirkeys@unknownkeysmacro{#1}% - }{% - \skv@err{Token '\detokenize{#1}' is not escaped}\@ehd - }% - }% + \def\dirkeys@unknownkeysmacro{#1} + }{ + \skv@err{Token '\detokenize{#1}' is not escaped}\skv@ehd + } + } }, - .define keys=\skv@handlerswafalse\dirkeys@dodefinekeys{#1}, - .new keys=\skv@handlerswatrue\dirkeys@dodefinekeys{#1}, - .initialize keys after define={% - \skvusehandler{.set boolean handler}{% - {.initialize keys after define}{skvdfk@initialize}{#1}% - }% + {.define key,.define keys}={ + \dirkeys@dodefinekeys{}{#1} + }, + {.new key,.new keys}={ + \dirkeys@dodefinekeys{*}{#1} + }, + {.define ordinary key,.define ordinary keys,.define ord keys}={ + \dirkeys@definetypekeys{ord}{}{#1} + }, + {.new ordinary key,.new ordinary keys,.new ord keys}={ + \dirkeys@definetypekeys{ord}{*}{#1} + }, + {.define command key,.define command keys,.define cmd keys}={ + \dirkeys@definetypekeys{cmd}{}{#1} + }, + {.new command key,.new command keys,.new cmd keys}={ + \dirkeys@definetypekeys{cmd}{*}{#1} + }, + {.define boolean key,.define boolean keys,.define bool keys}={ + \dirkeys@definetypekeys{bool}{}{#1} + }, + {.new boolean key,.new boolean keys,.new bool keys}={ + \dirkeys@definetypekeys{bool}{*}{#1} + }, + {.define toggle key,.define toggle keys,.define tog keys}={ + \dirkeys@definetypekeys{bool}{}{#1} + }, + {.new toggle key,.new toggle keys,.new tog keys}={ + \dirkeys@definetypekeys{bool}{*}{#1} + }, + {.define choice key,.define choice keys}={ + \dirkeys@definetypekeys{choice}{}{#1} + }, + {.new choice key,.new choice keys}={ + \dirkeys@definetypekeys{choice}{*}{#1} }, - .save initial values of keys={% + {.initialize keys after define,.initialize after define}={ \dirkeys@setbooleanhandler - {.save initial values of keys}{skvdfk@saveinitialvalues}{#1}% + {.initialize keys after define}{skvdfk@initialize}{#1} }, - .set keys={% - \skv@handlerswafalse\skv@handlerswbfalse - \dirkeys@dosetkeys{#1}\skvsetkeys + {.save initial values of keys,.save initial values}={ + \dirkeys@setbooleanhandler + {.save initial values of keys}{skvdfk@saveinitialvalues}{#1} }, - .set keys*={% - \skv@handlerswatrue\skv@handlerswbfalse - \dirkeys@dosetkeys{#1}\skvsetkeys + {.set keys,.setkeys,.set}={ + \dirkeys@setkeys{}{}\skvsetkeys{#1} }, - .set rmkeys={% - \skvifblankTF{#1}{% - \skv@handlerswafalse\skv@handlerswbtrue - \dirkeys@dosetkeys{}\skvsetrmkeys - }{% + {.set keys*,.setkeys*,.set*,.setkeys save unknown, + .set keys save unknown}={ + \dirkeys@setkeys{*}{}\skvsetkeys{#1} + }, + {.set rmkeys,.setrmkeys,.set remaining keys}={ + \skvifblankTF{#1}{ + \dirkeys@setkeys{}{rm}\skvsetrmkeys{} + }{ \skv@err{Key 'set rmkeys' can't have value: \MessageBreak Instead use the key 'ignore keys' \MessageBreak to suggest keys to be ignored - \MessageBreak when setting 'rmkeys'}\@ehd - }% + \MessageBreak when setting 'rmkeys'}\skv@ehd + } }, - .set rmkeys*={% - \skvifblankTF{#1}{% - \skv@handlerswatrue\skv@handlerswbtrue - \dirkeys@dosetkeys{}\skvsetrmkeys - }{% + {.set rmkeys*,.setrmkeys*,.set remaining keys*}={ + \skvifblankTF{#1}{ + \dirkeys@setkeys{*}{rm}\skvsetrmkeys{} + }{ \skv@err{Key 'set rmkeys*' can't have value: - \MessageBreak Instead use the key 'ignore keys' to suggest keys - \MessageBreak to be ignored when setting rmkeys}\@ehd - }% + \MessageBreak Instead use the handler '.ignore keys' to suggest keys + \MessageBreak to be ignored when setting rmkeys}\skv@ehd + } + }, + % '.try set keys' doesn't use the active prefixes and families within + % \directkeys. The prefix, families and other options are to be supplied + % in the argument #1. The key .key values (or .kv) is used to + % supply the key-value pairs. + % .try set keys={<options>} + {.try set keys,.try set,.try}={ + \dirkeys@trysetkeys{#1} + }, + % 'search also' set keys. + % .sa set keys={<options>} + {.search also set keys,.sa set keys}={ + \dirkeys@sasetkeys{#1} + }, + {.presetkeys,.preset keys}={ + \dirkeys@dolistedkeys@a{#1}\skv@presetkeys + }, + .gpreset keys={ + \dirkeys@dolistedkeys@a{#1}\skv@gpresetkeys + }, + .remove preset keys={ + \dirkeys@dolistedkeys@a{#1}\skvremovepresetkeys + }, + .gremove preset keys={ + \dirkeys@dolistedkeys@a{#1}\skvgremovepresetkeys + }, + .undefine preset keys={ + \skv@clfalse\dirkeys@dolistedkeys@b\skv@undefpresetkeys + }, + .gundefine preset keys={ + \skv@cltrue\dirkeys@dolistedkeys@b\skv@undefpresetkeys + }, + {.postsetkeys,.postset keys}={ + \dirkeys@dolistedkeys@a{#1}\skv@postsetkeys + }, + .gpostset keys={ + \dirkeys@dolistedkeys@a{#1}\skv@gpostsetkeys + }, + .remove postset keys={ + \dirkeys@dolistedkeys@a{#1}\skvremovepostsetkeys + }, + .gremove postset keys={ + \dirkeys@dolistedkeys@a{#1}\skvgremovepostsetkeys + }, + .undefine postset keys={ + \skv@clfalse\dirkeys@dolistedkeys@b\skv@undefpostsetkeys + }, + .gundefine postset keys={ + \skv@cltrue\dirkeys@dolistedkeys@b\skv@undefpresetkeys + }, + .option keys={ + \dirkeys@dolistedkeys@a{#1}\skvoptionkeys + }, + .goption keys={ + \dirkeys@dolistedkeys@a{#1}\skvgoptionkeys + }, + .remove option keys={ + \dirkeys@dolistedkeys@a{#1}\skvremoveoptionkeys + }, + .gremove option keys={ + \dirkeys@dolistedkeys@a{#1}\skvgremoveoptionkeys + }, + .nonoption keys={ + \dirkeys@dolistedkeys@a{#1}\skvnonoptionkeys + }, + .gnonoption keys={ + \dirkeys@dolistedkeys@a{#1}\skvgnonoptionkeys + }, + .remove nonoption keys={ + \dirkeys@dolistedkeys@a{#1}\skvremovenonoptionkeys + }, + .gremove nonoption keys={ + \dirkeys@dolistedkeys@a{#1}\skvgremovenonoptionkeys + }, + .need value keys={ + \dirkeys@dolistedkeys@a{#1}\skvneedvaluekeys + }, + .gneed value keys={ + \dirkeys@dolistedkeys@a{#1}\skvgneedvaluekeys + }, + .remove need value keys={ + \dirkeys@dolistedkeys@a{#1}\skvremoveneedvaluekeys + }, + .gremove need value keys={ + \dirkeys@dolistedkeys@a{#1}\skvgremoveneedvaluekeys + }, + .forbid value keys={ + \dirkeys@dolistedkeys@a{#1}\skvforbidvaluekeys + }, + .gforbid value keys={ + \dirkeys@dolistedkeys@a{#1}\skvgforbidvaluekeys + }, + .remove forbid value keys={ + \dirkeys@dolistedkeys@a{#1}\skvremoveforbidvaluekeys + }, + .gremove forbid value keys={ + \dirkeys@dolistedkeys@a{#1}\skvgremoveforbidvaluekeys + }, + .save initial value keys={ + \dirkeys@dolistedkeys@a{#1}\skvsaveinitialvaluekeys + }, + .gsave initial value keys={ + \dirkeys@dolistedkeys@a{#1}\skvgsaveinitialvaluekeys + }, + .remove save initial value keys={ + \dirkeys@dolistedkeys@a{#1}\skvremovesaveinitialvaluekeys + }, + .gremove save initial value keys={ + \dirkeys@dolistedkeys@a{#1}\skvgremovesaveinitialvaluekeys + }, + .undefine save initial value keys={ + \dirkeys@dolistedkeys@a{#1}\skvundefsaveinitialvaluekeys + }, + .gundefine save initial value keys={ + \dirkeys@dolistedkeys@a{#1}\skvgundefsaveinitialvaluekeys + }, + {.disable keys,.disable key}={ + \dirkeys@dolistedkeys@a{#1}\skvdisablekeys + }, + {.disabled key message type,.disabled key exception type}={ + \skvdisabledkeysmessagetype{#1} }, - .preset keys=\dirkeys@dolistedkeys@a{#1}\skv@presetkeys, - .gpreset keys=\dirkeys@dolistedkeys@a{#1}\skv@gpresetkeys, - .remove preset keys= - \dirkeys@dolistedkeys@a{#1}\skvremovepresetkeys, - .gremove preset keys= - \dirkeys@dolistedkeys@a{#1}\skvgremovepresetkeys, - .undefine preset keys= - \skv@clfalse\dirkeys@dolistedkeys@b\skv@undefpresetkeys, - .gundefine preset keys= - \skv@cltrue\dirkeys@dolistedkeys@b\skv@undefpresetkeys, - .postset keys=\dirkeys@dolistedkeys@a{#1}\skv@postsetkeys, - .gpostset keys=\dirkeys@dolistedkeys@a{#1}\skv@gpostsetkeys, - .remove postset keys=\dirkeys@dolistedkeys@a{#1}\skvremovepostsetkeys, - .gremove postset keys=\dirkeys@dolistedkeys@a{#1}\skvgremovepostsetkeys, - .undefine postset keys= - \skv@clfalse\dirkeys@dolistedkeys@b\skv@undefpostsetkeys, - .gundefine postset keys= - \skv@cltrue\dirkeys@dolistedkeys@b\skv@undefpresetkeys, - .need value keys=\dirkeys@dolistedkeys@a{#1}\skvneedvaluekeys, - .gneed value keys=\dirkeys@dolistedkeys@a{#1}\skvgneedvaluekeys, - .remove need value keys= - \dirkeys@dolistedkeys@a{#1}\skvremoveneedvaluekeys, - .gremove need value keys= - \dirkeys@dolistedkeys@a{#1}\skvgremoveneedvaluekeys, - .forbid value keys= - \dirkeys@dolistedkeys@a{#1}\skvforbidvaluekeys, - .gforbid value keys= - \dirkeys@dolistedkeys@a{#1}\skvgforbidvaluekeys, - .remove forbid value keys= - \dirkeys@dolistedkeys@a{#1}\skvremoveforbidvaluekeys, - .gremove forbid value keys= - \dirkeys@dolistedkeys@a{#1}\skvgremoveforbidvaluekeys, - .save initial value keys= - \dirkeys@dolistedkeys@a{#1}\skvsaveinitialvaluekeys, - .gsave initial value keys= - \dirkeys@dolistedkeys@a{#1}\skvgsaveinitialvaluekeys, - .remove save initial value keys= - \dirkeys@dolistedkeys@a{#1}\skvremovesaveinitialvaluekeys, - .gremove save initial value keys= - \dirkeys@dolistedkeys@a{#1}\skvgremovesaveinitialvaluekeys, - .undefine save initial value keys= - \dirkeys@dolistedkeys@a{#1}\skvundefsaveinitialvaluekeys, - .gundefine save initial value keys= - \dirkeys@dolistedkeys@a{#1}\skvgundefsaveinitialvaluekeys, - .disable keys=\dirkeys@dolistedkeys@a{#1}\skvdisablekeys, - .disabled key message type={\skvdisabledkeysmessagetype{#1}}, % Choices are always appended; never prepended, since the parent % key must first be set before choices are executed. % <key1>/{<ch1>.do={<act1>},...,<ch-n>.do={<act-n>}},..., % <key-n>/{<ch1>.do={<act1>},...,<ch-n>.do={<act-n>}} - .state pattern=\dirkeys@savechoice{#1}{x0}, - .state pattern expand once=\dirkeys@savechoice{#1}{x1}, - .state pattern expand twice=\dirkeys@savechoice{#1}{x2}, - .state pattern expanded=\dirkeys@savechoice{#1}{xx}, - % {<key-i>,...,<key-j>}/{<stylelist-ij>},..., - % {<key-n>,...,<key-m>}/{<stylelist-nm>}: - .append style=\dirkeys@savestyle{#1}{app}{x0}, - .prepend style=\dirkeys@savestyle{#1}{prep}{x0}, - .append style expanded=\dirkeys@savestyle{#1}{app}{xx}, - .prepend style expanded=\dirkeys@savestyle{#1}{prep}{xx}, - .append style expand once=\dirkeys@savestyle{#1}{app}{x1}, - .prepend style expand once=\dirkeys@savestyle{#1}{prep}{x1}, - .append style expand twice=\dirkeys@savestyle{#1}{app}{x2}, - .prepend style expand twice=\dirkeys@savestyle{#1}{prep}{x2}, + {.state pattern,.choice,.nominations}={ + \dirkeys@savechoice{#1}{x0} + }, + .state pattern expand once={ + \dirkeys@savechoice{#1}{x1} + }, + .state pattern expand twice={ + \dirkeys@savechoice{#1}{x2} + }, + {.state pattern expanded,.estate pattern,.enominations,.echoice}={ + \dirkeys@savechoice{#1}{xx} + }, + % {<key-i>,...,<key-j>}/{<slotlist-ij>},..., + % {<key-n>,...,<key-m>}/{<slotlist-nm>}: + {.append slot,.append slots,.slot,.slots,.style,.styles,.observers}={ + \dirkeys@saveslots{#1}{app}{x0} + }, + {.prepend slot,.prepend slots}={ + \dirkeys@saveslots{#1}{prep}{x0} + }, + {.append slot value expanded,.append slot expanded, + .append slots value expanded,.append slots expanded, + .eslot,.eslots,.estyle,.estyles}={ + \dirkeys@saveslots{#1}{app}{xx} + }, + {.prepend slot value expanded,.prepend slot expanded, + .prepend slots value expanded,.prepend slots expanded}={ + \dirkeys@saveslots{#1}{prep}{xx} + }, + {.append slot expand value once,.append slot expand once, + .append slots expand value once,.append slots expand once, + .slot expand once,.slots expand once,.style expand once, + .styles expand once}={ + \dirkeys@saveslots{#1}{app}{x1} + }, + {.prepend slot expand value once,.prepend slot expand once, + .prepend slots expand value once,.prepend slots expand once}={ + \dirkeys@saveslots{#1}{prep}{x1} + }, + {.append slot expand value twice,.append slot expand twice, + .append slots expand value twice,.append slots expand twice, + .slot expand twice,.slots expand twice,.style expand twice, + .styles expand twice}={ + \dirkeys@saveslots{#1}{app}{x2} + }, + {.prepend slot expand value twice,.prepend slot expand twice, + .prepend slots expand value twice,.prepend slots expand twice}={ + \dirkeys@saveslots{#1}{prep}{x2} + }, % {<linklist-1>}/<mainkeylist-1>,...,{<linklist-n>}/<mainkeylist-n>: - .append link=\dirkeys@savelink{#1}{app}{x0}, - .prepend link=\dirkeys@savelink{#1}{prep}{x0}, - .append link expanded=\dirkeys@savelink{#1}{app}{xx}, - .prepend link expanded=\dirkeys@savelink{#1}{prep}{xx}, - .append link expand once=\dirkeys@savelink{#1}{app}{x1}, - .prepend link expand once=\dirkeys@savelink{#1}{prep}{x1}, - .append link expand twice=\dirkeys@savelink{#1}{app}{x2}, - .prepend link expand twice=\dirkeys@savelink{#1}{prep}{x2}, - .list break=\skvbreaklooptrue, - .args=\dirkeys@assignarg{#1}{x0}, + {.append link,.append links,.link,.links}={ + \dirkeys@savelinks{#1}{app}{x0} + }, + {.prepend link,.prepend links}={ + \dirkeys@savelinks{#1}{prep}{x0} + }, + {.append link expanded value,.append link expanded, + .append links expanded value,.append links expanded,.elink,.elinks}={ + \dirkeys@savelinks{#1}{app}{xx} + }, + {.prepend link expanded value,.prepend link expanded, + .prepend links expanded value,.prepend links expanded}={ + \dirkeys@savelinks{#1}{prep}{xx} + }, + {.append link expand value once,.append link expand once, + .append links expand value once,.append links expand once, + .link expand once,.links expand once}={ + \dirkeys@savelinks{#1}{app}{x1} + }, + {.prepend link expand value once,.prepend link expand once, + .prepend links expand value once,.prepend links expand once}={ + \dirkeys@savelinks{#1}{prep}{x1} + }, + {.append link expand value twice,.append link expand twice, + .append links expand value twice,.append links expand twice, + .link expand twice,.links expand twice}={ + \dirkeys@savelinks{#1}{app}{x2} + }, + {.prepend link expand value twice,.prepend link expand twice, + .prepend links expand value twice,.prepend links expand twice}={ + \dirkeys@savelinks{#1}{prep}{x2} + }, + % .store value in={key1,key2}/<cmd>: + .store value in={ + \dirkeys@savestores{#1}{x0} + }, + {.store expanded value in,.store evalue in}={ + \dirkeys@savestores{#1}{xx} + }, + .store expanded once value in={ + \dirkeys@savestores{#1}{x1} + }, + .store expanded twice value in={ + \dirkeys@savestores{#1}{x2} + }, + {.list break,.listbreak,.break list}={ + \skvbreaklooptrue + }, + {.arg,.args}={ + \dirkeys@assignarg{#1}{x0} + }, % Expand arguments of keys at key setting time, not at key definition: - .args expanded=\dirkeys@assignarg{#1}{xx}, - .args expanded once=\dirkeys@assignarg{#1}{x1}, - .args expanded twice=\dirkeys@assignarg{#1}{x2}, - .set with defaults={ + {.arg expanded,.args expanded}={ + \dirkeys@assignarg{#1}{xx} + }, + {.arg expand once,.args expand once}={ + \dirkeys@assignarg{#1}{x1} + }, + {.arg expand twice,.args expand twice}={ + \dirkeys@assignarg{#1}{x2} + }, + {.use defaults,.set with defaults}={ \dirkeys@dolistedkeys@a{#1}\dirkeys@setwithdefaults }, - .unknown key handler={ - \dirkeys@dounknownkeyhandler{#1} + {.unknown key handler,.unknown option handler}={ + \dirkeys@setunknownkeyhandler{#1} }, % Redefine the default value macros of keys. % .default values={keya=vala,...,keyn=valn} - .default values={% + {.default value,.default values,.default,.defaults}={ \dirkeys@assigndefault{#1} }, % Change the current values of keys. % .assign values={keya=vala,...,keyn=valn} - .assign values={% + {.assign value,.assign values}={ \dirkeys@assignvalue{#1} }, + {.inherit,.keys let,.key let}={ + \dirkeys@keyslet{#1} + }, % A key inherits value from a key. % .inherit values={keya1/keya2,...,keyn1/keyn2} - .inherit values={% - \dirkeys@inherit{value}{#1} + {.inherit value,.inherit values}={ + \dirkeys@inheritproperty{value}{#1} }, - .inherit callback={% - \dirkeys@inherit{cbk}{#1} + {.inherit callback,.inherit callbacks,.inherit code}={ + \dirkeys@inheritproperty{cbk}{#1} }, - .inherit defaults={% - \dirkeys@inherit{defa}{#1} + {.inherit default,.inherit defaults}={ + \dirkeys@inheritproperty{defa}{#1} }, - % .prepend values={keya=vala,...,keyn=valn} - .prepend values={% + % .prepend values={key1=val1,...,keyn=valn} + {.prepend value,.prepend values}={ \dirkeys@addtocodeorvalue{pre}{value}{#1} }, - .append values={% + {.append value,.append values}={ \dirkeys@addtocodeorvalue{app}{value}{#1} }, - % .prepend code={keya=codea,...,keyn=coden} - .prepend code={% + % .prepend code={key1=code1,...,keyn=coden} + {.prepend code,.prepend codes}={ \dirkeys@addtocodeorvalue{pre}{cbk}{#1} }, - .append code={% + {.append code,.append codes}={ \dirkeys@addtocodeorvalue{app}{cbk}{#1} }, }, - .new narg handlers={% - .no such key={4}{% - % All the parameters would have been despaced when this handler - % is called. #1=prefix, #2=family, #3=key, #4=value. - \skvifcsdefTF{#1@#2@handler}{% + .new narg handlers={ + % All the parameters would have been despaced when '.no such key' + % is called. #1=prefix, #2=family, #3=key, #4=value. + .no such key={4}{ + \skvifcsdefTF{#1@#2@handler}{ \csname#1@#2@handler\endcsname{#1}{#2}{#3}{#4} - }{% - \skv@err{Key '#3' is not in family '#1/#2'}\@ehd - }% + }{ + \skv@err{Key '#3' is not in family '#1/#2'}\skv@ehd + } }, - .add style={2}{% - \skvusehandler{.prepend style}{#1}% - \skvusehandler{.append style}{#2}% + .add slot={2}{ + \skvusehandler{.prepend slot}{#1} + \skvusehandler{.append slot}{#2} }, - .add code={2}{% - \skvusehandler{.prepend code}{#1}% - \skvusehandler{.append code}{#2}% + .add code={2}{ + \skvusehandler{.prepend code}{#1} + \skvusehandler{.append code}{#2} }, - .add value={2}{% - \skvusehandler{.prepend value}{#1}% - \skvusehandler{.append value}{#2}% + .add value={2}{ + \skvusehandler{.prepend value}{#1} + \skvusehandler{.append value}{#2} }, % .get value={<pref>}{<fam>}{<key>}<cmd> - .get value={4}{% - \skvifcsdefTF{#1/#2/#3.@value}{% - \skvifescapedTF{#4}{% - \skvletcs#4{#1/#2/#3.@value}% - }{% - \skv@err{Token '\detokenize{#4}' isn't escaped}\@ehd - }% - }{% + .get value={4}{ + \skvifnamedefTF{#1/#2/#3.@value}{ + \skvifescapedTF{#4}{ + \skvletcs#4{#1/#2/#3.@value} + }{ + \skv@err{Token '\detokenize{#4}' isn't escaped}\skv@ehd + } + }{ \skv@err{Key '#3' isn't defined or has - \MessageBreak no value in '#1/#2'}\@ehd - }% + \MessageBreak no value in '#1/#2'}\skv@ehd + } }, - % '.try set keys' doesn't use the active prefixes and families within - % \dirkeys. The prefix, families and other options are to be supplied - % in the argument #1. The key .key values (or .kv) is used to - % supply the key-value pairs. - % .try set keys={<options>} - .try set keys={1}{\dirkeys@trysetkeys{#1}}, - % 'search also' set keys. - % .sa set keys={<options>} - .sa set keys={1}{\dirkeys@sasetkeys{#1}}, - % .set boolean handler={<handler>}{<boolean>}{<value>} - .set boolean handler={3}{% + % .set boolean handler={<handler>}{<boolean>}{<boolean.value>} + % See example use above. + .set boolean handler={3}{ \dirkeys@setbooleanhandler{#1}{#2}{#3} }, }, - .handler let={% - .exec=.exec code, - .handlers let=.handler let, - .prefix=.prefixes, .change prefix=.prefix, .cp=.prefix, - .add prefix=.add prefixes, - .ignore prefix=.ignore prefixes, - .restore prefix=.restore prefixes, - .hp=.holder prefix, - .family=.families, .change family=.family, .cf=.family, - .add family=.add families, - .ignore family=.ignore families, - .restore family=.restore families, - .root=.roots, .change root=.roots, .cd=.roots, - .path=.roots, .paths=.roots, .change path=.roots, - .add root=.add roots, - .add path=.add roots, .add paths=.add roots, - .ignore root=.ignore roots, - .ignore path=.ignore roots, .ignore paths=.ignore roots, - .restore root=.restore roots, - .restore path=.restore roots, .restore paths=.restore roots, - .push prefix=.push prefixes, .pop prefix=.pop prefixes, - .push family=.push families, .pop family=.pop families, - .push path=.push paths, .pop path=.pop paths, - .push hp=.push holder prefix, .pop hp=.pop holder prefix, - .ignore key=.ignore keys, .restore key=.restore keys, - .define key=.define keys, .new key=.new keys, - .initialize after define=.initialize keys after define, - .save initial values=.save initial values of keys, - .set=.set keys, .setkeys=.set keys, - .set*=.set keys*, .setkeys*=.set keys*, - .setkeys save unknown=.set keys*, - .setrmkeys=.set rmkeys, - .set remaining keys=.set rmkeys, - .setrmkeys*=.set rmkeys*, - .set remaining keys*=.set rmkeys*, - .presetkeys=.preset keys, .initial values=.preset keys, - .postsetkeys=.postset keys, - .try set=.try set keys, - .sa set=.sa set keys, .search also set keys=.sa set keys, - .use defaults=.set with defaults, - .restrict values=.state pattern, - .nominations=.state pattern, - .singleton=.state pattern, - .estate pattern=.state pattern expanded, - .esingleton=.state pattern expanded, - .style=.append style, - .styles=.append style, - .estyle=.append style expanded, - .style expand once=.append style expand once, - .style expand twice=.append style expand twice, - .link=.append link, - .links=.append link, - .elink=.append link expanded, - .link expand once=.append link expand once, - .link expand twice=.append link expand twice, - .listbreak=.list break, .break list=.list break, - .new handler=.new handlers, .define handler=.define handlers, - .kill handler=.kill handlers, - .initial value=.initial values, - .default value=.default values,.default=.default values, - .defaults=.default values, - .assign value=.assign values, - .inherit value=.inherit values, - .inherit default=.inherit defaults, - .inherit code=.inherit callback, - .prepend value=.prepend values, - .append value=.append values, - .disabled option message type=.disabled key message type, - .message type when disabled key is invoked=.disabled key message type, - .message type when disabled option is invoked=.disabled key message type, - .unknown option handler=.unknown key handler, + .handlers let reserved={ + {.disabled option message type, + .message type when disabled key is invoked, + .message type when disabled option is invoked + }=.disabled key message type, }, } % \skvpatchcmd[<prefix>]{<cmd>}{<search>}{<replace>}{<success>}{<fail>} +% \skvrobustdef*\skvpatchcmd{% \begingroup \@makeother{\#}\endlinechar\m@ne @@ -6846,30 +8339,32 @@ \edef\skv@tempb##1{##1\detokenize{#1}\skvrelax}% \skv@tempb{\expandafter\skv@tempa\meaning#2}% } -\skvrobustdef*\skvifmacroTF#1{% - \skvifntypeTF{#1}{% - \begingroup - \edef\skv@tempa##1{\def##1####1\detokenize{macro}:####2\skvrelax}% - \skv@tempa\skv@tempa{% - \expandafter\endgroup\ifx\@nnil##2\@nnil - \expandafter\@secondoftwo - \else - \expandafter\@firstoftwo - \fi - }% - \edef\skv@tempb##1{##1\detokenize{macro}:\skvrelax}% - \skv@tempb{\expandafter\skv@tempa\meaning#1}% - }{% - \@secondoftwo - }% +\edef\skv@begindoctoks{\string\begin\string{\string\document\string}} +\skvrobustdef*\skvAtBeginEnvironment#1{% + \skvaftercs\skvappendtomacro{lps@atbegin@#1@hook}% +} +\skvrobustdef*\skvAtEndEnvironment#1{% + \skvaftercs\skvappendtomacro{lps@atend@#1@hook}% } -\skvrobustdef*\skvifmacroFT#1{\skvifmacroTF{#1}\@secondoftwo\@firstoftwo} +\skvpatchcmd\begin + {\csname#1\endcsname} + {\skvcsuse{lps@atbegin@#1@hook}\csname#1\endcsname} + {} + {\skv@err{Patching '\string\begin' failed!\MessageBreak + '\string\skvAtBeginEnvironment' will not work\@gobble}\@ehd + } -%\skvxzapspaces{\detokenize{\begin{\document}}}\skv@begindoctoks -\edef\skv@begindoctoks{\string\begin\string{\string\document\string}} +\skvpatchcmd\end + {\csname end#1\endcsname} + {\skvcsuse{lps@atend@#1@hook}\csname end#1\endcsname} + {} + {\skv@err{Patching '\string\end' failed!\MessageBreak + '\string\skvAtEndEnvironment' will not work\@gobble}\@ehd + } \skv@core@restorecodes + \endinput %% End of file 'skeyval-core.tex'. diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex b/Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex index 309a5649c93..a61c4f0c499 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-for.tex @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'skeyval-for', version 1.1a, 2012/10/16. % +% This is file 'skeyval-for.tex', version 1.2, 2013/02/10. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -23,7 +23,7 @@ % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % % and skeyval-testpkg.sty. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup% @@ -59,16 +59,21 @@ \expandafter\let\csname skeyval-for-loaded\endcsname\endinput \ifx\ProvidesFile\@undefined - \message{File 'skeyval-for.tex' 2012/10/16 v1.1a + \message{File 'skeyval-for.tex' 2013/02/10 v1.2 Loops for skeyval package (AM)} \else \ProvidesFile{skeyval-for.tex} - [2012/10/16 v1.1a Loops for skeyval package (AM)] + [2013/02/10 v1.2 Loops for skeyval package (AM)] \@addtofilelist{skeyval-for.tex} \fi -\skvrobustdef*\skv@nostackerr{\skv@err{You've called an empty stack}\@ehd} -% \skvsavestate<base-fn>{<fn-list>}<counter> +\skvrobustdef*\skv@nostackerr{% + \skv@err{You've called an empty stack}\skv@ehd +} +% \skvsavestate<base-fn>{<fn-list>}<counter-number> +% +% See file skeyval-core.tex for \skvpushfunctions and \skvpopfunctions. +% \skvrobustdef*\skvsavestate#1#2#3{% \skvgadvanceno#3\@ne \begingroup @@ -80,13 +85,13 @@ \def\do##1{\let\skvnoexpandcs{\skv@prova{##1}}\noexpand##1}% \edef\reserved@a{\endgroup#2}\reserved@a } -% \skvrestorestate<base-fn><counter> +% \skvrestorestate<base-fn><counter-number> \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 + \skv@err{Stack of '\noexpand#1' is undefined}\skv@ehd \fi \edef\skv@prova{\skvexpandtwice\skv@elt}% \edef\skv@provb##1##{\endgroup##1\gdef\skvexpandonce\skv@elt}% @@ -95,60 +100,78 @@ } \skvnewregisters\bool{% - \ifskvbreakloop\ifforeachlastitem - \ifskvprocessempty\ifskv@foreach@swa - \ifskv@foreach@swb\ifskv@foreach@parenth + \ifbreakallforeachloops,\ifskvbreakloop,\ifforeachlastitem, + \ifskvprocessempty,\ifskv@foreach@swa,\ifskv@foreach@swb, + \ifskv@foreach@parenth,\ifskv@useemptylist } -\skvnewnumbers[skv@]{csvdepth,dolistcnt} - -\skvrobustdef*\skv@usetempst#1#2{% - \edef#2{\skvifdefboolTF{skv@tempst}\skvexpandonce\unexpanded{#1}}% +\skvnewlet\skvbreakloop\skvbreaklooptrue +\skvnewlet\breaknewforeach\skvbreaklooptrue +% \breakallforeachloops will break all current loops (inner and outer): +\skvnewdef*\breakallforeachloops{% + \skvbreaklooptrue\breakallforeachloopstrue } + +\skvnewnumbers[skv@]{csvdepth,dolistdepth} % % \skvdolist{<parser>}{<list>}<holdercmd>{<callback>} % \skvdolist*{<parser>}{<listcmd>}<holdercmd>{<callback>} -% -% 1. \skvdolist can process both csv and tsv/nsv lists. -% 2. This can be nested to any depth, with different parsers on each -% level. -% 3. This will not process an empty list; see \skvecommaloop. +% \skvparselist{<parser>}{<list>}<holdercmd>{<callback>} +% \skvparselist*{<parser>}{<listcmd>}<holdercmd>{<callback>} +% \skvprocesslist{<parser>}{<list>}<holdercmd>{<callback>} +% \skvprocesslist*{<parser>}{<listcmd>}<holdercmd>{<callback>} +% +% 1. These macros can process both csv and tsv/nsv lists. Use empty +% <parser> for tsv lists. +% 2. These macros can be nested to any depth, with different parsers +% on each level. +% 3. \skvdolist and \skvparselist will not process an empty list, but +% \skvprocesslist will do so. % 4. For comma lists, \skvcommaloop and \skvcommaparse are faster. % See later. -% 5. For processing kv lists, use \skvkvparse. +% 5. For processing kv lists, use \skvparsekvlist. % -\skvrobustdef*\skvdolist{\skv@testst\skv@dolist} +\skvrobustdef*\skvdolist{\skv@useemptylistfalse\skv@testst\skv@dolist} \skvrobustdef*\skv@dolist#1#2#3#4{% - \skvgadvanceno\skv@dolistcnt\@ne + % \skvlistcount is used by listkeys. + \skvsavestate\skvdolist{% + \do\skv@dolist@callback + \do\skv@dolist@a\do\skvlistcount\do\ifskv@useemptylist + }\skv@dolistdepth \skv@usetempst{#2}#3% - \def\skv@dolist@a{skv@dolist@\skvrom\skv@dolistcnt}% - \skvcsdef{\skv@dolist@a}##1##2##3#1{% - \skvifstrcmpTF{##3}{\skv@dolist@nil}{% + \edef\skv@dolist@callback{\unexpanded{#4}}% + \def\skvlistcount{0}% + \def\skv@dolist@a##1##2#1{% + \skvifstrcmpTF{##2}{\skv@dolist@nil}{% % To allow nesting of loop: \skvbreakloopfalse }{% - \edef##1{\unexpanded{##3}}% - ##2\relax + \edef##1{\unexpanded{##2}}% + \edef\skvlistcount{\the\numexpr\skvlistcount+1}% + \skv@dolist@callback\relax \ifskvbreakloop \skvbreakloopfalse \begingroup - \skvcsdef{\skv@dolist@a}####1\skv@dolist@nil#1{\endgroup}% + \def\skv@dolist@a####1####2\skv@dolist@nil#1{% + \endgroup + \edef\skvremainder{\unexpanded{####2}}% + }% \fi - \@nameuse{\skv@dolist@a}##1{##2}% + \skv@dolist@a{##1}% }% }% - \skvifemptyTF#3{}{% - \edef\reserved@a{\unexpanded{\@nameuse{\skv@dolist@a}#3{#4}}}% - \expandafter\reserved@a#3#1\skv@dolist@nil#1% + \ifskv@useemptylist + \def\reserved@a##1##2##3{##3}% + \else + \let\reserved@a\skvifemptyTF + \fi + \reserved@a#3{}{% + \expandafter\skv@dolist@a\expandafter#3#3#1\skv@dolist@nil#1% }% - \skvgadvanceno\skv@dolistcnt\m@ne + \skvrestorestate\skvdolist\skv@dolistdepth } - % First normalize the list before parsing. -% -% \skvparselist{<parser>}{<list>}<holdercmd>{<callback>} -% \skvparselist*{<parser>}{<listcmd>}<holdercmd>{<callback>} -% -\skvrobustdef*\skvparselist{\skv@testst\skv@parselist} +\skvrobustdef*\skvparselist{\skv@useemptylistfalse\skv@testst\skv@parselist} +\skvrobustdef*\skvprocesslist{\skv@useemptylisttrue\skv@testst\skv@parselist} \skvrobustdef*\skv@parselist#1#2#3{% \skv@usetempst{#2}#3% \skvcsvnormalize[#1]#3% @@ -156,14 +179,11 @@ \skv@dolist{#1}#3#3% } -\skvifdefinable\listbreaker{\let\listbreaker\relax} -\skvifdefinable\listpauser{\let\listpauser\relax} -\skvnewdef*\skv@listbreakertoks{\listbreaker} -\skvnewdef*\skv@listpausertoks{\listpauser} - +\skvnewlet\foreachlistbreaker\relax +\skvnewlet\foreachlistpauser\relax +\skvnewdef*\skv@listbreakertoks{\foreachlistbreaker} +\skvnewdef*\skv@listpausertoks{\foreachlistpauser} \skvnewlet\skvprocessempty\skvprocessemptytrue -\skvletmanytocmd{\skvbreakloop\interruptloop\skvbreakforeach - \interruptforeach}\skvbreaklooptrue % Reversing tokens: \skvnewdef*\skvreverse#1{\skv@reverse#1\skv@reverse@stop} @@ -217,14 +237,14 @@ } % A version of LaTeX's \@tfor that can parse undoubled parameter -% characters. +% characters and terminate the loop by using \skvbreakloop. % % \skvtfor<holder.cmd>:={<list>}\do{<callback>} % \skvtfor*<holder.cmd>:={<listcmd>}\do{<callback>} % % Example: % -% \skvnewregister\count\nr +% \skvnewregister\count{\nr} % \skvtfor\x:=a \ifx {\def\x#1{#1}} \fi\do{% % \nr\z@ % \skvtfor\y:=12345\do{% @@ -239,7 +259,7 @@ \skvrobustdef*\skv@tfor#1:={\skv@tf@r#1 } \skvrobustdef\skv@tf@r#1#2\do#3{% \edef#1{\skvtrimspace{#2}}% - \edef#1{\skvifboolTF{skv@tempst}\skvexpandtwice\skvexpandonce{#1}}% + \edef#1{\skvifdefboolTF{skv@tempst}\skvexpandtwice\skvexpandonce{#1}}% \skvifemptyTF#1{}{% \skvbreakloopfalse \expandafter\skv@tforloop#1\skv@tfor@nil\skv@tfor#1{#3}% @@ -266,23 +286,29 @@ %+++++++++++++++ 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. +% specialized for comma lists and they are faster, since they don't +% stack any state. +% 2. There is no fear of parameter characters in <callback> being mixed +% with those of \skv@commaloop@picknext. +% 2. They can be nested to any depth. % % \skvcommaloop{<list>}<holder-cmd>{<callback>} % \skvcommaloop*{<listcmd>}<holder-cmd>{<callback>} % +% Example: +% +% \skvcommaloop{x#1,y#1}\tempa{\edef\xx#1{#1\tempa}} +% \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. \skvifxTF#2\@empty{}{% - \skvexpandnext{\skv@c@mmaloop#2{#3}}#2,\skv@commaloop@nil,% + \skvexpandnext{\skv@commaloop@picknext#2{#3}}#2,\skv@commaloop@nil,% }% } -\skvrobustdef\skv@c@mmaloop#1#2#3,{% +\skvrobustdef\skv@commaloop@picknext#1#2#3,{% \skvifstrcmpTF{#3}{\skv@commaloop@nil}{% \skvbreakloopfalse }{% @@ -291,9 +317,12 @@ \ifskvbreakloop \skvbreakloopfalse \begingroup - \long\def\skv@c@mmaloop##1\skv@commaloop@nil,{\endgroup}% + \long\def\skv@commaloop@picknext##1##2##3\skv@commaloop@nil,{% + \endgroup + \edef\skvremainder{\unexpanded{##3}}% + }% \fi - \skv@c@mmaloop#1{#2}% + \skv@commaloop@picknext#1{#2}% }% } % @@ -306,7 +335,7 @@ % \skvrobustdef\skvecommaloop{\skv@testst\skv@ecommaloop} \skvrobustdef\skv@ecommaloop#1#2#3{% - \edef#2{\unexpanded{\skv@c@mmaloop#2{#3}}}% + \edef#2{\unexpanded{\skv@commaloop@picknext#2{#3}}}% \ifskv@tempst\expandafter\expandafter\fi#2#1,\skv@commaloop@nil,% } % @@ -325,30 +354,17 @@ % \skvkvparse{<list>}<cmd>{<callback>} % \skvkvparse*{<listcmd>}<cmd>{<callback>} % -% \skvkvparse is as \skvcommaloop but will first normalize <list> using -% \skvkvnormalize. +% 1. \skvkvparse is as \skvcommaloop but will first normalize <list> using +% \skvkvnormalize. +% 2. It is meant for processing key-value lists. % \skvrobustdef*\skvkvparse{\skv@testst\skv@kvparse} -\skvnewlet\skvparsekeyvals\skvkvparse +\skvnewlet\skvparsekvlist\skvkvparse \skvrobustdef\skv@kvparse#1#2#3{% \skv@usetempst{#1}#2% \skvkvnormalize#2% \skvcommaloop*#2#2{#3}% } -% \skvcommaprocess{<list>}<holder.cmd> -% \skvcommaprocess*{<listcmd>}<holder.cmd> -% -% If <list> or <listcmd> is a single item, then no looping is required. -% -\skvrobustdef*\skvcommaprocess{\skv@testst\skv@commaprocess} -\skvrobustdef*\skv@commaprocess#1#2#3{% - \skv@usetempst{#1}#2% - \skvxifinTF{,}{\skvoxdetok#2}{% - \skvcommaparse*#2#2{#3}% - }{% - \skvdespacecontent#2#3% - }% -} % \skvcountelements[<parser>]{<list>}{<return.cmd>} % \skvcountelements*[<parser>]{<listcmd>}{<return.cmd>} \skvrobustdef*\skvcountelements{\skv@teststopt\skv@countelements,} @@ -402,14 +418,20 @@ % % 3. Elements of the form (a,b) and [a,b] are grabbed together. % -% 4. Use \interruptforeach to break out of the loop prematurely. +% 4. Use \breaknewforeach to break out of the loop prematurely. % % 5. \newforeach can be nested. - -% \skv@foreach@sisterdepth must be different from \foreachdepth, +% +% 6. The star (*) variant of \newforeach is equivalent to using the +% key 'list is a macro' (or *) in <options>. +% +% \skv@foreach@holderdepth must be different from \foreachnestdepth, % to avoid confusing two different stacks. -\skvnewnumbers{foreachdepth,skv@foreach@sisterdepth,skv@foreach@nra,% - skv@warnsubparser} +\skvnewnumbers{foreachnestdepth,skv@foreach@holderdepth,% + skv@foreach@nra,skv@warnsubparser} +% \newforeach will not accept \skvifstreq or \skvifstrcmpTF because +% they don't start with '\if'. So we introduce \ifforeachstrcmp: +\skvnewlet\ifforeachstrcmp\skvifstreq \skvnewdef*\skv@foreach@onlyinitially{} \skvrobustdef*\skvforeachonlyinitially#1{% \edef\skv@foreach@onlyinitially{% @@ -496,9 +518,9 @@ \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@fi@toks must use \detokenize. Don't change to \string! +\skvnewedef*\skv@foreach@fi@toks{\detokenize{\fi}} +\skvnewedef*\skv@foreach@if@toks{\string\if} % \skv@foreach@ifacceptkv and \skv@foreach@maketester must come % before the initialization of keys: @@ -508,7 +530,7 @@ \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 + \skv@err{Invalid syntax '\detokenize{#1}'}\skv@ehd \else \edef\next{\unexpanded{#2}}% \fi @@ -522,12 +544,12 @@ }{% \skv@err{Value of key '#1' must \MessageBreak be escaped: the holder macro - \MessageBreak to be evaluated}\@ehd + \MessageBreak to be evaluated}\skv@ehd }% }{% \skv@err{Value of key '#1' must \MessageBreak be only one token: the holder - \MessageBreak macro to be evaluated}\@ehd + \MessageBreak macro to be evaluated}\skv@ehd }% } % \skv@foreach@maketester{<cond>}<cond.tester.cmd>{<flag>} @@ -536,7 +558,14 @@ % 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. +% should be entered in postcallback. This is because +% \skv@foreach@maketester is called (by key 'loop stopper') for +% formating the premature exit condition and (in +% \skv@foreach@parsecountin and \skv@foreachfox@parsecountin) for the +% condition for counting an item of the list. In the latter case, +% there is no need to enter the formated +% condition in the postcallback, since it it is entered in the +% 'afterprecallback' or (in the case of \foreachfox) in 'precallback'. % % Examples: \ifnum\x>10\fi, \ifx\x\cmd\fi. % @@ -546,10 +575,11 @@ \begingroup \edef\skv@prova{\detokenize{#1}}% \skvifblankTF{#1}{% - \skv@err{A blank conditional given in \string\newforeach}\@ehd + \skv@err{A blank conditional has been given in + \MessageBreak\string\newforeach or a similar command}\skv@ehd }{% - \skvxifinTF{\skv@foreach@fi\relax}{\detokenize{#1}\relax}{% - \skvxifinTF{\relax\skv@foreach@if}{\relax\detokenize{#1}}{% + \skvxifinTF{\skv@foreach@fi@toks\relax}{\detokenize{#1}\relax}{% + \skvxifinTF{\relax\skv@foreach@if@toks}{\relax\detokenize{#1}}{% \edef#2{\noexpand\skvifconditionTF\unexpanded{#1}}% \ifnum#3=\@ne \skv@foreach@addtocallback{post}{% @@ -561,7 +591,7 @@ {Invalid, possibly unbalanced, conditional '\skv@prova'}% }% }{% - \skv@err{Invalid conditional '\skv@prova'}\@ehd + \skv@err{Invalid conditional '\skv@prova'}\skv@ehd }% }% \skvexpanded{\endgroup @@ -602,30 +632,26 @@ \def\skv@foreach@subparser{/} ; parser/{,}/ - \ifskvindef\else - \edef\skv@foreach@parser{\unexpanded{#1}} - \skvstripouterbraces{2}\skv@foreach@parser - \skvxifntypeTF{\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 + \edef\skv@foreach@parser{\unexpanded{#1}} + \skvstripouterbraces{2}\skv@foreach@parser + \skvxifntypeTF{\detokenize{#1}}{% + \begingroup + % It is assumed that every n-type parser and subparser + % must have catcode 12: + \skvexpandnext{\catcode`}\skv@foreach@parser=12\relax + \skvrescan\skv@foreach@parser + \skvaftergroupdef\skv@foreach@parser\endgroup + }{} ; subparser/{/}/ - \ifskvindef\else - \edef\skv@foreach@subparser{\unexpanded{#1}} - \skvstripouterbraces{2}\skv@foreach@subparser - \skvxifntypeTF{\detokenize{#1}}{ - \begingroup - \skvexpandnext{\catcode`}\skv@foreach@subparser=12\relax - \skv@rescan\skv@foreach@subparser - \skvaftergroupdef\skv@foreach@subparser\endgroup - }{} - \fi + \edef\skv@foreach@subparser{\unexpanded{#1}} + \skvstripouterbraces{2}\skv@foreach@subparser + \skvxifntypeTF{\detokenize{#1}}{ + \begingroup + \skvexpandnext{\catcode`}\skv@foreach@subparser=12\relax + \skvrescan\skv@foreach@subparser + \skvaftergroupdef\skv@foreach@subparser\endgroup + }{} ; terminator,callback terminator/{;}/ \edef\skv@foreach@terminator{\unexpanded{#1}}% @@ -633,27 +659,40 @@ ; % process up to = <nr> % Maximum number of items to process: - process up to,process up to number/\@nil/ - \ifskvindef\else + process up to,process up to number// + \skviflacus#1\then\else + \skvensureinteger{process up to}{#1}% \def\skv@foreach@processupto{#1}% - \ifx\skv@foreach@processupto\@nnil\else - \skv@ensureinteger{process up to}{#1}% - \fi + \skvstripouterbraces{2}\skv@foreach@processupto \fi ; process empty list/true/ \edef\skv@foreach@processempty{0\skvifstrcmpTF{true}{#1}01}% /true,false ; - % Eg, exit when=\ifnum\x=20\fi + % 'break=<condition>' + % Break list processing when <condition> is satisfied. <condition> must + % be a balanced plain TeX conditional. Eg, 'exit when={\ifnum\x=20\fi}'. + % Notice the use of outer braces in '{\ifnum\x=20\fi}'. This avoids + % conflicting the two equality signs: for the key-value and for number + % testing. .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 + break,loop stopper,exit when/\if01\fi/ + \edef\skv@tempa{\unexpanded{#1}}% + \skvstripouterbraces{2}\skv@tempa + \skvexpbracenext\skv@foreach@maketester\skv@tempa + \skv@foreach@exittester\@ne + ; + % Java-type of continue: If the user wants to ignore the callback for + % some items, he can instantiate the key 'condition=<condition>'. + % <condition> must be a balanced plain TeX conditional. Eg, + % continue={\ifnum\x=20\fi}. + .exec/\let\skv@foreach@continuetester\@secondoftwo; + continue,ignore callback/\if01\fi/ + \edef\skv@tempa{\unexpanded{#1}}% + \skvstripouterbraces{2}\skv@tempa + \skvexpbracenext\skv@foreach@maketester\skv@tempa + \skv@foreach@continuetester\skvz@ ; % 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. @@ -724,39 +763,28 @@ \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 - \skvifescapedTF{#1}{% - \let\skv@foreach@itemcounter\skv@prova - }{% - \skv@err{Non-escaped value '\detokenize{#1}' - \MessageBreak for key 'item counter'}\@ehd - }% - \fi - \fi + item counter,counter/\foreachdefaultitemcounter/ + \skvifescapedTF{#1}{% + \def\skv@foreach@itemcounter{#1}% + }{% + \skv@err{Non-escaped value '\detokenize{#1}' + \MessageBreak for key 'item counter'}\skv@ehd + }% ; - 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 + list breaker/\foreachlistbreaker/ + \edef\skv@prova{\unexpanded{#1}}% + \ifx\skv@prova\@empty + \skv@err{Invalid empty value for key 'list breaker'}\skv@ehd + \else + \let\skv@listbreakertoks\skv@prova \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 + list pauser/\foreachlistpauser/ + \edef\skv@prova{\unexpanded{#1}}% + \ifx\skv@prova\@empty + \skv@err{Invalid empty value for key 'list pauser'}\skv@ehd + \else + \let\skv@listpausertoks\skv@prova \fi ; % Remember outside the loop the holder values. Of course, this @@ -768,25 +796,20 @@ % This default value of 'link' is required by \skv@foreach@filllist: .exec code/\def\skv@foreach@link{\@nil}; link/\@nil/ - \ifskvindef\else + \edef\skv@prova{\unexpanded{#1}}% + \ifcase0% + \ifx\skv@prova\@empty 1\fi + \ifx\skv@prova\@nnil 1\fi\relax \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{\skvifstrcmpTF{#1}{left}{right}{left}}% - \skvcsedef{skv@foreach@grow\skv@prova}{01}% - \fi + \edef\skv@prova{\unexpanded{#1}}% + \ifx\skv@prova\@nnil\else + \skvcsedef{skv@foreach@grow#1}{00} + \edef\skv@prova{\skvifstrcmpTF{#1}{left}{right}{left}}% + \skvcsedef{skv@foreach@grow\skv@prova}{01}% \fi /left,right ; @@ -795,17 +818,13 @@ \def\skv@foreach@growright{01} ; grow left/true/ - \ifskvindef\else - \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}01} - \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}10} - \fi + \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}01} + \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}10} /true,false ; grow right/true/ - \ifskvindef\else - \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}01} - \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}10} - \fi + \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}01} + \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}10} /true,false ; % Keep the decimals in rounded numbers or dimensions when list is @@ -829,17 +848,17 @@ \edef\skv@foreach@expandlistbeforefill{0\skvifstrcmpTF{true}{#1}01} /true,false ; - expand list once,*,list is a macro,macro list/true/ + expand list once,x1,list is a macro,macro list/true/ \edef\skv@foreach@expandlistonce{0\skvifstrcmpTF{true}{#1}01}% /true,false ; - expand list twice/true/ + expand list twice,x2/true/ \edef\skv@foreach@expandlisttwice{0\skvifstrcmpTF{true}{#1}01}% /true,false ; % Don't use 'expand' for this key, to avoid confusing it with % the 'expand' for holder macros: - expand list,fully expand list,expand list fully/true/ + expand list,fully expand list,expand list fully,xx/true/ \edef\skv@foreach@expandlistfully{0\skvifstrcmpTF{true}{#1}01}% /true,false ; @@ -847,38 +866,22 @@ \edef\skv@foreach@reverselist{0\skvifstrcmpTF{true}{#1}01} /true,false ; - reverse list,reverse,reflect/true/ - \edef\skv@foreach@reverselist{0\skvifstrcmpTF{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{skeyval/foreach}{% - parser, - subparser, - callback terminator, - 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, - reverse list=false, - expand list once=false, - expand list twice=false, - expand list fully=false, +% The following keys don't need presetting. The user must supply +% values when they are called. In internal loops, their values will +% have to be revised from those of the outer loop. +% +% link,evaluate,,evaluate num,evaluate dim,expand,count in, +% process up to,grow +% +\quickkeys.preset{skeyval/foreach}{% + parser,subparser,loop stopper,callback terminator,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,reverse list=false,expand list once=false, + expand list twice=false,expand list fully=false, } \skvnewdef*\skv@foreach@kvlist{} @@ -926,36 +929,36 @@ \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 + \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{% \expandafter\skvifntypeTF\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 + \MessageBreak I can't find holder macro}\skv@ehd }% }{% \skv@err{Value of key 'evaluate': - \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\@ehd + \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provb\@empty - \skv@err{Value of key 'evaluate' has no child macro}\@ehd + \skv@err{Value of key 'evaluate' has no child macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@provb}{% \expandafter\skvifntypeTF\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 + \MessageBreak I can't find child macro}\skv@ehd }% }{% \skv@err{Value of key 'evaluate': - \MessageBreak child \skvoxdetok\skv@provb not escaped}\@ehd + \MessageBreak child \skvoxdetok\skv@provb not escaped}\skv@ehd }% \fi \ifx\skv@provc\@empty \skv@err{Value of key 'evaluate' has no formula or - \MessageBreak holder macro to be expanded}\@ehd + \MessageBreak holder macro to be expanded}\skv@ehd \fi \skv@tempxifin{\pgfmathparse}{##3}{% \def\skv@tempc####1\pgfmathparse####2\skv@nil{% @@ -963,7 +966,7 @@ \skv@foreach@swatrue \else \skv@err{Invalid token \detokenize{####1} - \MessageBreak before \string\pgfmathparse}\@ehd + \MessageBreak before \string\pgfmathparse}\skv@ehd \fi }% \skv@tempc##3\skv@nil @@ -986,7 +989,7 @@ \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'evaluate': - \MessageBreak there is 'using', but no 'as'}\@ehd + \MessageBreak there is 'using', but no 'as'}\skv@ehd }% }{% % No formula given. Maybe the key is 'expand' or still 'evaluate' @@ -995,10 +998,10 @@ \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 + \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd \else \ifx\@nnil##2% - \skv@err{Value of key 'evaluate' has no child macro}\@ehd + \skv@err{Value of key 'evaluate' has no child macro}\skv@ehd \else \skv@tempa##1as##2using##1\skv@nil \fi @@ -1008,7 +1011,7 @@ }{% % 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 + \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd \else \skvifntypeTF{#1}{% % Expand the holder macro: @@ -1016,7 +1019,7 @@ }{% \skv@err{Value of key 'evaluate': more than 1 \MessageBreak token '\detokenize{#1}'. - \MessageBreak I can't find holder macro}\@ehd + \MessageBreak I can't find holder macro}\skv@ehd }% \fi }% @@ -1047,7 +1050,7 @@ \skvrobustdef*\skv@foreach@parsepgfmathparse#1{% \begingroup \ifdefined\pgfmathparse\else - \skv@err{No \string\pgfmathparse; 'pgfmath' module not loaded}\@ehd + \skv@err{No \string\pgfmathparse; 'pgfmath' module not loaded}\skv@ehd \fi \def\skv@tempxifin##1##2{% \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}% @@ -1058,36 +1061,36 @@ \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 + \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{% \expandafter\skvifntypeTF\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 + \MessageBreak I can't find holder macro}\skv@ehd }% }{% \skv@err{Value of key 'pgfmath parse': - \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\@ehd + \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provb\@empty - \skv@err{Value of key 'pgfmath parse' has no child macro}\@ehd + \skv@err{Value of key 'pgfmath parse' has no child macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@provb}{% \expandafter\skvifntypeTF\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 + \MessageBreak I can't find child macro}\skv@ehd }% }{% \skv@err{Value of key 'pgfmath parse': - \MessageBreak child \skvoxdetok\skv@provb not escaped}\@ehd + \MessageBreak child \skvoxdetok\skv@provb not escaped}\skv@ehd }% \fi \ifx\skv@provc\@empty \skv@err{Value of key 'pgfmath parse' has no formula or - \MessageBreak holder macro to be expanded}\@ehd + \MessageBreak holder macro to be expanded}\skv@ehd \fi \skv@tempxifin{\pgfmathparse}{##3}{% \def\skv@tempc####1\pgfmathparse####2\skv@nil{% @@ -1095,18 +1098,18 @@ \skv@foreach@swatrue \else \skv@err{Invalid token \detokenize{####1} - \MessageBreak before \string\pgfmathparse}\@ehd + \MessageBreak before \string\pgfmathparse}\skv@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 + \MessageBreak\noexpand\numexpr not allowed}\skv@ehd }{% \skv@tempxifin{\dimexpr}{##3}{% \skv@err{Value of key 'pgfmath parse': - \MessageBreak\noexpand\dimexpr not allowed}\@ehd + \MessageBreak\noexpand\dimexpr not allowed}\skv@ehd }{% \skv@foreach@swatrue \edef\skv@provc{\noexpand\pgfmathparse{\skvexpandonce\skv@provc}}% @@ -1120,16 +1123,16 @@ \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'pgfmath parse': - \MessageBreak there is 'using', but no 'as'}\@ehd + \MessageBreak there is 'using', but no 'as'}\skv@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 + \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd \else \ifx\@nnil##2% - \skv@err{Value of key 'pgfmath parse' has no child macro}\@ehd + \skv@err{Value of key 'pgfmath parse' has no child macro}\skv@ehd \else \skv@tempa##1as##2using##1\skv@nil \fi @@ -1139,7 +1142,7 @@ }{% % 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 + \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd \else \skvifntypeTF{#1}{% % Evaluate the holder macro: @@ -1147,7 +1150,7 @@ }{% \skv@err{Value of key 'pgfmath parse': more than 1 \MessageBreak token '\detokenize{#1}'. - \MessageBreak I can't find holder macro}\@ehd + \MessageBreak I can't find holder macro}\skv@ehd }% \fi }% @@ -1204,17 +1207,17 @@ \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 + \skv@err{Value of key 'count' has no counter macro}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{% \expandafter\skvifntypeTF\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 + \MessageBreak I can't find counter macro}\skv@ehd }% }{% \skv@err{Value of key 'count':\MessageBreak - counter macro \skvoxdetok\skv@prova not escaped}\@ehd + counter macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provd\@empty @@ -1224,7 +1227,7 @@ \expandafter\let\skv@prova\skv@provd }{% \skv@err{Value of key 'count':\MessageBreak - initial \skvoxdetok\skv@provd not an integer}\@ehd + initial \skvoxdetok\skv@provd not an integer}\skv@ehd }% \fi \skv@foreach@swafalse @@ -1240,11 +1243,11 @@ \expandafter\skvifntypeTF\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 + \MessageBreak I can't find holder macro}\skv@ehd }% }{% \skv@err{Value of key 'count':\MessageBreak - holder macro \skvoxdetok\skv@provb not escaped}\@ehd + holder macro \skvoxdetok\skv@provb not escaped}\skv@ehd }% \skv@foreach@swatrue % \skv@tester is the second argument of \skv@foreach@maketester. @@ -1259,7 +1262,7 @@ \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'count': - \MessageBreak there is 'satisfying', but no 'all'}\@ehd + \MessageBreak there is 'satisfying', but no 'all'}\skv@ehd }% }{% \skv@tempxifin{all}{#1}{% @@ -1267,14 +1270,14 @@ }{% % 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 + \skv@err{Value of key 'count' has no counter macro}\skv@ehd \else \skvifntypeTF{#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 + \MessageBreak I can't find counter macro}\skv@ehd }% \fi }% @@ -1308,7 +1311,7 @@ \skv@tempxifin{(}{#1}{% \skv@err{Value of key 'remember': '(' found. \MessageBreak I don't accept this PGF format. - \MessageBreak remove the parenthesis '()'}\@ehd + \MessageBreak Remove the parenthesis '(<your input>)'}\skv@ehd }{}% \def\skv@tempa##1as##2initially##3\skv@nil{% \edef\skv@prova{\skvtrimspace{##1}}% @@ -1317,22 +1320,22 @@ \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 + \MessageBreak i.e., no macro that holds input}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@prova}{}{% \skv@err{Value of key 'remember': - \MessageBreak Holder macro \skvoxdetok\skv@prova not escaped}\@ehd + \MessageBreak Holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd }% \fi \ifx\skv@provb\@empty \skv@err{Value of key 'remember' has no child macro; - \MessageBreak i.e., no macro after 'as'}\@ehd + \MessageBreak i.e., no macro after 'as'}\skv@ehd \else \expandafter\skvifescapedTF\expandafter{\skv@provb}{% \skv@foreach@swatrue }{% \skv@err{Value of key 'remember': - \MessageBreak Child \skvoxdetok\skv@provb not escaped}\@ehd + \MessageBreak Child \skvoxdetok\skv@provb not escaped}\skv@ehd }% \fi }% @@ -1341,7 +1344,7 @@ \skv@tempa#1\skv@nil }{% \skv@err{Value of key 'remember': - \MessageBreak There is 'initially', but no 'as'}\@ehd + \MessageBreak There is 'initially', but no 'as'}\skv@ehd }% }{% \skv@tempxifin{as}{#1}{% @@ -1350,6 +1353,7 @@ % No 'as' and 'initially': \edef\skv@prova{\skvtrimspace{#1}}% \ifx\skv@prova\@empty\else + % Go and raise error in \skv@tempa: \skv@tempa#1as initially\skv@nil \fi }% @@ -1391,7 +1395,7 @@ \skv@tempxifin{(}{#1}{% \skv@err{Value of key 'recall': '(' found. \MessageBreak I don't accept this PGF format. - \MessageBreak remove the parenthesis '()'}\@ehd + \MessageBreak remove the parenthesis '()'}\skv@ehd }{}% \skv@foreach@swafalse \def\skv@tempa##1initially##2\skv@nil{% @@ -1399,7 +1403,7 @@ \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 + \MessageBreak i.e., no macro that holds input}\skv@ehd \else \expandafter\skvifntypeTF\expandafter{\skv@prova}{% \expandafter\skvifescapedTF\expandafter{\skv@prova}{% @@ -1420,11 +1424,11 @@ }% }{% \skv@err{Value of key 'recall': - \MessageBreak \detokenize{#1} is not escaped}\@ehd + \MessageBreak \detokenize{#1} is not escaped}\skv@ehd }% }{% \skv@err{Value of key 'recall': - \MessageBreak \detokenize{#1} is not one token}\@ehd + \MessageBreak \detokenize{#1} is not one token}\skv@ehd }% \fi }% @@ -1432,7 +1436,7 @@ \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 + \MessageBreak of the form \<foreachlast><holder.name>}\skv@ehd }{% \skv@tempxifin{initially}{#1}{% \skv@tempa#1\skv@nil @@ -1486,60 +1490,48 @@ \endgroup }% \skvletmanytocmd{% - \prependtobeginforeach\appendtobeginforeach\atbeginforeach - \prependtoendforeach\appendtoendforeach\atendforeach + \prependtobeginforeach,\appendtobeginforeach,\atbeginforeach, + \prependtoendforeach,\appendtoendforeach,\atendforeach }\skv@foreach@latehook } \skvrobustdef*\skv@foreach@pushstate{% \skvsavestate\skv@foreach@stack{% - \do\skv@foreach@seenstar - \do\skv@foreach@parser\do\skv@foreach@subparser - \do\skv@foreach@listisamacro + \do\skv@foreach@seenstar\do\skv@foreach@parser + \do\skv@foreach@subparser\do\skv@foreach@listisamacro \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@exittester\do\skv@foreach@continuetester + \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@normalizelist\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@getnext\do\skv@foreach@picknext\do\skv@foreach@getrm \do\skv@foreach@do@a\do\skv@foreach@do@b - \do\skv@foreach@paramlist - \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 + % Macros '...lookahead...' need stacking in \foreachfox and when + % \newforeach is nested with \foreachfox: + \do\skv@foreach@lookahead@a\do\skv@foreach@lookahead@b + \do\skv@foreach@lookahead@c\do\skv@foreach@lookahead@d + \do\skv@foreach@paramlist\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@expandlistbeforefill\do\skv@foreach@expandlistonce \do\skv@foreach@expandlisttwice\do\skv@foreach@expandlistfully \do\skv@listbreakertoks\do\skv@listpausertoks - \do\skv@foreach@reverselist - \do\foreachcurrentitem - \do\foreachnextitem - \do\foreachitemcount - \do\foreachprevitem + \do\skv@foreach@reverselist\do\foreachcurrentitem + \do\foreachnextitem\do\foreachitemcount\do\foreachprevitem % The following commands are disabled on entry into the loop. % Hence they need to be stacked here: - \do\prependtobeginforeach - \do\appendtobeginforeach - \do\atbeginforeach - \do\prependtoendforeach - \do\appendtoendforeach - \do\atendforeach - }\foreachdepth + \do\prependtobeginforeach\do\appendtobeginforeach\do\atbeginforeach + \do\prependtoendforeach\do\appendtoendforeach\do\atendforeach + }\foreachnestdepth } \skvrobustdef*\skv@foreach@popstate{% - \skvrestorestate\skv@foreach@stack\foreachdepth + \skvrestorestate\skv@foreach@stack\foreachnestdepth } -\skvnewdef*\foreachnestdepth{\foreachdepth} \skvnewlet\skv@foreach@nil\relax \skvnewdef*\skv@foreach@nnil{\skv@foreach@nil} \skvrobustdef*\newforeach{\skv@testst\skv@newforeach@beginprescan} @@ -1560,11 +1552,11 @@ }{% \skvifnextchar i{% \endgroup - \skv@err{\string\newforeach: no holder macro seen}\@ehd + \skv@err{\string\newforeach: no holder macro seen}\skv@ehd }{% \skvifnextchar\skv@orig@bgroup{% \endgroup - \skv@err{\string\newforeach: no holder macro seen}\@ehd + \skv@err{\string\newforeach: no holder macro seen}\skv@ehd }{% \skv@foreach@collectholders }% @@ -1591,7 +1583,7 @@ } \skvrobustdef*\skv@foreach@endprescan#1[#2]{% \skvifblankTF{#1}{% - \skv@err{\string\newforeach: no holder macros seen}\@ehd + \skv@err{\string\newforeach: no holder macros seen}\skv@ehd }{% \skv@foreach@scanarg[#2]#1% }% @@ -1602,18 +1594,17 @@ \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{}% + % Don't confuse macros of various depths; reset them here: + \def\do##1{\def##1{}}% + \do\skv@foreach@itemcounter\do\skv@foreach@processupto + \do\skv@foreach@callback\do\skv@foreach@auxcallback + \do\skv@foreach@precallback\do\skv@foreach@afterprecallback + \do\skv@foreach@postcallback\do\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. + % keys have to be reset here. Reset all keys: they might have been + % fixed by the outer loop and the inner loop might assume the default + % values of the keys are those being used. \skv@foreach@setkeys{#1}% % We've set the keys; let's overrule \skv@foreach@expandlistonce if % we had seen a star suffix. Don't overrule \skv@foreach@expandlisttwice @@ -1622,9 +1613,10 @@ \def\skv@foreach@expandlistonce{00}% \fi \ifcase0% - \if\skv@foreach@expandlistonce0\else - \if\skv@foreach@expandlisttwice0\else - \if\skv@foreach@expandlistfully0\else 1\fi\fi\fi\relax + % Take only one case: + \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}% @@ -1647,7 +1639,7 @@ \skvifescapedTF{#1}{% \skv@err{Token '\noexpand#1' cannot be a subparser; \MessageBreak it seems to be a holder macro. I expected - \MessageBreak the subparser to be the token here.}\@ehd + \MessageBreak the subparser to be the token here.}\skv@ehd }{% \edef\skv@prova{\skvtrimspace{#1}}% \let\elt\skvexpandonce @@ -1662,6 +1654,7 @@ \MessageBreak I have used '\elt\skv@prova', but please submit \MessageBreak '\elt\skv@prova' as the value of the key 'subparser' + \MessageBreak so that I can stop giving this warning. }% \fi \let\skv@foreach@subparser\skv@prova @@ -1671,7 +1664,7 @@ \else \skvifescapedTF{#1}{}{% \skv@err{Token '\noexpand#1' is not escaped - \MessageBreak and can't be a holder macro}\@ehd + \MessageBreak and can't be a holder macro}\skv@ehd }% \fi \advance\skv@cnta\@ne @@ -1687,13 +1680,13 @@ \skvifstrcmpTF{#1#2}{in}{% \skv@foreach@scanarg@d }{% - \skv@err{I have seen 'i' but no expected 'in'}\@ehd + \skv@err{I have seen 'i' but no expected 'in'}\skv@ehd }% } \skvrobustdef*\skv@foreach@scanarg@d{% \ifx\skv@foreach@holderlist\@empty \skv@err{No item holder macros before 'in' - \MessageBreak or before left brace}\@ehd + \MessageBreak or before left brace}\skv@ehd \fi \skvifnextchar\skv@orig@bgroup{% \skv@foreach@scanarg@e @@ -1707,7 +1700,7 @@ \noexpand\newforeach or key 'expand list once', etc., \MessageBreak is missing.}% }{% - \let\skv@tempehd\@ehd + \let\skv@tempehd\skv@ehd }% \skv@err{I expected a left brace for beginning of list, \MessageBreak since you haven't told me that your @@ -1734,7 +1727,7 @@ \skvifnextchar\skv@orig@bgroup \skv@foreach@scanarg@h\skv@foreach@scanarg@g }{% - \skv@err{I have seen 'd' but no the expected 'do'}\@ehd + \skv@err{I have seen 'd' but no the expected 'do'}\skv@ehd }% } % We've exhausted all options for grabbing the callback, so now @@ -1775,7 +1768,7 @@ \skv@prova }% % In case callback terminator is currently active, rescan it. - \skv@rescan\skv@foreach@terminator + \skvrescan\skv@foreach@terminator \expandafter\skv@prova\expandafter{\skv@foreach@terminator}% } % #1: callback @@ -1812,16 +1805,19 @@ {#2}% }% % Initial code, if any: - \skvcsuse{skv@foreach@atbeginhook@\skvrom\foreachdepth}% + \skvcsuse{skv@foreach@atbeginhook@\skvrom\foreachnestdepth}% \skvifdefTF\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 + \expandafter\skv@foreach@normalize\expandafter[\skv@foreach@parser]% + \skv@foreach@userlist + \expandafter\skv@foreach@normalize\expandafter[\skv@foreach@subparser]% + \skv@foreach@userlist + \ifnum\foreachnestdepth=\skvz@ + \breakallforeachloopsfalse + \fi \skvbreakloopfalse \foreachlastitemfalse \def\skv@foreach@lookahead@a##1{% - \def\skv@foreach@continue{##1.}% + \def\skv@foreach@picknext{##1.}% \futurelet\skv@foreach@next\skv@foreach@lookahead@b }% \def\skv@foreach@lookahead@b{% @@ -1831,12 +1827,12 @@ \ifx\skv@foreach@next(% \expandafter\expandafter\expandafter\skv@foreach@lookahead@d \else - \expandafter\expandafter\expandafter\skv@foreach@continue + \expandafter\expandafter\expandafter\skv@foreach@picknext \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@lookahead@c[##1]{\skv@foreach@picknext[{##1}]}% + \def\skv@foreach@lookahead@d(##1){\skv@foreach@picknext({##1})}% \def\skv@foreach@mainloop##1{% \def\skv@foreach@getnext####1##1####2\skv@foreach@stop{% \edef\foreachnextitem{\skvexpandonce{\@gobble####1}}% @@ -1874,21 +1870,17 @@ }% \def\skv@foreach@do@b####1{% \edef\foreachitemcount{\the\numexpr\foreachitemcount+1}% - \ifcase0% - \ifx\skv@foreach@itemcounter\@undefined 1\fi - \ifx\skv@foreach@itemcounter\@empty 1\fi - \ifx\skv@foreach@itemcounter\@nnil 1\fi\relax + \ifx\skv@foreach@itemcounter\@empty\else \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: + % If the user decides to continue after \foreachlistpauser is picked up, + % don't use \foreachlistpauser as an item: \skvifxTF\foreachcurrentitem\skv@listpausertoks{}{% - \expandafter\skv@foreach@callback\expandafter{\foreachcurrentitem}% + \skvexpbracenext\skv@foreach@callback\foreachcurrentitem + \let\foreachprevitem\foreachcurrentitem }% - \let\foreachprevitem\foreachcurrentitem - \ifcase0% - \ifx\skv@foreach@processupto\@undefined 1\fi - \ifx\skv@foreach@processupto\@nnil 1\fi\relax + \ifx\skv@foreach@processupto\@empty\else \ifnum\foreachitemcount<\skv@foreach@processupto\relax\else \skvbreakloop \fi @@ -1900,7 +1892,9 @@ }% }% \def\skv@foreach@getrm####1{% - \skvbreakloopfalse + \ifbreakallforeachloops\else + \skvbreakloopfalse + \fi \foreachlastitemfalse \def\skv@prova########1\skv@foreach@nil##1{% \edef\foreachlistremainder{\unexpanded{########1}}% @@ -1909,7 +1903,9 @@ \skv@prova####1% }% \skvifxTF\skv@foreach@userlist\@empty{% - \if\skv@foreach@processempty\skv@foreach@callback{}\fi + \if\skv@foreach@processempty\skvafterfi + \skv@foreach@callback{}% + \fi }{% \expandafter\skv@foreach@filllist\expandafter {\skv@foreach@parser}\skv@foreach@userlist @@ -1924,16 +1920,16 @@ \skv@foreach@makeprecode{#1}% \if\skv@foreach@recoverholders\else \expandafter\skvsavestate\expandafter\skv@foreach@holderstate - \expandafter{\skv@foreach@holderlist}\skv@foreach@sisterdepth + \expandafter{\skv@foreach@holderlist}\skv@foreach@holderdepth \fi \skv@foreach@makeauxcallback{#3}% \skvexpandbracenext\skv@foreach@mainloop\skv@foreach@parser - \skvcsuse{skv@foreach@atendhook@\skvrom\foreachdepth}% + \skvcsuse{skv@foreach@atendhook@\skvrom\foreachnestdepth}% \if\skv@foreach@recoverholders\else - \skvrestorestate\skv@foreach@holderstate\skv@foreach@sisterdepth + \skvrestorestate\skv@foreach@holderstate\skv@foreach@holderdepth \fi \skv@foreach@popstate - \ifnum\foreachdepth=\skvz@ + \ifnum\foreachnestdepth=\skvz@ \def\skv@warnsubparser{0}% \fi } @@ -1957,7 +1953,7 @@ \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 + first in the list\MessageBreak of holder macros}\skv@ehd \else % Eg, if subparser is slash (/), \skv@foreach@paramlist will have % the syntax: ##1/##2/...: @@ -2010,6 +2006,20 @@ \skvcmdexit\skv@foreach@precallback }% } +% Example (*): +% +% This example demonstrates why \skv@foreach@continuetester must be +% located delicately, at where it is currently. +% +% \def\ditem{D} +% \newforeach [ +% continue=\ifx\x\ditem\fi,remember=\x as \rx initially A +% ] \x in { +% B,(C1),D,E,[F1],G,H +% }{% +% $\overrightarrow{\rx\x}$\ifforeachlastitem.\else,\space\fi +% } +% % #1: callback \skvrobustdef*\skv@foreach@makeauxcallback#1{% \begingroup @@ -2022,25 +2032,37 @@ % Add extra subparsers in case some items aren't subparser-complete: \edef\skv@tempa{\skv@generatesubparser{1}}% \let\foreacheov\relax - \let\\\noexpand + \let\do\noexpand \skvexpanded{\endgroup % Define auxiliary callback: - \def\\\skv@foreach@auxcallback\skv@foreach@paramlist\foreacheov{% + \def\do\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 - \\\ifnum\\\foreachitemcount=\@ne - \\\skv@foreach@onlyinitially - \\\fi - \unexpanded{#1}% - % User tests/tasks, eg, if requested from the keys 'remember', - % 'exit when', etc: - \skvexpandonce\skv@foreach@postcallback + \do\ifnum\do\foreachitemcount=\@ne + \do\skv@foreach@onlyinitially + \do\fi + \ifx\skv@foreach@continuetester\@secondoftwo + \noexpand\skv@foreach@continuetester + \else + % Expose the parameter characters in \skv@foreach@continuetester: + \skvexpandonce\skv@foreach@continuetester + \fi + {% + \relax + }{% + % If the user wants to ignore the callback for some items, he can + % use the key 'continue=<condition>': + \unexpanded{#1}% + % User tests/tasks, eg, if requested from the keys 'remember', + % 'exit when', etc: + \skvexpandonce\skv@foreach@postcallback + }% }% % Define the real callback: - \def\\\skv@foreach@callback####1{% - \\\skv@foreach@auxcallback####1\skvxonce\skv@tempa\foreacheov + \def\do\skv@foreach@callback####1{% + \do\skv@foreach@auxcallback####1\skvxonce\skv@tempa\foreacheov }% }% } @@ -2132,7 +2154,7 @@ \skvifdefTF\skv@foreach@link{% \skvifxFT\skv@foreach@link\@nnil }{% - \skv@err{List auto-completion: 'link' is undefined}\@ehd + \skv@err{List auto-completion: 'link' is undefined}\skv@ehd }% }% \skvexpanded{% @@ -2158,8 +2180,7 @@ \skv@foreach@normalize[#1]\skv@foreach@filledlist }{% \edef\skv@foreach@filledlist{% - \skvaddlist{#1}\skv@foreach@filledlist - \skvtrimspace{##1}% + \skvaddlist{#1}\skv@foreach@filledlist\skvtrimspace{##1}% }% }% }% @@ -2168,10 +2189,10 @@ % \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 + \skv@err{I can't find lower limit before '...'}\skv@ehd \else \skvxiffound{\relax\detokenize{#1}...}\in{\relax\detokenize{#2}}\then - \skv@err{I can't find lower limit before '...'}\@ehd + \skv@err{I can't find lower limit before '...'}\skv@ehd \fi \fi % \newforeach format is '<parser>...<parser>': @@ -2180,7 +2201,7 @@ \def\skv@prova##1#1##2#1...#1##3#1##4#1##5\skv@nil{% \skvifblankTF{##3}{% \skv@err{I can't find upper limit number or dimension, - \MessageBreak i.e., after symbool '...'}\@ehd + \MessageBreak i.e., after symbool '...'}\skv@ehd }{% % \skv@foreach@filllist@a may be reentered. Hence accumulate % filled list: @@ -2198,7 +2219,7 @@ \expandafter\skv@prova\skv@tempa#1#1\skv@nil }{% % Not \newforeach format: try PGF's \foreach format: - \skv@foreach@trypgfformat{#1}{#2}% + \skv@foreach@trypgflikeformat{#1}{#2}% }% } @@ -2247,7 +2268,7 @@ \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 + 'grow right=true or false'}\skv@ehd \fi \begingroup \def\skv@prova##1{% @@ -2260,7 +2281,7 @@ \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 + '\detokenize\expandafter{\skv@provb#3, #4}'}\skv@ehd \fi \def\skv@prova####1##1####2\skv@nil{% \if\skv@foreach@growright @@ -2269,9 +2290,9 @@ \edef\skv@prova{\skvtrimspace{##1####2}}% \fi \def\do########1{{\skvtrimspace{########1}}}% - % \skv@foreach@trypgfformat@a<parser><guide><lower1><lower2><upper> + % \skv@foreach@trypgflikeformat@a<parser><guide><lower1><lower2><upper> \skvexpanded{\endgroup - \noexpand\skv@foreach@trypgfformat@a + \noexpand\skv@foreach@trypgflikeformat@a {\unexpanded{#1}}{\skvexpandonce\skv@prova}\do{#2}\do{#3}\do{#4}% }% }% @@ -2291,7 +2312,7 @@ % {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 +% {A_2pt,A_4pt,A_...pt,A_10pt} : <guide> = A_ and pt % % skeyval formats: % {a^1,a^3,a^...,a^9} : no additional info. required @@ -2308,14 +2329,14 @@ % % 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. +% together with the rest of the list. Save the BL2 items in +% \skv@foreach@filledlist. % % 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 '...': + % sure that #2 contains '<guide><parser>...' or '...': \begingroup \skv@cnta\skvz@ \def\do##1#1{% @@ -2350,7 +2371,7 @@ \else \ifnum\skv@cnta=\skvz@ \skv@err{List <<\detokenize{#2}>>\MessageBreak - contains symbol '...' but not a lowerbound}\@ehd + contains symbol '...' but not a lowerbound}\skv@ehd \fi \fi \fi @@ -2360,16 +2381,21 @@ }% } -% \skv@foreach@trypgfformat{<parser>}{<list>} +% \skv@foreach@trypgflikeformat{<parser>}{<list>} +% +% When we say 'try PGF-like format', we don't actually mean the +% PGF format with left and right guides, as in, +% +% {A_2pt,A_4pt,A_...pt,A_10pt} : <guide> = 'A_(left)' and 'pt(right)' (*) % -% 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, +% 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} or {1pt,4pt,...pt,10pt} % -% \skv@foreach@trypgfformat will auto-complete this list without -% knowledge of the values of the keys 'link' and 'grow'. +% \skv@foreach@trypgflikeformat will auto-complete this list without +% knowledge of the values of the keys 'link' and 'grow'. The syntax at (*) +% above isn't recognized by the auto-completion scheme of skeyval. % % skeyval formats: % @@ -2382,15 +2408,15 @@ % % {A_2pt,A_4pt,A_...pt,A_10pt} % -% is illegal here, because the skeyval-for package uses the location +% is illegal here, because the file skeyval-for.tex uses the location % of the guide (left or right of ...) to determine the direction of growth. % -\skvrobustdef*\skv@foreach@trypgfformat#1#2{% +\skvrobustdef*\skv@foreach@trypgflikeformat#1#2{% \skv@foreach@splitonguide{#1}{#2}% \def\skv@prova##1#1##2#1##3...##4#1##5#1##6#1##7\skv@nil{% \skvifblankTF{##5}{% \skv@err{I can't find upper limit number or dimension, - \MessageBreak i.e., after symbool '...'}\@ehd + \MessageBreak i.e., after symbool '...'}\skv@ehd }{% % \skv@foreach@filllist@a may be reentered. Hence \skviflacus{##1}\then\else @@ -2403,12 +2429,12 @@ \skvifblankTF{##3}{% \skvifblankTF{##4}{% \skv@err{No direction of growth before and/or after - \MessageBreak symbol '...'}\@ehd + \MessageBreak symbol '...'}\skv@ehd }{% \def\skv@foreach@growleft{00}% \def\skv@foreach@growright{01}% \skvexpanded{% - \skv@foreach@trypgfformat@a + \skv@foreach@trypgflikeformat@a {\unexpanded{#1}}\do{##4}\do{##1}\do{##2}\do{##5}% }% }% @@ -2417,17 +2443,17 @@ \def\skv@foreach@growright{00}% \def\skv@foreach@growleft{01}% \skvexpanded{% - \skv@foreach@trypgfformat@a + \skv@foreach@trypgflikeformat@a {\unexpanded{#1}}\do{##3}\do{##1}\do{##2}\do{##5}% }% }{% - \skv@err{Having both '\detokenize{##3 and ##4}' in an + \skv@err{Having both '\detokenize{'##3' and '##4'} in an \MessageBreak ellipsis list is illegal in - \MessageBreak\noexpand\newforeach and \noexpand\newforeach. + \MessageBreak\noexpand\newforeach and \noexpand\foreachfox. \MessageBreak I know that PGF's \noexpand\foreach needs it, \MessageBreak but I don't need it. I can \MessageBreak auto-fill your list with information - \MessageBreak on only one side.}\@ehd + \MessageBreak on only one side of <<...>>.}\skv@ehd }% }% % In case the list is folded on ellipsis (...): @@ -2437,7 +2463,8 @@ \expandafter\skv@prova\skv@tempa#1#1#1\skv@nil } % -% \skv@foreach@trypgfformat@a{<parser>}{<guide>}{<lower1>}{<lower2>}{<upper>} +% \skv@foreach@trypgflikeformat@a +% {<parser>}{<guide>}{<lower1>}{<lower2>}{<upper>} % % 1. Use the <guide> to get the contant and variable parts of the % elements. @@ -2448,7 +2475,7 @@ % 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{% +\skvrobustdef*\skv@foreach@trypgflikeformat@a#1#2#3#4#5{% \skv@foreach@swafalse \skviflacus#3\then\else \skvxifinTF{#2}{#3}{}\skv@foreach@swatrue @@ -2459,7 +2486,7 @@ \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 + \MessageBreak due to wrong direction of growth}\skv@ehd \fi % Get from the left or right of 'link' (#2) the components that should be % grown, without the link: @@ -2516,7 +2543,7 @@ \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 + \MessageBreak aren't of the same type}\skv@ehd \fi }{% \skv@foreach@ifupperalpha{#4}{% @@ -2541,7 +2568,7 @@ \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 + \MessageBreak aren't of the same type}\skv@ehd \fi }{% \skv@foreach@swatrue @@ -2552,7 +2579,7 @@ \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 + \skv@err{The units on \detokenize{'#4', '#5'} are different}\skv@ehd \fi \ifskv@foreach@swa \ifx\@nnil#3\@nnil @@ -2571,7 +2598,7 @@ }\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 + % <lower1> was saved earlier in \skv@foreach@trypgflikeformat, 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 @@ -2605,7 +2632,7 @@ '\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 + \MessageBreak See manual for acceptable syntaxes}\skv@ehd \fi \fi }% @@ -2666,13 +2693,13 @@ \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 + '\detokenize{#2}'}\skv@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 + '\detokenize{#2}'}\skv@ehd \fi \fi % The bounds may have decimal places. So the calculation has to be @@ -2711,7 +2738,7 @@ \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 + step '\skv@foreach@step' isn't an integer}\skv@ehd }% \skv@foreach@addtolist{#1}{#2}#4% \skvifstrcmpTF{#2}{#3}{}{% diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-ltxcmds.tex b/Master/texmf-dist/tex/latex/skeyval/skeyval-ltxcmds.tex index 17b4c19c9d5..0235cf5bfb1 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval-ltxcmds.tex +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-ltxcmds.tex @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'skeyval-ltxcmds.tex', version 1.1a, 2012/10/16. % +% This is file 'skeyval-ltxcmds.tex', version 1.2, 2013/02/10. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -23,7 +23,7 @@ % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % % and skeyval-testpkg.sty. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup% @@ -58,7 +58,7 @@ \csname skeyval-ltxcmds-loaded\endcsname \expandafter\let\csname skeyval-ltxcmds-loaded\endcsname\endinput -\message{skeyval-ltxcmds 2012/10/16 v1.1a skeyval TeX header (AM)} +\message{skeyval-ltxcmds 2013/02/10 v1.2 skeyval LaTeX header (AM)} \countdef\m@ne=22 \m@ne=-1 \def\wlog{\immediate\write\m@ne} @@ -146,7 +146,6 @@ \xdef#1{\the\toks@}% \endgroup } - % In case we call \@latex@error, etc, without LaTeX: \newwrite\@unused \def\typeout#1{% @@ -282,7 +281,6 @@ Type H <return> for immediate help% }% } \def\@infonoline#1{\@latex@info{#1\@gobble}} - \errorcontextlines=\m@ne \ifnum\inputlineno=\m@ne \let\on@line\@empty diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-ltxpatch.sty b/Master/texmf-dist/tex/latex/skeyval/skeyval-ltxpatch.sty index 82d624e3985..3bea153e722 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval-ltxpatch.sty +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-ltxpatch.sty @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'skeyval-ltxpatch.sty', version 1.1a, 2012/10/16. % +% This is file 'skeyval-ltxpatch.sty', version 1.2, 2013/02/10. % % % % The rationale for this package: the patch in 'xkvltxp' package isn't % % strong enough. % @@ -26,7 +26,7 @@ % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.sty, % % and skeyval-testpkg.sty. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup @@ -72,7 +72,7 @@ \NeedsTeXFormat{LaTeX2e}[2011/06/27] \ProvidesPackage{skeyval-ltxpatch} - [2012/10/16 v1.1a Patches for LaTeX2e kernel options processing (AM)] + [2013/02/10 v1.2 Patches for LaTeX2e kernel options processing (AM)] \ifdefined\skvz@\else\newdimen\skvz@\fi \def\@space{ } diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-pstkey.sty b/Master/texmf-dist/tex/latex/skeyval/skeyval-pstkey.sty index 280338217ac..c3f458644e6 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval-pstkey.sty +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-pstkey.sty @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'skeyval-pstkey.sty', version 1.1a, 2012/10/16. % +% This is file 'skeyval-pstkey.sty', version 1.2, 2013/02/10. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -23,7 +23,7 @@ % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % % and skeyval-testpkg.sty. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup @@ -69,7 +69,7 @@ \NeedsTeXFormat{LaTeX2e}[2011/06/27] \ProvidesPackage{skeyval-pstkey} - [2012/10/16 v1.1a LaTeX/package wrapper for skeyval-pstkey.tex (AM)] + [2013/02/10 v1.2 LaTeX/package wrapper for skeyval-pstkey.tex (AM)] \expandafter\ifx\csname skeyval-pstkey-loaded\endcsname \endinput\else diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-pstkey.tex b/Master/texmf-dist/tex/latex/skeyval/skeyval-pstkey.tex index bc5952d0377..4e2dc1f9ad7 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval-pstkey.tex +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-pstkey.tex @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'skeyval-pstkey.tex', version 1.1a, 2012/10/16. % +% This is file 'skeyval-pstkey.tex', version 1.2, 2013/02/10. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -23,7 +23,7 @@ % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % % and skeyval-testpkg.sty. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup% @@ -62,12 +62,12 @@ \def\skv@@afterelse#1\else#2\fi{\fi#1} \ifx\ProvidesFile\@undefined\skv@@afterelse - \message{File 'skeyval-pstkey.tex' 2012/10/16 v1.1a + \message{File 'skeyval-pstkey.tex' 2013/02/10 v1.2 PSTricks specialization of skeyval package (AM)} \input skeyval-core \else\skv@@afterfi \ProvidesFile{skeyval-pstkey.tex} - [2012/10/16 v1.1a PSTricks specialization of skeyval (AM)] + [2013/02/10 v1.2 PSTricks specialization of skeyval (AM)] \@addtofilelist{skeyval-pstkey.tex} \@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}} \fi diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval-view.sty b/Master/texmf-dist/tex/latex/skeyval/skeyval-view.sty index 6e40b3d6611..4996acf58b3 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval-view.sty +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval-view.sty @@ -1,5 +1,5 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'skeyval-view.sty', version 1.1a, 2012/10/16. % +% This is file 'skeyval-view.sty', version 1.2, 2013/02/10. % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -23,7 +23,7 @@ % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % % and skeyval-testpkg.sty. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup @@ -69,11 +69,10 @@ \NeedsTeXFormat{LaTeX2e}[2011/06/27] \ProvidesPackage{skeyval-view} - [2012/10/16 v1.1a Viewer utility for skeyval package (AM)] + [2013/02/10 v1.2 Viewer utility for skeyval package (AM)] \@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}} \directkeys*{% - .prefix=SKVV, - .family=skvview, + .path=SKVV/skvview, .holder prefix=skvv@, .initialize keys after define, .every unknown option={ @@ -101,8 +100,7 @@ \skvnewnumbers[skvv@]{depth,nra} \directkeys*{ - .prefix=SKVV, - .family=skvview, + .path=SKVV/skvview, .holder prefix=skvv@, .initialize after define=false, .define keys={ @@ -158,6 +156,7 @@ }% } \protected\def\skv@ordkey@a#1[#2]#3{% + % Pointers have been stripped in \skv@ordkey. \skvifstrcmpTF{#2}{^skv^}{% \skvv@tabulate{#1}{ordinary}{[none]}% }{% @@ -167,7 +166,7 @@ \skvcsedef{\skv@header#1.@cbk}{\unexpanded{#3}}% } \protected\def\skv@cmdkey#1#2[#3]#4{% - \skv@strippointers{#2}\skvcurrentkey + \skv@strippointersfromkey{#2}% \skvifdefboolTF{skv@st}{% \skv@definedefault\skvcurrentkey{#3}% \skvv@tabulate\skvcurrentkey{command}{#3}% @@ -184,7 +183,7 @@ } \protected\def\skv@choicekey@g{% \skvcommaparse*\skv@currlist\skv@prova{% - \skvexpbracenext\skv@strippointers\skv@prova\skvcurrentkey + \skvexpbracenext\skv@strippointersfromkey\skv@prova \ifx\skv@default\skv@rej \skvv@tabulate\skvcurrentkey{choice}{[none]}% \else\skvafterfi @@ -200,6 +199,7 @@ }% } \protected\def\skv@boolkey@c#1#2#3#4{% + % Pointers have been stripped in \skv@boolkey. \skvcsnewif{\skv@zapornot{\skv@zapsw}{#2}}% \edef\skvv@boolortog{\if\skv@typetogkey toggle\else bool\fi}% \skvifdefboolTF{skv@st}{% @@ -219,7 +219,7 @@ % #2: styles, #3: default, #4: callback \protected\def\skv@appendstyles@a#1#2[#3]#4{% \skvcommaparse{#1}\skv@prova{% - \skvexpbracenext\skv@strippointers\skv@prova\skvcurrentkey + \skvexpbracenext\skv@strippointersfromkey\skv@prova \skvexpanded{% \skvifstrcmpTF{#3}{^skv^}{% \skvv@tabulate{\skvcurrentkey}{style}{[none]}% @@ -246,18 +246,18 @@ \skvv@coliitrue\skvv@coliiitrue\skvv@colivtrue\skvv@colvtrue \else \skvsetnumber\skvv@nra\@ne - \@expandtwoargs\skv@in@{,prefix,}{,\skvv@columns,}% + \@expandtwoargs\skvtestifin{,prefix,}{,\skvv@columns,}% \ifin@\skvadvanceno\skvv@nra\@ne\skvv@coliitrue\else\skvv@coliifalse\fi - \@expandtwoargs\skv@in@{,family,}{,\skvv@columns,}% + \@expandtwoargs\skvtestifin{,family,}{,\skvv@columns,}% \ifin@\skvadvanceno\skvv@nra\@ne\skvv@coliiitrue\else\skvv@coliiifalse\fi - \@expandtwoargs\skv@in@{,type,}{,\skvv@columns,}% + \@expandtwoargs\skvtestifin{,type,}{,\skvv@columns,}% \ifin@ \skvadvanceno\skvv@nra\@ne\skvv@colivtrue \else - \@expandtwoargs\skv@in@{,key type,}{,\skvv@columns,}% + \@expandtwoargs\skvtestifin{,key type,}{,\skvv@columns,}% \ifin@\skvadvanceno\skvv@nra\@ne\skvv@colivtrue\else\skvv@colivfalse\fi \fi - \@expandtwoargs\skv@in@{,default,}{,\skvv@columns,}% + \@expandtwoargs\skvtestifin{,default,}{,\skvv@columns,}% \ifin@\skvadvanceno\skvv@nra\@ne\skvv@colvtrue\else\skvv@colvfalse\fi \fi \ifskvv@view @@ -334,8 +334,7 @@ } \directkeys*{ - .prefix=SKVV, - .family=skvvshow, + .path=SKVV/skvvshow, .holder prefix=skvvs@, .initialize keys after define, .new keys={ diff --git a/Master/texmf-dist/tex/latex/skeyval/skeyval.sty b/Master/texmf-dist/tex/latex/skeyval/skeyval.sty index fce36938787..010ce8c51fd 100644 --- a/Master/texmf-dist/tex/latex/skeyval/skeyval.sty +++ b/Master/texmf-dist/tex/latex/skeyval/skeyval.sty @@ -1,5 +1,19 @@ %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% -% This is file 'skeyval.sty', version 1.1a, 2012/10/16. % +% This is file 'skeyval.sty', version 1.2, 2013/02/10. % +% % +% NOTE % +% % +% Beginning from version 1.0, 2012/09/01, the skeyval package has changed % +% radically. Users of pre-version 1.0 of the package can load it now by % +% calling: % +% % +% \usepackage[compatibility]{skeyval} % +% \RequirePackage[compatibility]{skeyval} % +% or % +% \usepackage{skeyval-bc} % +% \RequirePackage{skeyval-bc} % +% % +% LICENSE % % % % This package and accompanying files may be distributed and/or % % modified under the conditions of the LaTeX Project Public License, % @@ -15,6 +29,8 @@ % implied warranties of merchantability and fitness for a particular % % purpose. % % % +% DISTRIBUTION % +% % % The following files constitute the skeyval bundle and must be % % distributed as a whole: % % % @@ -23,7 +39,7 @@ % skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, % % and skeyval-testpkg.sty. % % % -% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). % +% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% \begingroup @@ -67,19 +83,19 @@ \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{skeyval}[2012/10/16 v1.1a Robust key-value parser (AM)] +\ProvidesPackage{skeyval}[2013/02/10 v1.2 Robust key-value parser (AM)] \NeedsTeXFormat{LaTeX2e}[2011/06/27] \input skeyval-core -\skvrobustdef*\skvAfterEndPackage{% +\skvrobustdef*\skvafterendpackage{% \skvifcsdefTF{\@currname.\@currext-skv@endpkghook}{}{% \@namedef{\@currname.\@currext-skv@endpkghook}{}% }% \expandafter\g@addto@macro \csname\@currname.\@currext-skv@endpkghook\endcsname } -\skvrobustdef*\skvAfterPackage#1{% +\skvrobustdef*\skvafterpackage#1{% \skvafterbegindocument{% \skvifcsdefTF{ver@#1.\@pkgextension}{}{% \skv@warn{Package '#1' was never loaded}% @@ -99,13 +115,12 @@ }% \unexpanded\expandafter{\@popfilename}% } +\skvundef\skv@documentclass \skvrobustdef*\skv@getdocumentclass{% - \skv@swafalse - \ifx\@filelist\@undefined\else - \ifx\@filelist\relax\else - \ifx\@filelist\@gobble\else\skv@swatrue\fi - \fi\fi - \ifskv@swa + \ifcase0% + \ifx\@filelist\@undefined 1\fi + \ifx\@filelist\relax 1\fi + \ifx\@filelist\@gobble 1\fi\relax \skvcommaparse*\@filelist\skv@tempa{% \filename@parse\skv@tempa \ifx\filename@ext\@clsextension @@ -119,20 +134,22 @@ }% \fi } -\skv@getdocumentclass + +% The following packages need access to the original \@classoptionslist: +\skvnewdef*\skv@optionprocessorpackages{% + xkeyval,kvoptions,catoptions,biblatex,pgfopts,ltxkeys% +} % Filter class options to remove those with '=': \skvrobustdef*\skv@filterclassoptions{% - \skv@swafalse - \ifx\@classoptionslist\@undefined\else - \ifx\@classoptionslist\relax\else\skv@swatrue\fi - \fi - \ifskv@swa - \let\skv@filterclassoptions\relax + \ifcase0% + \ifx\@classoptionslist\@undefined 1\fi + \ifx\@classoptionslist\relax 1\fi\relax + \global\let\skv@filterclassoptions\relax \skvkvnormalize\@classoptionslist - \let\skv@origclassoptlist\@classoptionslist + \let\skvoriginalclassoptionslist\@classoptionslist \let\skv@classoptionslist\@classoptionslist \let\@classoptionslist\@empty - \skvcommaloop*\skv@origclassoptlist\skv@tempa{% + \skvcommaloop*\skvoriginalclassoptionslist\skv@tempa{% \skvxifinTF{=}{\skvexpandonce\skv@tempa}{}{% \skvaddtolist*\@classoptionslist\skv@tempa }% @@ -140,11 +157,9 @@ \def\@fileswith@ptions##1[##2]##3{% \edef\skv@tempa{\unexpanded{##3}}% \skvcsvnormalize\skv@tempa - % The following packages need access to the original - % \@classoptionslist. - \skvcommaloop{xkeyval,kvoptions,keyval2e,ltxkeys}\skv@prova{% + \skvcommaloop*\skv@optionprocessorpackages\skv@prova{% \skvxifinTF{,\skv@prova,}{,\skv@tempa,}{% - \let\@classoptionslist\skv@origclassoptlist + \let\@classoptionslist\skvoriginalclassoptionslist \skvbreakloop }{}% }% @@ -153,15 +168,6 @@ }% \fi } -\skvifdefFT\skv@documentclass{% - \let\skv@documentclass\@empty - \let\skv@classoptionslist\@empty - \edef\@popfilename{% - \skvexpandonce\@popfilename\skv@filterclassoptions - }% -}{% - \skv@filterclassoptions -} \skvrobustdef*\skvbeforebegindocument{% \skvgappendtomacro\skv@beforebegindoc } @@ -187,7 +193,7 @@ } \skvrobustdef*\skv@notprerr#1{% \@latex@error{Command \detokenize{#1} should be used only - in preamble}\@ehd + in preamble}\skv@ehd } \skvnewdef*\skv@everypagehook{} \skvrobustdef*\skvatbegineverypage{\skvgappendtomacro\skv@everypagehook} @@ -206,29 +212,37 @@ \skvnewdef*\skv@preamblecmdhook{} \skvrobustdef*\skvonlypreamble#1{% - \def\do##1{% + \def\skv@provb##1{% + \skvifntypeTF{##1}{}{% + \skv@err{More than one macro + \MessageBreak '\detokenize{##1}'. + \MessageBreak Maybe a comma is missing in the list}\skv@ehd + }% \skvxifinTF{\detokenize{\do##1}}{\skvoxdetok\skv@preamblecmdhook}{% \skv@warn{Command '\noexpand##1' multiply \MessageBreak submitted to \string\skvonlypreamble: ignored}% }{% \xdef\skv@preamblecmdhook{% - \skvexpandonce\skv@preamblecmdhook - \unexpanded{\do##1}% + \skvexpandonce\skv@preamblecmdhook\unexpanded{\do##1}% }% }% }% \skvcommaparse{#1}\skv@prova{% - \expandafter\do\expandafter{\skv@prova}% + \expandafter\skv@provb\expandafter{\skv@prova}% }% } \AtEndOfPackage{% \skvafterbegindocument{% \def\do#1{% \skvifdefTF#1{% - \gdef#1{\@latexerr{'\string#1' is a preamble command}\@ehd}% + \gdef#1{\@latexerr{'\string#1' is a preamble command}\skv@ehd}% }{% - \@@warning{Undefined command '\unexpanded{#1}' - appeared in \string\skvonlypreamble}% + \ifx\relax#1\else + \@@warning{Undefined command '\unexpanded{#1}' + \MessageBreak appeared in \string\skvonlypreamble. + \MessageBreak Only defined commands should be + \MessageBreak submitted to \string\skvonlypreamble.}% + \fi }% }% \skv@preamblecmdhook @@ -242,7 +256,7 @@ % \skvunknownoptionhandler[<prefixes>]<<families>>{<handler>} % \skvrobustdef*\skvunknownoptionhandler{% - \skv@testopt\skv@unknownoptionhandler\skv@defaultpref + \skv@testopt\skv@unknownoptionhandler\skvdefaultprefix } \skvrobustdef*\skv@unknownoptionhandler[#1]{% \skvifnextchar<{\skv@unkn@wnoptionhandler{#1}}% @@ -251,14 +265,12 @@ \skvrobustdef*\skv@unkn@wnoptionhandler#1<#2>{% \skv@unknownkeyhandler[#1]{#2}% } - - \skvrobustdef*\skv@testopte#1{\skv@testopta{\skv@t@stopte{#1}}} -\skvrobustdef*\skv@t@stopte#1{\skv@testopt{\skv@t@st@pte{#1}}\skv@defaultpref} +\skvrobustdef*\skv@t@stopte#1{\skv@testopt{\skv@t@st@pte{#1}}\skvdefaultprefix} \skvrobustdef*\skv@t@st@pte#1[#2]{% % Only one prefix is allowed: \skvxifinTF{,}{\detokenize{#2}}{% - \skv@err{Only one prefix is allowed, but you gave '#2'}\@ehd + \skv@err{Only one prefix is allowed, but you gave '#2'}\skv@ehd }{% \skv@makeprefix{#2}% \skvifnextchar<{\skv@@t@st@pte{#1}}% @@ -289,6 +301,14 @@ \let\skvdefkey\skvvoidkey \skv@dox@a } +% \skvdeclareobsoleteoption +% [<pref>]{<fam>}{<obsolete key>}{<new key>}[<defa>]{<callback>} +\skvrobustdef*\skvdeclareobsoleteoption{% + \let\@fileswith@pti@ns\@badrequireerror + \let\skvdefkey\skvobsoletekey + \skv@dox@a +} + % \skvdeclarebooloption[<pref>]<<fam>>[<mp>]{<key>}[<defa>]{<callback>} \skvrobustdef*\skvdeclarebooloption{% \let\@fileswith@pti@ns\@badrequireerror @@ -302,44 +322,40 @@ \skv@dox@a } -% Our default action for unknown options is tied to \@currname & \@currext: +% Our default action for unknown options is tied to \@currname +% and \@currext: \skvrobustdef\skv@dox#1{% - \skvcsedef{skv@dox@\@currname @\@currext}{% + \skvcsedef{skv@dox@\@currname.\@currext}{% \unexpanded{% - \begingroup \ifx\skvcurrentvalue\skv@novaluetoks \def\skvcurrentvalue{no value}% \fi - \@onelevel@sanitize\CurrentOption - \@onelevel@sanitize\skvcurrentvalue #1% - \endgroup }% }% } -\skvrobustdef*\skv@dox@a{\skv@testopt\skv@dox@b\skv@defaultpref} +\skvrobustdef*\skv@dox@a{\skv@testopt\skv@dox@b\skvdefaultprefix} \skvrobustdef*\skv@dox@b[#1]{% - \skvifnextchar<% - {\skv@dox@c{#1}}{\skv@dox@c{#1}<\@currname.\@currext>}% + \skvifnextchar<{\skv@dox@c{#1}}{\skv@dox@c{#1}<\@currname.\@currext>}% } \skvrobustdef*\skv@dox@c#1<#2>{\skvdefkey[#1]{#2}} % Declare options with default values that will be used when the options % are called without user values. % -% \skvDeclarePassedOptions[<pref>]{<fam>}{<option>=<default>,...} +% \skvdeclarepassedoptions[<pref>]{<fam>}{<option>=<default>,...} % % Example: % -% \skvDeclarePassedOptions[KV]{fam}{% +% \skvdeclarepassedoptions[KV]{fam}{% % hyperref={colorlinks,breaklinks},xcolor=svgnames % } % -\skvrobustdef*\skvDeclarePassedOptions{% - \skv@testopt\skv@declarepassedoptions\skv@defaultpref +\skvrobustdef*\skvdeclarepassedoptions{% + \skv@testopt\skv@declarepassedoptions\skvdefaultprefix } \skvrobustdef*\skv@declarepassedoptions[#1]#2#3{% - \skvparsekeyvals{#3}\skv@tempa{% + \skvparsekvlist{#3}\skv@tempa{% \skvexpbracenext\skv@kvsplit\skv@tempa{% \skvdeclareoption[#1]<#2>{##1}[##2]{% \skvifcsdefTF{ver@##1.sty}{% @@ -347,9 +363,9 @@ \MessageBreak now you're passing options to it. \MessageBreak Instruction ignored}% }{% - \skvPassOptionsToPackage{####1}{##1}% + \skvpassoptionstopackage{####1}{##1}% \AtBeginDocument{% - \skvifpackageloaded{##1}{}{% + \skvifpackageloadedTF{##1}{}{% \skv@warn{Options were passed to package \MessageBreak '##1' but it was never loaded}% }% @@ -359,9 +375,9 @@ }% }% } -% \skvPassOptionsToPackage{<opts>}{<pkg>} -\skvrobustdef*\skvPassOptionsToPackage{\skv@passoptions{sty}} -\skvrobustdef*\skvPassOptionsToClass{\skv@passoptions{cls}} +% \skvpassoptionstopackage{<opts>}{<pkg>} +\skvrobustdef*\skvpassoptionstopackage{\skv@passoptions{sty}} +\skvrobustdef*\skvpassoptionstoclass{\skv@passoptions{cls}} \skvrobustdef*\skv@passoptions#1#2#3{% \begingroup \edef\@elt{opt@\skvtrimspace{#3}.#1}% @@ -372,14 +388,16 @@ \endgroup } -% \skvDeclarePassedOptionsLoadPackage +% Pass options to package and load the package after processing options. +% +% \skvdeclarepassedoptionsloadpackage % [<pref>]{<fam>}{<option>=<default>,...} % -\skvrobustdef*\skvDeclarePassedOptionsLoadPackage{% - \skv@testopt\skv@declarepassedoptions@load\skv@defaultpref +\skvrobustdef*\skvdeclarepassedoptionsloadpackage{% + \skv@testopt\skv@declarepassedoptions@load\skvdefaultprefix } \skvrobustdef*\skv@declarepassedoptions@load[#1]#2#3{% - \skvparsekeyvals{#3}\skv@tempa{% + \skvparsekvlist{#3}\skv@tempa{% \skvexpbracenext\skv@kvsplit\skv@tempa{% \skvdeclareoption[#1]<#2>{##1}[##2]{% \skvifcsdefTF{ver@##1.sty}{% @@ -418,86 +436,134 @@ % 4. The \ProcessOptionsX of xkeyval package doesn't expect any plus (+) % suffix: it processes options only in a single family. % -\skvrobustdef*\skvprocessoptions{\skv@testopte\skv@pox} +% 5. \skvpackagelist contains the list of loaded packages with their +% options that are found on the current paths. See +% <https://groups.google.com/forum/#!topic/comp.text.tex/XErNCMcT_jc> +% for the rationale. Example: +% +% \usepackage[option1,option2]{foobar} +% \show\skvpackagelist +% \expandafter\show\csname foobar.sty.poxkeys\endcsname +% +\skvnewlet\skvpackagelist\@empty +\skvrobustdef*\skvprocessoptions{% + \skv@getdocumentclass + \ifdefined\skv@documentclass + \global\let\skv@getdocumentclass\relax + \skv@filterclassoptions + \fi + \skv@testopte\skv@pox +} +\skvnewlet\skv@savprocessoptions\skvprocessoptions +\skvrobustdef*\skv@badprocessoptions{% + \skv@testopte{% + \skv@err{\noexpand\skvprocessoptions can't be nested}\skv@ehd + }% +} \skvrobustdef*\skv@pox[#1]{% \skv@inpoxtrue \let\@fileswith@pti@ns\@badrequireerror - \edef\skv@userclassorpackage{\@currname.\@currext}% + \let\skvprocessoptions\skv@badprocessoptions \begingroup - \let\skv@clsoptsfound\@empty - \let\skv@clsorpkgopts\@empty + \edef\skv@userclassorpackage{\@currname.\@currext}% + \let\skv@classoptionsfound\@empty + \let\skv@classorpackageoptions\@empty + % The list of pox keys for each family, simply for taking + % pox keys outside the current scope: \let\skv@exitpoxkeys\@empty - \skvifxTF\skv@userclassorpackage\skv@documentclass{% + % The list of pox keys in all familes: + \let\skvcurrentpoxkeys\@empty + \ifx\skv@userclassorpackage\skv@documentclass + \skv@inclasstrue \let\@unusedoptionlist\skv@classoptionslist - }{% - \ifcase0\ifx\skv@classoptionslist\@empty\else - \ifx\skv@classoptionslist\relax\else\ifskv@st1\fi\fi\fi\relax - \skv@swafalse - \else - \skv@swatrue - \fi - \skvifboolFT{skv@swa}{}{% - \def\ifkeyundef##1##2##3{\skvexpanded{\skvifkeydefFT[##1]{##2}{##3}}}% - \skvcommaloop*\skv@classoptionslist\CurrentOption{% - \expandafter\expandafter\expandafter - \skv@g@tkeyname\CurrentOption=\skv@nil\skvcurrentkey - % Test if key is defined in one of the families. The search will - % stop as soon as the key is found in any of the families. - \ifkeyundef\skvcurrentprefix\skv@fams\skvcurrentkey{}{% - \edef\skv@clsoptsfound{% - \skvexpandonce\skv@clsoptsfound - \ifx\skv@clsoptsfound\@empty\else,\fi - \skvexpandonce\CurrentOption + \else + \skv@inclassfalse + \ifcase0% + \ifx\skv@classoptionslist\@undefined 1\fi + \ifx\skv@classoptionslist\@empty 1\fi + \ifx\skv@classoptionslist\relax 1\fi\relax + \ifskv@st + \def\ifkeyundef##1##2##3{\skvexpanded{\skvifkeydefFT[##1]{##2}{##3}}}% + \skvcommaloop*\skv@classoptionslist\CurrentOption{% + \expandafter\expandafter\expandafter + \skv@g@tkeyname\CurrentOption=\skv@getname@nil\skvcurrentkey + % Test if key is defined in one of the families. The search will + % stop as soon as the key is found in any of the families. + \ifkeyundef\skvcurrentprefix\skv@fams\skvcurrentkey{}{% + \edef\skv@classoptionsfound{% + \skvaddlist,\skv@classoptionsfound\skvexpandonce\CurrentOption + }% + \expandafter\skv@removeoption\expandafter{\CurrentOption}% }% - \expandafter\skv@useoption\expandafter{\CurrentOption}% }% - }% - \ifx\skv@clsoptsfound\@empty\else\skvafterfi - \skvexpbracenext\skv@getkeynames\skv@clsoptsfound\skv@tempd - \skvexpbracenext\skv@getpoxkeys\skv@tempd + \ifx\skv@classoptionsfound\@empty\else + \skvexpbracenext\skv@getnamesofkeys\skv@classoptionsfound\skv@tempd + \skvexpbracenext\skv@getpoxkeys\skv@tempd + \fi \fi - }% - }% - \skvletcs\skv@clsorpkgopts{opt@\@currname.\@currext}% - \skvifxTF\skv@clsorpkgopts\@empty{}{% - \skvifxTF\skv@clsorpkgopts\relax{}{% - \skvexpbracenext\skv@getkeynames\skv@clsorpkgopts\skv@tempd - \skvexpbracenext\skv@getpoxkeys\skv@tempd - }% - }% - % Package options have higher priority than class options. Hence - % filter class options \skv@clsoptsfound that are also present - % as package options \skv@clsorpkgopts: - \ifcase0\ifx\skv@clsoptsfound\@empty\else - \ifx\skv@clsorpkgopts\@empty\else - \ifx\skv@clsorpkgopts\relax\else1\fi\fi\fi\relax - \else\skvafterfi + \fi + \fi + \skvletcs\skv@classorpackageoptions{opt@\@currname.\@currext}% + \ifx\skv@classorpackageoptions\relax + \def\skv@classorpackageoptions{}% + \fi + \skvifemptyTF\skv@classorpackageoptions{}{% + \skvexpbracenext\skv@getnamesofkeys\skv@classorpackageoptions\skv@tempd + \skvexpbracenext\skv@getpoxkeys\skv@tempd + % Package options have higher priority than class options. Hence + % filter class options \skv@classoptionsfound that are also present + % as package options \skv@classorpackageoptions: \skvifxTF\skv@userclassorpackage\skv@documentclass{}{% - \skvcommaloop*\skv@clsoptsfound\CurrentOption{% - \expandafter\expandafter\expandafter - \skv@g@tkeyname\CurrentOption=\skv@nil\skv@tempa - \skvxifinTF{,\skvoxdetok\skv@tempa,}{,\skvoxdetok\skv@tempd,}{}{% - \edef\skv@clsorpkgopts{% - \skvexpandonce\skv@clsorpkgopts,\skvexpandonce\CurrentOption + \skvifemptyTF\skv@classoptionsfound{}{% + \skvcommaloop*\skv@classoptionsfound\CurrentOption{% + \expandafter\skv@g@tkeyname\CurrentOption=\skv@getname@nil\skv@tempa + \skvxifinTF{,\skvoxdetok\skv@tempa,}{,\skvoxdetok\skv@tempd,}{}{% + \edef\skv@classorpackageoptions{% + \skvaddlist,\skv@classorpackageoptions + \skvexpandonce\CurrentOption + }% }% }% }% }% + }% + % Get document class options that are on the current paths: + \ifx\skv@userclassorpackage\skv@documentclass + \def\skvclassoptionsfound{}% + \skvcommaloop*\skv@classorpackageoptions\skv@prova{% + \expandafter\skv@g@tkeyname\skv@prova=\skv@getname@nil\skvcurrentkey + \edef\skv@prova{[\skvcurrentprefix]{\skv@fams}{\skvcurrentkey}}% + \expandafter\skvifkeydefTF\skv@prova{% + \edef\skvclassoptionsfound{% + \skvaddlist,\skvclassoptionsfound\skvcurrentkey + }% + }{}% + }% + \else + \let\skvclassoptionsfound\skv@classoptionsfound \fi + % \skvpackagelist is populated by all calls to \skvprocessoptions. + \skvletcs\skv@prova{\@currname.\@currext.poxkeys}% + \edef\skvpackagelist{% + \skvaddlist,\skvpackagelist + \skvifdefFT\skv@prova{}{\@currname.\@currext{\skv@prova}}% + }% + \let\do\skvcmdexit \skvexpanded{\endgroup - \skv@exitpoxkeys - \skvcmdexit\@unusedoptionlist - % There may be preset keys even when \skv@clsorpkgopts is empty: + \do\skvclassoptionsfound\do\skvcurrentpoxkeys + \do\skvpackagelist\do\@unusedoptionlist + \skvboolexit\ifskv@inclass\skv@exitpoxkeys + % There may be preset keys even when \skv@classorpackageoptions is empty: \skvsetkeys\ifskv@pl+\fi[\skvcurrentprefix]{\skv@fams}[#1]% - {\skvexpandonce\skv@clsorpkgopts}% + {\skvexpandonce\skv@classorpackageoptions}% }% - \skvcslet{skv@dox@\@currname @\@currext}\relax - \skvinitializermkeys*\skvcurrentprefix\skv@fams + \skvcslet{skv@dox@\@currname.\@currext}\relax \skv@inpoxfalse \let\@fileswith@pti@ns\@@fileswith@pti@ns + \let\skvprocessoptions\skv@savprocessoptions \AtEndOfPackage{\let\@unprocessedoptions\relax}% - \csname skv@\@currname @\@currext @afterprocess@hook\endcsname - \skvcslet{skv@\@currname @\@currext @afterprocess@hook}\relax + \csname skv@\@currname.\@currext @afterprocess@hook\endcsname + \skvcslet{skv@\@currname.\@currext @afterprocess@hook}\relax } % \skvprocessoptionswithclassoptions*+[<pref>]{<fams>}[<na>] @@ -506,9 +572,11 @@ % user hasn't put it. % \skvrobustdef*\skvprocessoptionswithclassoptions{% - \skv@testopte\skv@pox@copyclassoptions + \skv@testopte\skv@processoptionswithclassoptions +} +\skvrobustdef*\skv@processoptionswithclassoptions[#1]{% + \skv@sttrue\skv@pox[#1]% } -\skvrobustdef*\skv@pox@copyclassoptions[#1]{\skv@sttrue\skv@pox[#1]} % \skvprocessoptionswithoutclassoptions*+[<pref>]{<fams>}[<na>] % @@ -516,175 +584,189 @@ % user has put it. % \skvrobustdef*\skvprocessoptionswithoutclassoptions{% - \skv@testopte\skv@pox@nocopyclassoptions + \skv@testopte\skv@processoptionswithoutclassoptions +} +\skvrobustdef*\skv@processoptionswithoutclassoptions[#1]{% + \skv@stfalse\skv@pox[#1]% } -\skvrobustdef*\skv@pox@nocopyclassoptions[#1]{\skv@stfalse\skv@pox[#1]} % \skv@getpoxkeys{<keys>} % -% Get pox keys (ie, keys processed as options) from package or -% class options. +% 1. Get pox keys (ie, keys processed as options) from package or +% class options. +% 2. This isn't a user command! See \skvgetdefinedkeys in file +% skeyval-core.tex. \skvrobustdef*\skv@getpoxkeys#1{% \begingroup - \def\xiftest{% - \skvexpanded{% - \noexpand\skvifkeyinfamiliesFT - [\skvcurrentprefix]{\skv@fams}{\skvcurrentkey}% + \skvcommaloop*\skv@fams\skvcurrentfamily{% + \skv@makeheader\skvcurrentfamily + % Prepare to take poxkeys outside the group: + \skvxifinTF{\skvoxdetok\skv@header}{\skvoxdetok\skv@exitpoxkeys}{}{% + \edef\skv@exitpoxkeys{% + \skvexpandonce\skv@exitpoxkeys + \noexpand\skvcsexit{\skvcurrentpath.@poxkeys}% + }% }% - }% - \skvcommaloop{#1}\skvcurrentkey{% - \xiftest{}{% - % \skv@header is formed in the search for the key: - \skvletcs\skv@prova{\skv@header.@poxkeys}% - \skvifdefTF\skv@prova{% - \skvxifinTF{,\skvoxdetok\skvcurrentkey,}{,\skvoxdetok\skv@prova,}{}{% - \skvcsedef{\skv@header.@poxkeys}{\skv@prova,\skvcurrentkey}% - }% - }{% - \skvcsedef{\skv@header.@poxkeys}{\skvcurrentkey}% + \edef\skv@prova{\@currname.\@currext.poxkeys}% + \skvxifinTF{\skvoxdetok\skv@prova}{\skvoxdetok\skv@exitpoxkeys}{}{% + \edef\skv@exitpoxkeys{% + \skvexpandonce\skv@exitpoxkeys\noexpand\skvcsexit{\skv@prova}% }% - \skvxifinTF{\skvoxdetok\skv@header}{\skvoxdetok\skv@exitpoxkeys}{}{% - \edef\skv@exitpoxkeys{% - \skvexpandonce\skv@exitpoxkeys - \noexpand\skvcsexit{\skv@header.@poxkeys}% + }% + \skvcommaloop{#1}\skvcurrentkey{% + \skvifcsdefFT{\skv@header\skvcurrentkey.@cbk}{}{% + \skvletcs\skv@prova{\skvcurrentpath.@poxkeys}% + \skvifdefTF\skv@prova{% + \skvxifinTF{,\skvcurrentkey,}{,\skv@prova,}{}{% + \skvcsedef{\skvcurrentpath.@poxkeys}{% + \skvaddlist,\skv@prova\skvcurrentkey + }% + }% + }{% + \skvcsedef{\skvcurrentpath.@poxkeys}{\skvcurrentkey}% + }% + \skvletcs\skv@prova{\@currname.\@currext.poxkeys}% + \skvifdefTF\skv@prova{% + \skvxifinTF{,\skvcurrentkey,}{,\skv@prova,}{}{% + \skvcsedef{\@currname.\@currext.poxkeys}{% + \skvaddlist,\skv@prova\skvcurrentkey + }% + }% + }{% + \skvcsedef{\@currname.\@currext.poxkeys}{\skvcurrentkey}% + }% + \skvxifinTF{,\skvcurrentkey,}{,\skvcurrentpoxkeys,}{}{% + \edef\skvcurrentpoxkeys{% + \skvaddlist,\skvcurrentpoxkeys\skvcurrentkey + }% }% }% }% }% + \let\do\skvcmdexit \skvexpanded{\endgroup - \skvcmdexit\skv@exitpoxkeys + \do\skvcurrentpoxkeys + % We need the list in \skv@exitpoxkeys outside the current scope. + % It will be used to take poxkeys (on each path) outside the scope + % in \skv@pox: + \do\skv@exitpoxkeys + % We need the poxkeys on each path outside the current scope: \skv@exitpoxkeys }% } % +++++++++ Utilities for handling options via \directkeys +++++++++% -\skvrobustdef*\dirkeys@declareoptions@a{% - \let\@fileswith@pti@ns\@badrequireerror - \skv@dox -} -\skvrobustdef*\dirkeys@declareoptions@b#1{% +% \dirkeys@declareoptions{<star>}{<list>} +% +% <star>, if present, means new options. +% +\skvrobustdef*\dirkeys@declareoptions#1#2{% \let\@fileswith@pti@ns\@badrequireerror - \skv@inopttrue \begingroup - \edef\skv@tempb{\unexpanded{#1}}% + % The boolean skv@inopt differs from skv@inpox. skv@inopt is only + % meant to set the default family in \dirkeys@setdefaultpath + % when dealing with options. + \skv@inopttrue \def\skv@tempa{}% - \def\do##1##2{% + \edef\skv@tempb{\unexpanded{#2}}% + \def\skv@pathdo##1##2{% \edef\skv@tempa{% \skvexpandonce\skv@tempa - \skvdefinekeys\ifskv@handlerswa*\fi[##1]{##2}% + \skvdefinekeys#1[##1]{##2}% [\dirkeys@holderprefixtoks]{\skvexpandonce\skv@tempb}% }% }% - \dirkeys@getcurrentroots\do + \dirkeys@pathlist \expandafter\endgroup\skv@tempa - \skv@inoptfalse } -% % \dirkeys@executeoptions{<options>} +% \dirkeys@executeoptions{<plus sign or empty>}{<kvlist>} % -% 1. Ececute options on all the prevailing paths. If any of -% the options isn't found on a path, report error (ie, -% don't save the key to the list of 'remaining keys'). Unknown -% options should be flagged by an error immediately. -% 2. There is no plus (+) variant for this command/handler. -% 3. It is the user's responsibility to ensure that keys exist on -% current paths. This is easier to enforce if there is only one -% current path (prefix and family). +% 1. <no-plus> = Execute options on ONLY the first path found. If an +% option isn't found on the given paths, report error (ie, +% don't save the option to the list of 'remaining keys'). Unknown +% options should be flagged by an error immediately. Hence no +% star (*) form of \dirkeys@executeoptions. +% 2. <plus> = Execute options on all the prevailing paths. If an +% option isn't found on the given paths, flag error. % -\skvrobustdef*\dirkeys@executeoptions#1{% - \skv@inopttrue +\skvrobustdef*\dirkeys@executeoptions#1#2{% \begingroup - % Don't confuse parameter characters in #1 with those of \do: - \edef\skv@tempb{\unexpanded{#1}}% - \def\skv@tempa{}% - \def\do##1##2{% - \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% - \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% - \edef\skv@tempa{% - \skvexpandonce\skv@tempa - \skvsetkeys[##1]{##2}[\skv@igkeys]{\skvexpandonce\skv@tempb}% - }% - }% - \dirkeys@getcurrentroots\do - \expandafter\endgroup\skv@tempa - \skv@inoptfalse -} - -% \dirkeys@executeoptions@b{<options>} -% -% 1. Ececute options in all the prevailing families. If any of -% the options isn't found in at least one family, report error (ie, -% don't save the key to the list of 'remaining keys'). Unknown options -% should be flagged immediately. -% 2. The plus (+) variant will execute the option in each family in -% which the option is found. -% 3. The difference between \dirkeys@executeoptions and -% \dirkeys@executeoptions@b is that in \dirkeys@executeoptions -% the prefixes can be more than one. Options will be executed for -% all combinations of prefixes and families. -% 4. Prevailing prefixes can't be more than one. -% -\skvrobustdef*\dirkeys@executeoptions@b#1{% \skv@inopttrue - \begingroup - \dirkeys@collectpaths - \skvexpanded{\endgroup - \skvsetkeys+[\skv@tempa]{\skv@tempb}[\skv@tempc]% - }{#1}% - \skv@inoptfalse -} -\skvrobustdef*\dirkeys@collectpaths{% - \skvemptify{\do\skv@tempa\do\skv@tempb\do\skv@tempc}% - \def\do##1##2{% - \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% - \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% - \skvxifinTF{,##1,}{,\skv@tempa,}{}{% - \edef\skv@tempa{\skv@tempa\ifx\skv@tempa\@empty\else,\fi##1}% - }% - \skvxifinTF{,##2,}{,\skv@tempb,}{}{% - \edef\skv@tempb{\skv@tempb\ifx\skv@tempb\@empty\else,\fi##2}% - }% - \edef\skv@tempc{% - \skv@tempc\ifx\skv@tempc\@empty\else,\fi\skv@igkeys + % If the number of families is greater than one, gnored keys + % from different families will mixed. This is the case even in + % \skvsetkeys. + \skvemptify{\skv@igkeys,\skv@fams}% + \@tempcnta\skvz@ + \def\skv@pathdo##1##2{% + \advance\@tempcnta\@ne + \def\skv@pref{##1}% + \ifnum\@tempcnta=\@ne + \def\skv@firstpref{##1}% + \else + \ifx\skv@pref\skv@firstpref\else + \skv@err{You can't use multiple prefixes when + \MessageBreak calling the handler '.execute options'. + \MessageBreak Check your values of '.prefix' and '.paths'}\skv@ehd + \fi + \fi + \skvxifinTF{,##2,}{,\skv@fams,}{}{% + \edef\skv@fams{\skvaddlist,\skv@fams##2}% }% + \skvletcs\skv@prova{##1/##2/.@ignoredkeys}% + \ifdefined\skv@prova + \edef\skv@igkeys{\skvaddlist,\skv@igkeys\skv@prova}% + \fi }% - \dirkeys@getcurrentroots\do - \skvifelementcount*\skv@tempa\tw@ - {\skv@err{You can't submit more than one prefix here}\@ehd}{} + \dirkeys@pathlist + \ifx\skv@fams\@empty + \skv@err{No family before calling '.execute options'}\skv@ehd + \fi + \skvexpanded{\endgroup + \skvsetkeys#1[\skv@pref]{\skv@fams}[\skv@igkeys]% + }{#2}% } -\skvrobustdef*\dirkeys@processoptions{% - \skv@inopttrue +\skvrobustdef*\dirkeys@processoptions#1#2{% \begingroup - \def\skv@tempa{}% - \def\do##1##2{% - \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}% - \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}% - \edef\skv@tempa{% - \skvexpandonce\skv@tempa - \skvprocessoptions\ifskv@handlerswa*\fi - [##1]<##2>[\skv@igkeys]% + \skv@inopttrue + % If the number of families is greater than one, gnored keys + % from different families will mixed. This is the case even in + % \skvprocessoptions. + \skvemptify{\skv@igkeys,\skv@fams}% + \@tempcnta\skvz@ + \def\skv@pathdo##1##2{% + \advance\@tempcnta\@ne + \def\skv@pref{##1}% + \ifnum\@tempcnta=\@ne + \def\skv@firstpref{##1}% + \else + \ifx\skv@pref\skv@firstpref\else + \skv@err{You can't use multiple prefixes when + \MessageBreak calling the handler '.process options'. + \MessageBreak Check your values of '.prefix' and '.paths'}\skv@ehd + \fi + \fi + \skvxifinTF{,##2,}{,\skv@fams,}{}{% + \edef\skv@fams{\skvaddlist,\skv@fams##2}% }% + \skvletcs\skv@prova{##1/##2/.@ignoredkeys}% + \ifdefined\skv@prova + \edef\skv@igkeys{\skvaddlist,\skv@igkeys\skv@prova}% + \fi }% - \dirkeys@getcurrentroots\do - \expandafter\endgroup\skv@tempa - \skv@inoptfalse -} -\skvrobustdef*\dirkeys@processoptions@b{% - \skv@inopttrue - \begingroup - \dirkeys@collectpaths + \dirkeys@pathlist + \ifx\skv@fams\@empty + \skv@err{No family before calling '.process options'}\skv@ehd + \fi \skvexpanded{\endgroup - \skvprocessoptions\ifskv@handlerswa*\fi - +[\skv@tempa]<\skv@tempb>[\skv@tempc]% + \skvprocessoptions#1#2[\skv@pref]<\skv@fams>[\skv@igkeys]% }% - \skv@inoptfalse } % ++++++++ Keys for the handler <.mega process options> +++++++++ % \directkeys*{% - .prefix=SKV, - .family=megapox, + .path={SKV/megapox}, .holder prefix=dirkeys@pox@, .initialize keys after define=true, .new keys={ @@ -692,124 +774,121 @@ \def\dirkeys@pox@igkeys{#1} \skvstripouterbraces{2}\dirkeys@pox@igkeys , - .ord/.options prefix/\skv@defaultpref/ - \skvxifinTF{,}{\detokenize{#1}}{ - \skv@err{Only one prefix is allowed in processing options}\@ehd - }{ - \def\dirkeys@pox@pref{#1} + .ord/{.prefix,.options prefix}/\skvdefaultprefix/ + \skv@ifoneprefix{#1}{% + \edef\dirkeys@pox@pref{#1} \skvstripouterbraces{2}\dirkeys@pox@pref + }{% + \skv@err{Only one prefix is allowed in + \MessageBreak processing options}\skv@ehd } , - .ord/.options families/\@currname.\@currext/ + .ord/{.family,.families,.options families,.options family}/ + \@currname.\@currext/ \edef\dirkeys@pox@fams{#1} \skvstripouterbraces{2}\dirkeys@pox@fams + \skv@makepaths\dirkeys@pox@pref\dirkeys@pox@fams + \dirkeys@megapox@pathlist\skv@pathdo , - .ord/.copy class options/true/ - \edef\dirkeys@pox@copyclass{\skvifstrcmpTF{#1}{true}{00}{01}} + .ord/{path,.paths,.option path,.option paths}/ + {KV/\@currname.\@currext}/ + \skv@formatpaths{#1}\dirkeys@megapox@pathlist + , + .ord/{.copy class options,.include class options}/true/ + \edef\dirkeys@pox@copyclass{0\skvifstrcmpTF{#1}{true}{0}{1}} , - }, - .styles={ - .prefix/.options prefix=#1, - .options family/.options families=#1, - .family/.options families=#1, - .families/.options families=#1, - .include class options/.copy class options=#1, }, } %\skvshowcs{SKV/megapox/.options family.@cbk} %\skvshowcs{SKV/megapox/.pref.@cbk} +\skvnewnumbers[skv@]{megapoxdepth} \skvrobustdef*\dirkeys@megaprocessoptions#1{% - \skvpushfunctions\dirkeys@megaprocessoptions{% - \do\dirkeys@pox@pref\do\dirkeys@pox@fams + \skvpushfunctions\dirkeys@megapox{% + \do\dirkeys@pathlist\do\skv@pathdo\do\dirkeys@megapox@pathlist \do\dirkeys@pox@igkeys\do\dirkeys@pox@copyclass - }\skv@gendepth - \skv@inopttrue + }\skv@megapoxdepth + \skvemptify{\dirkeys@megapox@pathlist,\dirkeys@pox@igkeys}% + \let\dirkeys@pox@pref\skvdefaultprefix + \def\dirkeys@pox@copyclass{01}% \skvsetkeys[SKV]{megapox}{#1}% + \ifx\dirkeys@pox@igkeys\@empty + % So that all '...@ignoredkeys' will be undefined: + \let\dirkeys@pox@igkeys\undefined + \fi + \let\dirkeys@pathlist\dirkeys@megapox@pathlist + \def\skv@pathdo##1##2{% + \skvcslet{##1/##2/.@ignoredkeys}\dirkeys@pox@igkeys + }% + \dirkeys@pathlist \skvexpanded{% - \skvprocessoptions\if\dirkeys@pox@copyclass*\fi+% - [\dirkeys@pox@pref]<\dirkeys@pox@fams>[\dirkeys@pox@igkeys]% + \dirkeys@processoptions\if\dirkeys@pox@copyclass*\fi{+}% }% - \skv@inoptfalse - \skvpopfunctions\dirkeys@megaprocessoptions\skv@gendepth + \skvpopfunctions\dirkeys@megapox\skv@megapoxdepth } -% +++++++++++++ Handlers for processing options ++++++++++++++ % +% +++++++++++++ Handlers for executing and processing options ++++++++++++ % \directkeys*{% .new handlers={ - .action for unknown options=\dirkeys@declareoptions@a{#1}, - .declare options={ - \skv@handlerswafalse\dirkeys@declareoptions@b{#1} + {.action for unknown options,.action for unknown options}={ + \let\@fileswith@pti@ns\@badrequireerror + \skv@dox{#1} }, - .new options={ - \skv@handlerswatrue\dirkeys@declareoptions@b{#1} + {.declare option,.declare options,.define option,.define options}={ + \dirkeys@declareoptions{}{#1} }, - .execute options={ - \dirkeys@executeoptions{#1} + {.new option,.new options}={ + \dirkeys@declareoptions{*}{#1} }, - .execute options+={ - \dirkeys@executeoptions@b{#1} + {.execute options,.executeoptions,.execute options in one family}={ + \dirkeys@executeoptions{}{#1} }, - .execute options*={ + {.execute options*,.executeoptions*}={ \skv@err - {Handler <.execute options*> is undefined} - {Handler <.execute options> has no star (*) variant, + {Handler '.execute options*' is undefined} + {Handler '.execute options' has no star (*) variant, \MessageBreak since we don't want to ignore unknown \MessageBreak options from within package or class file.}% }, - .execute options*+={ - \skv@err - {Handler <.execute options*+> is undefined} - {Handler <.execute options+> has no star (*) variant, - \MessageBreak since we don't want to ignore unknown - \MessageBreak options from within package or class file.}% + {.execute options+,.executeoptions+,.execute options in all families}={ + \dirkeys@executeoptions{+}{#1} }, % 1. All <.process options> handlers will filter out ignored keys. % 2. <.process options*> will copy class options. - % 3. <.process options+> will set options in all the active families - % in which the options exist. - % 4. <.process options*+> will copy class options and set options in - % all the active families in which the options are found. - .process options={ - \skv@handlerswafalse\dirkeys@processoptions + {.process options,.processoptions,.process options in one family}={ + \dirkeys@processoptions{}{} }, - .process options*={ - \skv@handlerswatrue\dirkeys@processoptions + {.process options*,.processoptions*, + .copy class options and process options, + .copy class options and process options in one family}={ + \dirkeys@processoptions{*}{} }, - .process options+={ - \skv@handlerswafalse\dirkeys@processoptions@b + {.process options+,.processoptions+,.process options in all families}={ + \dirkeys@processoptions{}{+} }, - .process options*+={ - \skv@handlerswatrue\dirkeys@processoptions@b + {.process options*+,.processoptions*+, + .copy class options and process options in all families}={ + \dirkeys@processoptions{*}{+} }, % The handler <.mega process options> will: - % 1. Search all families in its key <families>. - % 2. Not perform filtering of ignored paths and keys; in fact, will not + % 1. Search all families in its key <paths>. + % 2. Not filter ignored paths and keys; in fact, it will not % use active paths and keys. % 3. The handler '.mega process options' has the keys <ignore options>, % <options prefix>, <options families>, and <copy class options>. % These keys have aliases. % See an example later in this file. - .mega process options={ + {.mega process options,.megaprocessoptions}={ \dirkeys@megaprocessoptions{#1} }, - .mega process options*={ + {.mega process options*,.megaprocessoptions*}={ \dirkeys@megaprocessoptions{#1,copy class options} }, }, .handler let={ - .action for unknown option=.action for unknown options, - .every unknown option=.action for unknown options, - .define options=.declare options, - .processoptions=.process options, - .processoptions*=.process options*, - .copy class options and process options in all active families= - .process options*+, - .copy class options and process options in all families= - .process options*+, - .copy class options and process options=.process options*, - .executeoptions=.execute options, + {.action for unknown option,.every unknown option}= + .action for unknown options, }, } %\skvshowcs{dirkeys@handler@.every unknown option} @@ -819,69 +898,59 @@ % till after the options section: \skvrobustdef*\skvafterprocessoptions{% \expandafter\skvgappendtomacro - \csname skv@\@currname @\@currext @afterprocess@hook\endcsname + \csname skv@\@currname.\@currext @afterprocess@hook\endcsname } -\skvnewlet\skvifpackageloaded\@ifpackageloaded +\skvnewlet\skvifpackageloadedTF\@ifpackageloaded -\def\skv@visiteduseoptions{01} -\skvrobustdef*\skv@useoption#1{% - \if\skv@visiteduseoptions\else - \skvcsvnormalize\@unusedoptionlist - \def\skv@visiteduseoptions{00}% - \fi - \begingroup - \@onelevel@sanitize\@unusedoptionlist - \skv@kvosplit{\detokenize{#1}}{% - \edef\CurrentOption{\skvtrimspace{##1}}% +\skvnewdef*\skv@visiteduseoptions{01} +\skvrobustdef*\skv@removeoption#1{% + \ifx\@unusedoptionlist\@empty\else + \if\skv@visiteduseoptions\else + \skvcsvnormalize\@unusedoptionlist + \def\skv@visiteduseoptions{00}% + \fi + \begingroup + \skv@g@tkeyname#1=\skv@getname@nil\skv@tempb + \@onelevel@sanitize\skv@tempb \def\skv@tempa{}% \skvcommaloop*\@unusedoptionlist\skv@prova{% - \skv@kvosplit\skv@prova{% - \edef\reserved@a{\skvtrimspace{####1}}% - \ifx\reserved@a\CurrentOption\else - \edef\skv@tempa{% - \skv@tempa\ifx\skv@tempa\@empty\else,\fi\skv@prova - }% - \fi - }% + \expandafter\skv@g@tkeyname\skv@prova=\skv@getname@nil\skv@provb + \@onelevel@sanitize\skv@provb + \ifx\skv@provb\skv@tempb\else + \edef\skv@tempa{\skvaddlist,\skv@tempa\skvexpandonce\skv@prova}% + \fi }% \let\@unusedoptionlist\skv@tempa - }% - \skvaftergroupdef\@unusedoptionlist\endgroup + \skvaftergroupdef\@unusedoptionlist\endgroup + \fi } \skvonlypreamble{% - \skvdeclareoption,\skvexecuteoptions,\skvprocessoptions,\skv@useoption, - \dirkeys@declareoptions@a,\dirkeys@declareoptions@b, - \dirkeys@megaprocessoptions,\dirkeys@processoptions, - \dirkeys@processoptions@b,\skvprocessoptionswithclassoptions, - \skvprocessoptionswithoutclassoptions,\dirkeys@executeoptions, - \dirkeys@executeoptions@b + \skvdeclareoption,\skvexecuteoptions,\skvprocessoptions,\skv@removeoption, + \skveveryunknownoption,\dirkeys@declareoptions, + \dirkeys@megaprocessoptions,\dirkeys@processoptions,\dirkeys@executeoptions, + \skvprocessoptionswithclassoptions,\skvprocessoptionswithoutclassoptions } %+++++++++++++++++ This package's options section ++++++++++++++++++% \skvrobustdef*\setupskeyval{\skvsetkeys[SKV]{skeyval}} \skv@inoptionsectrue - -%\skvshowcs{dirkeys@handler@.every unknown option} - \directkeys*{% .every unknown option={ \@onelevel@sanitize\CurrentOption \PackageWarning{skeyval}{Unknown option '\CurrentOption' ignored}% }, - .prefix=SKV, - .family=skeyval, + .path=SKV/skeyval, .holder prefix=skv@, .new options={ - .bool/verbose/true, - .bool/tracingkeys/true, + .bool/{verbose,tracingkeys}/true, .ord/{keyparser,key parser}/{,}/ \def\skv@keyparser{#1}% \skvstripouterbraces{2}\skv@keyparser, .bool/compatibility/true/ \ifskv@compatibility \skvafterprocessoptions{% - \skvifpackageloaded{skeyval-bc}{}{% + \skvifpackageloadedTF{skeyval-bc}{}{% \RequirePackage{skeyval-bc}% } }% @@ -898,9 +967,17 @@ .copy class options, }, } -%\skvshowcs{SKV/skeyval/keyparser.@cbk} - \skv@inoptionsecfalse \skv@restorecodes \endinput + + + + + + +\edef\skv@prova{\@currname.\@currext/\skvcurrentkey}% + \skvxifinTF{,\skv@prova,}{,\skvpackagelist,}{}{% + \edef\skvpackagelist{\skvaddlist,\skvpackagelist\skv@prova}% + }% |