summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/skeyval/skeyval-core.tex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2013-02-13 00:03:06 +0000
committerKarl Berry <karl@freefriends.org>2013-02-13 00:03:06 +0000
commitfee6ae63b6689ddbae970ff9114c6ed976bf1dab (patch)
tree939a7748a57f664be54e21ea64d2168617f5d07c /Master/texmf-dist/tex/latex/skeyval/skeyval-core.tex
parent4abc207ecf013eb27bf9f83c29b8a82408c9cd71 (diff)
skeyval (12feb13)
git-svn-id: svn://tug.org/texlive/trunk@29092 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/skeyval/skeyval-core.tex')
-rw-r--r--Master/texmf-dist/tex/latex/skeyval/skeyval-core.tex5115
1 files changed, 3305 insertions, 1810 deletions
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'.