summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/skeyval/tex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/skeyval/tex
Initial commit
Diffstat (limited to 'macros/latex/contrib/skeyval/tex')
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-bc.sty3194
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-core.tex8466
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-for.tex2862
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-ltxcmds.tex316
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-ltxpatch.sty444
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-pstkey.sty87
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-pstkey.tex94
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-testclass.cls321
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-testpkg.sty456
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval-view.sty425
-rw-r--r--macros/latex/contrib/skeyval/tex/skeyval.sty971
11 files changed, 17636 insertions, 0 deletions
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-bc.sty b/macros/latex/contrib/skeyval/tex/skeyval-bc.sty
new file mode 100644
index 0000000000..6d90b9958e
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-bc.sty
@@ -0,0 +1,3194 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-bc.sty', version 0.73 of skeyval package, %
+% 2011/01/01. %
+% NOTE %
+% This file is provided only for backward compatibility (bc) of the %
+% skeyval package. Beginning from version 1.0, September 2012, the %
+% package has changed radically. Users of pre-version 1.0 of the package %
+% can load it now by calling: %
+% %
+% \usepackage[compatibility]{skeyval} %
+% \RequirePackage[compatibility]{skeyval} %
+% or %
+% \usepackage{skeyval-bc} %
+% \RequirePackage{skeyval-bc} %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup
+\catcode064 11% @
+\catcode123 01% {
+\catcode125 02% }
+\def\SKV@tempa{\endgroup
+ \edef\SKV@restorecodes{%
+ \catcode035 \the\catcode035% #
+ \catcode064 \the\catcode064% @
+ \catcode123 \the\catcode123% {
+ \catcode125 \the\catcode125% }
+ \catcode061 \the\catcode061% =
+ }%
+}
+\SKV@tempa
+\catcode035 06% #
+\catcode061 12% =
+\catcode064 11% @
+\catcode123 01% {
+\catcode125 02% }
+\def\SKV@setcode#1#2{%
+ \edef\SKV@restorecodes{%
+ \SKV@restorecodes
+ \catcode#1 \the\catcode#1\relax
+ }%
+ \catcode#1 #2\relax
+}
+\AtEndOfPackage{%
+ \SKV@AfterPackageEnd{%
+ \SKV@restorecodes
+ \SKV@Undef!{\SKV@setcode\SKV@restorecodes}%
+ }%
+}
+\SKV@setcode{010}{12}% ^^J
+\SKV@setcode{032}{10}% SP
+\SKV@setcode{033}{12}% !
+\SKV@setcode{036}{03}% $
+\SKV@setcode{038}{03}% &
+\SKV@setcode{040}{12}% (
+\SKV@setcode{041}{12}% )
+\SKV@setcode{042}{12}% *
+\SKV@setcode{043}{12}% +
+\SKV@setcode{044}{12}% ,
+\SKV@setcode{045}{12}% -
+\SKV@setcode{047}{12}% /
+\SKV@setcode{058}{12}% :
+\SKV@setcode{059}{12}% ;
+\SKV@setcode{060}{12}% >
+\SKV@setcode{062}{12}% <
+\SKV@setcode{063}{12}% ?
+\SKV@setcode{091}{12}% [
+\SKV@setcode{093}{12}% ]
+\SKV@setcode{096}{12}% `
+\SKV@setcode{126}{13}% ~
+\def\SKV@rcsid$#1: #2 #3 #4 #5${#4 v#3}
+\ProvidesPackage{skeyval}[%
+ \SKV@rcsid $Id: skeyval.sty,v 0.73 2011/01/01 09:00:00 Ahmed Musa $
+ Extensions to the xkeyval parser (AM)
+]
+\NeedsTeXFormat{LaTeX2e}[1996/12/01]
+\ifnum0=0%
+ \ifx\eTeXversion\SKV@undefined1\else\ifnum\eTeXversion<\tw@1\fi\fi
+\else
+ \PackageError{skeyval}{eTeX not loaded or old version}%
+ {This package requires eTeX version 2 or later.}%
+ \endinput
+\fi
+\newtoks\SKV@toks
+\newcount\SKV@depth
+\protected\def\@nil{\@nil}
+\def\@nnil{\@nil}
+\def\@space{ }
+\long\def\@firstofthree#1#2#3{#1}
+\long\def\@secondofthree#1#2#3{#2}
+\long\def\@thirdofthree#1#2#3{#3}
+\long\def\@gobblethree#1#2#3{}
+\long\def\SKV@car#1#2\@nil{#1}
+\long\def\SKV@cdr#1#2\@nil{#2}
+\long\def\SKV@carcube#1#2#3#4\@nil{#1#2#3}
+\def\SKV@threexp{\expandafter\expandafter\expandafter}
+\def\SKV@aftercs#1#2{\expandafter#1\csname#2\endcsname}
+\def\SKV@xaftercs#1#2{\SKV@threexp#1\csname#2\endcsname}
+\SKV@aftercs\let{SKV@1of1}\@firstofone
+\SKV@aftercs\let{SKV@1of2}\@firstoftwo
+\SKV@aftercs\let{SKV@2of2}\@secondoftwo
+\SKV@aftercs\let{SKV@1of3}\@firstofthree
+\SKV@aftercs\let{SKV@2of3}\@secondofthree
+\SKV@aftercs\let{SKV@3of3}\@thirdofthree
+\def\SKV@ifx#1#2{\@nameuse{SKV@\ifx#1#21\else2\fi of2}}
+\def\SKV@unifx#1#2{\@nameuse{SKV@\ifx#1#22\else1\fi of2}}
+\def\SKV@csifx#1#2{\begingroup\expandafter\endgroup\expandafter
+ \SKV@ifx\csname#1\endcsname#2}
+\def\SKV@uncsifx#1#2{\begingroup\expandafter\endgroup\expandafter
+ \SKV@unifx\csname#1\endcsname#2}
+\def\SKV@ifxcs#1#2{\begingroup\expandafter\endgroup\expandafter
+ \SKV@ifx\expandafter#1\csname#2\endcsname}
+\def\SKV@unifxcs#1#2{\begingroup\expandafter\endgroup\expandafter
+ \SKV@unifx\expandafter#1\csname#2\endcsname}
+\def\SKV@ifdefined#1{\@nameuse{SKV@\ifdefined#11\else2\fi of2}}
+\def\SKV@oifdefined#1{\@nameuse{SKV@\expandafter\SKV@ifdefined#1{1}{2}of2}}
+\def\SKV@unifdefined#1{\@nameuse{SKV@\SKV@ifdefined{#1}{2}{1}of2}}
+\def\SKV@ifcsname#1{\@nameuse{SKV@\ifcsname#1\endcsname1\else2\fi of2}}
+\def\SKV@unifcsname#1{\@nameuse{SKV@\SKV@ifcsname{#1}{2}{1}of2}}
+\def\SKV@ifnum#1#2#3{\@nameuse{SKV@\ifnum#1#2#3 1\else2\fi of2}}
+\protected\def\SKV@AtEndAfterPackageEnd#1{\AtEndOfPackage
+ {\SKV@AfterPackageEnd{#1}}}
+\begingroup
+\def\SKV@tempa{%
+ \def\SKV@nodocerr{%
+ \PackageError{skeyval}{'skeyval' package loaded before
+ \string\documentclass}{Load skeyval package after
+ \string\documentclass.}%
+ \endinput
+ }%
+ \def\SKV@tempb##1\@nil,{}%
+ \def\SKV@tempa##1,{%
+ \def\@currname{##1}%
+ \SKV@ifx\SKV@documentclass\SKV@undefined{%
+ \SKV@ifx\@currname\@nnil{}{%
+ \filename@parse\@currname
+ \SKV@unifx\filename@ext\@clsextension{}{%
+ \SKV@unifcsname{opt@\filename@area\filename@base.%
+ \filename@ext}{}{%
+ \edef\SKV@documentclass{\filename@area%
+ \filename@base.\filename@ext}%
+ }%
+ }%
+ \SKV@tempa
+ }%
+ }{%
+ \let\SKV@tempa\SKV@tempb\SKV@tempa
+ }%
+ }%
+ \SKV@ifx\@filelist\relax\SKV@nodocerr{%
+ \SKV@ifx\@filelist\@gobble\SKV@nodocerr{%
+ \expandafter\SKV@tempa\@filelist,\@nil,%
+ }%
+ }%
+ \SKV@ifx\SKV@documentclass\SKV@undefined\SKV@nodocerr\relax
+}
+\SKV@tempa\endgroup
+\def\SKV@notdefinable{%
+ \PackageError{skeyval}%
+ {Command '\@backslashchar\resvd@a' not definable,
+ \MessageBreak or name '\@backslashchar\@qend...' illegal}%
+ {Command '\@backslashchar\resvd@a' already defined.}%
+}
+\def\SKV@ifdefinable#1{%
+ \begingroup
+ \escapechar92\relax
+ \xdef\resvd@a{\expandafter\@gobble\string#1}%
+ \edef\resvd@b{\expandafter\SKV@car\string#1\@nil}%
+ \SKV@ifx\resvd@b\@backslashchar{}{%
+ \PackageError{skeyval}{Backslash required}{Backslash
+ required in argument of '\string\SKV@ifdefinable'.}%
+ }%
+ \SKV@ifdefined#1{%
+ \SKV@ifx{#1}\relax{\aftergroup\@firstofone}%
+ {\aftergroup\SKV@notdefinable}%
+ }{%
+ \edef\resvd@b{\unexpanded\expandafter{\csname end\resvd@a\endcsname}}%
+ \expandafter\SKV@ifx\resvd@b\relax{%
+ \SKV@ifx\resvd@a\@qrelax{\aftergroup\SKV@notdefinable}%
+ {\aftergroup\@firstofone}
+ }{\aftergroup\SKV@notdefinable}%
+ }%
+ \endgroup
+}
+\def\SKV@csifdefinable#1{\begingroup\expandafter\endgroup
+ \expandafter\SKV@ifdefinable\csname#1\endcsname}
+\newcommand*\@ifpackagecurrent[2]{%
+ \@nameuse{SKV@\ifnum\SKV@threexp\@parse@version
+ \csname ver@#1.\@pkgextension\endcsname//00\@nil
+ <\expandafter\@parse@version#2//00\@nil2\else1\fi of2}%
+}
+\newcommand*\@ifpackagenotcurrent[2]{%
+ \@nameuse{SKV@\@ifpackagecurrent{#1}{#2}{2}{1}of2}}
+\newcommand*\@ifloadedandcurrent[2]{%
+ \begingroup
+ \@ifpackageloaded{#1}{%
+ \@ifpackagecurrent{#1}{#2}{\aftergroup\@firstofthree}{%
+ \aftergroup\@secondofthree}}{\aftergroup\@thirdofthree}%
+ \endgroup
+}
+\@ifloadedandcurrent{xkeyval}{2008/08/13}{}{%
+ \PackageError{skeyval}%
+ {Your loaded version of xkeyval package is not current}%
+ {You need version 2.6a (or higher) of xkeyval package.}%
+ \endinput
+}{\RequirePackage{xkeyval}[2008/08/13]}
+\newcommand*\SKV@ifdefinable@n[1]{%
+ \XKV@sp@deflist\SKV@tempa{#1}%
+ \XKV@for@o\SKV@tempa\SKV@tempa{%
+ \edef\resvd@a{\SKV@threexp\SKV@car
+ \expandafter\string\SKV@tempa\@nil}%
+ \SKV@unifx\resvd@a\@backslashchar{}{%
+ \PackageError{skeyval}{Backslash not allowed}{Backslash not
+ allowed in argument of '\string\SKV@ifdefinable@n'.}%
+ }%
+ \SKV@csifdefinable\SKV@tempa\relax
+ }%
+}
+\SKV@ifdefinable@n{SKV@def,SKV@d@f,SKV@pdef,SKV@pd@f}
+\protected\def\SKV@def{\@star@or@long\SKV@d@f}
+\def\SKV@d@f#1{\SKV@ifdefinable#1{\l@ngrel@x\def#1}}
+\protected\def\SKV@pdef{\@star@or@long\SKV@pd@f}
+\def\SKV@pd@f#1{\SKV@ifdefinable#1{\l@ngrel@x\protected\def#1}}
+\SKV@pdef*\SKV@gdef{\@star@or@long\SKV@gd@f}
+\SKV@def*\SKV@gd@f#1{\SKV@ifdefinable#1{\l@ngrel@x\gdef#1}}
+\SKV@pdef*\SKV@edef{\@star@or@long\SKV@ed@f}
+\SKV@def*\SKV@ed@f#1{\SKV@ifdefinable#1{\l@ngrel@x\edef#1}}
+\SKV@pdef*\SKV@pgdef{\@star@or@long\SKV@pgd@f}
+\SKV@def*\SKV@pgd@f#1{\SKV@ifdefinable#1{\l@ngrel@x\protected\gdef#1}}
+\SKV@pdef*\SKV@pedef{\@star@or@long\SKV@ped@f}
+\SKV@def*\SKV@ped@f#1{\SKV@ifdefinable#1{\l@ngrel@x\protected\edef#1}}
+\SKV@pdef*\SKV@pxdef{\@star@or@long\SKV@pxd@f}
+\SKV@def*\SKV@pxd@f#1{\SKV@ifdefinable#1{\l@ngrel@x\protected\xdef#1}}
+\SKV@pdef*\SKV@redef{\@star@or@long\SKV@red@f}
+\SKV@def*\SKV@red@f#1{%
+ \SKV@ensurescape{#1}%
+ \SKV@unifdefined{#1}{}{%
+ \SKV@ifx{#1}\relax{}{%
+ \SKV@vbmsg{info}{Command '\string#1' redefined\on@line}%
+ }%
+ }%
+ \l@ngrel@x\def#1%
+}
+\SKV@pdef*\SKV@csredef{\SKV@aftercs\SKV@redef}
+\SKV@pdef*\SKV@predef{\@star@or@long\SKV@pred@f}
+\SKV@def*\SKV@pred@f#1{%
+ \SKV@ensurescape{#1}%
+ \SKV@unifdefined{#1}{}{%
+ \SKV@ifx{#1}\relax{}{%
+ \SKV@vbmsg{info}{Command '\string#1' redefined\on@line}%
+ }%
+ }%
+ \l@ngrel@x\protected\def#1%
+}
+\SKV@pdef*\SKV@cspredef{\SKV@aftercs\SKV@predef}
+\SKV@def*\SKV@vbmsg#1#2{%
+ \begingroup
+ \def\@i{info}\def\@ii{warn}\def\@iii{#1}%
+ \@nameuse{SKV@\ifSKV@verbose1\else2\fi of2}%
+ {\SKV@ifx\@i\@iii
+ {\SKV@info{#2}}%
+ {\SKV@ifx\@ii\@iii{\SKV@warn{#2}}{}}%
+ }{}%
+ \endgroup
+}
+\define@boolkeys[KV]{skeyval@i}[SKV@]{st,pl,cl,rt,
+ lt,sw,sk,loc,uv}[true]
+\setkeys[KV]{skeyval@i}{st,pl,cl,rt,lt,sw,sk,loc,uv}
+\define@boolkey+[KV]{skeyval}[SKV@]{verbose}[true]{}{%
+ \SKV@inputerr{#1}{verbose}%
+}
+\setkeys[KV]{skeyval}{verbose=false}
+\SKV@pdef\SKV@info#1{\PackageInfo{skeyval}{#1\@gobble}}
+\SKV@pdef\SKV@warn#1{\PackageWarningNoLine{skeyval}{#1}}
+\SKV@pdef\SKV@err#1#2{\PackageError{skeyval}{#1}{#2}}
+\SKV@def*\SKV@MB{\MessageBreak}
+\SKV@pdef\SKV@afterfi#1\fi{\fi#1}
+\SKV@pdef\SKV@afterelsefi#1\else#2\fi{\fi#1}
+\SKV@pdef\SKV@afterfifi#1\fi#2\fi{\fi#2\fi#1}
+\SKV@def*\SKV@badargerr#1#2{%
+ \SKV@err{Invalid #2 argument for command '\@backslashchar#1'}%
+ {Bad #2 argument for command '\@backslashchar#1'.\SKV@MB
+ You need to look again at user instruction\SKV@MB
+ for command '\@backslashchar#1'.}%
+}
+\SKV@def*\SKV@state#1#2#3{%
+ \ifcase#1\relax
+ \def\SKV@ste{XKV@prefix,XKV@fams,XKV@tkey,XKV@na,ifXKV@st,%
+ ifXKV@pl,ifXKV@knf,CurrentOption,ifSKV@sk}%
+ \SKV@ifempty{#3}{\advance\XKV@depth\@ne}{}%
+ \or
+ \def\SKV@ste{ifSKV@st,ifSKV@pl,ifSKV@cl,ifSKV@rt,ifSKV@lt}%
+ \SKV@ifempty{#3}{\advance\SKV@depth\@ne}{}%
+ \else
+ \SKV@err{Unknown state identifier '#1'}%
+ {I expected '\string#1' to be number 0 or 1.}%
+ \fi
+ \XKV@for@o\SKV@ste\SKV@ste{%
+ \SKV@aftercs\let{\SKV@ste#2\SKV@aftercs}{\SKV@ste#3}%
+ }%
+ \ifcase#1\relax
+ \SKV@ifempty{#2}{\advance\XKV@depth\m@ne}{}%
+ \or
+ \SKV@ifempty{#2}{\advance\SKV@depth\m@ne}{}%
+ \fi
+}
+\SKV@def*\XKV@savstate{\SKV@state{0}{@\romannumeral\XKV@depth}{}}
+\SKV@def*\XKV@resstate{\SKV@state{0}{}{@\romannumeral\XKV@depth}}
+\SKV@def*\SKV@savstate{\SKV@state{1}{@\romannumeral\SKV@depth}{}}
+\SKV@def*\SKV@resstate{\SKV@state{1}{}{@\romannumeral\SKV@depth}}
+\def\XKV@srstate#1#2{\SKV@state{0}{#1}{#2}}
+\SKV@def*\SKV@scantoksa{\SKV@savstate\SKV@testoptf\SKV@sc@ntoksa}
+\SKV@def\SKV@sc@ntoksa[#1]#2{%
+ \ifSKV@cl\let\gl@l@x\global\else\let\gl@l@x\relax\fi
+ \SKV@for[#1]{#2}\SKV@resvda{%
+ \ifSKV@pl
+ \SKV@ifcsdef\SKV@resvda{}{%
+ \SKV@err{Command '\SKV@csexpox\SKV@resvda' undefined}%
+ {I can't scan contents of undefined command
+ '\SKV@csexpox\SKV@resvda'}%
+ }%
+ \SKV@expnext\SKV@ensurenoscape\SKV@resvda
+ \expandafter\let\expandafter\SKV@resvdb%
+ \csname\SKV@resvda\endcsname
+ \else
+ \expandafter\SKV@ifdef\SKV@resvda{}{%
+ \SKV@err{Command '\SKV@expox\SKV@resvda' undefined}%
+ {I can't scan contents of undefined command
+ '\SKV@expox\SKV@resvda'}%
+ }%
+ \SKV@expnext\SKV@ensurescape\SKV@resvda
+ \expandafter\let\expandafter\SKV@resvdb\SKV@resvda
+ \fi
+ \SKV@noexpparse\SKV@resvdb
+ \begingroup
+ \edef\SKV@resvdb##1##2{##1{##2{\SKV@expox\SKV@resvdb}}}%
+ \everyeof{\noexpand}\endlinechar\m@ne\makeatletter
+ \SKV@resvdb{\xdef\SKV@resvdb}{\scantokens\expandafter}%
+ \endgroup
+ \ifSKV@pl
+ \gl@l@x\SKV@aftercs\let\SKV@resvda\SKV@resvdb
+ \else
+ \gl@l@x\expandafter\let\SKV@resvda\SKV@resvdb
+ \fi
+ }%
+ \SKV@resstate
+}
+\SKV@def*\SKV@emptycmds{\SKV@savstate\SKV@testoptf\SKV@em@tycmds}
+\SKV@def\SKV@em@tycmds[#1]#2{%
+ \ifSKV@cl\let\gl@l@x\global\else\let\gl@l@x\relax\fi
+ \SKV@for[#1]{#2}\SKV@resvda{%
+ \ifSKV@pl
+ \SKV@expnext\SKV@ensurenoscape\SKV@resvda
+ \gl@l@x\SKV@aftercs\let\SKV@resvda\@empty
+ \else
+ \SKV@expnext\SKV@ensurescape\SKV@resvda
+ \gl@l@x\expandafter\let\SKV@resvda\@empty
+ \fi
+ }%
+ \SKV@resstate
+}
+\SKV@pdef*\SKV@csdef{\SKV@savstate\SKV@t@stoptb{\SKV@newcs\def}}
+\SKV@pdef*\SKV@csgdef{\SKV@savstate\SKV@t@stoptb{\SKV@newcs\gdef}}
+\SKV@pdef*\SKV@csedef{\SKV@savstate\SKV@t@stoptb{\SKV@newcs\edef}}
+\SKV@pdef*\SKV@csxdef{\SKV@savstate\SKV@t@stoptb{\SKV@newcs\xdef}}
+\SKV@def*\SKV@newcs#1#2{%
+ \ifSKV@st\let\l@ngrel@x\relax\else\let\l@ngrel@x\long\fi
+ \ifSKV@pl
+ \let\SKV@next\SKV@n@wcs
+ \else
+ \def\SKV@next{\l@ngrel@x\SKV@aftercs}%
+ \fi
+ \SKV@resstate\SKV@next#1{#2}%
+}
+\SKV@def*\SKV@n@wcs#1#2{%
+ \SKV@ifcsname{#2}%
+ {\SKV@csifx{#2}\relax{}{\def\resvd@a{#2}\SKV@notdefinable}}%
+ {\l@ngrel@x\SKV@aftercs{#1}{#2}}%
+}
+\SKV@def*\SKV@csuse#1{\SKV@ifcsname{#1}{\@nameuse{#1}}{}}
+\SKV@pdef\SKV@expargs#1#2#3#4\@nil{%
+ \begingroup
+ \protected@edef\SKV@tempa{\endgroup
+ \ifcase#1\relax
+ \unexpanded{#2}{#3}%
+ \or
+ \unexpanded{#2#3}{#4}%
+ \or
+ \unexpanded{#2}{#3}{#4}%
+ \or
+ \unexpanded{#2}#3\unexpanded{#4}%
+ \else
+ \SKV@err{Unknown expansion type '\string#1' for
+ \string\SKV@expargs}{I expected your first
+ argument '\string#1' to be between 0 and 3.}%
+ \fi
+ }%
+ \SKV@tempa
+}
+\SKV@def*\SKV@findescape#1{%
+ \begingroup\escapechar92\relax
+ \edef\resvd@a{\expandafter\SKV@car\string#1\@nil}%
+ \expandafter\aftergroup\csname SKV@%
+ \SKV@ifx\resvd@a\@backslashchar{1}{2}of2\endcsname
+ \endgroup
+}
+\SKV@def*\SKV@ensurescape#1{%
+ \SKV@findescape{#1}{}%
+ {\SKV@err{Backslash required in '\string#1'}%
+ {I expected a backslash to be the leading\SKV@MB
+ character in your argument '\string#1'.}}%
+}
+\SKV@def*\SKV@ensurenoscape#1{%
+ \SKV@findescape{#1}%
+ {\SKV@err{Backslash not allowed in '\string#1'}%
+ {I didn't expect a backslash to be the leading\SKV@MB
+ character in your argument '\string#1'.}}{}%
+}
+\SKV@pdef\SKV@ifnextchar#1#2#3{%
+ \let\SKV@nxc#1\def\SKV@nxa{#2}\def\SKV@nxb{#3}%
+ \futurelet\@temptoks\SKV@ifnextch@r
+}
+\SKV@def*\SKV@ifnextch@r{%
+ \ifx\@temptoks\SKV@nxc\let\SKV@nxb\SKV@nxa\fi\SKV@nxb
+}
+\SKV@pdef\SKV@ifchar#1#2#3{%
+ \SKV@ifnextchar#1{\begingroup
+ \def\SKV@tempa#1{\endgroup#2}\SKV@tempa}{#3}%
+}
+\SKV@pdef*\SKV@ifstar{\SKV@ifchar{*}}
+\SKV@pdef*\SKV@ifplus{\SKV@ifchar{+}}
+\SKV@pdef*\SKV@ifask{\SKV@ifchar{?}}
+\SKV@pdef*\SKV@ifclam{\SKV@ifchar{!}}
+\SKV@pdef*\SKV@ifright{\SKV@ifchar{>}}
+\SKV@pdef*\SKV@ifleft{\SKV@ifchar{<}}
+\SKV@pdef*\SKV@if@brack#1#2{\SKV@ifnextchar[{#1}{#2}}
+\SKV@pdef*\SKV@if@paren#1#2{\SKV@ifnextchar({#1}{#2}}
+\SKV@pdef*\SKV@if@left#1#2{\SKV@ifnextchar<{#1}{#2}}
+\SKV@pdef*\SKV@testopt#1#2{\SKV@if@brack{#1}{#1[{#2}]}}
+\SKV@pdef*\SKV@testopta#1{\SKV@t@stopta{\SKV@t@st@pta{#1}}}
+\SKV@pdef*\SKV@t@stopta#1{\SKV@ifstar{\SKV@sttrue#1}{\SKV@stfalse#1}}
+\SKV@pdef*\SKV@t@st@pta#1{\SKV@ifplus{\SKV@pltrue#1}{\SKV@plfalse#1}}
+\SKV@pdef*\SKV@t@st@p@a#1{\SKV@ifclam{\SKV@cltrue#1}{\SKV@clfalse#1}}
+\SKV@pdef*\SKV@testoptb#1{\SKV@t@stopta{\SKV@t@st@pta{\SKV@t@st@p@a{#1}}}}
+\SKV@pdef*\SKV@t@stoptb#1{\SKV@t@stopta{\SKV@t@st@pta{#1}}}
+\SKV@pdef*\SKV@testoptc#1{\SKV@t@st@pta{\SKV@t@st@p@a{#1}}}
+\SKV@pdef*\SKV@testoptd#1{\SKV@t@stopta{\SKV@testopt#1{,}}}
+\SKV@pdef*\SKV@testopte#1{\SKV@testoptb{\SKV@testopt#1{,}}}
+\SKV@pdef*\SKV@t@stopte#1{\SKV@t@stoptb{\SKV@testopt#1{,}}}
+\SKV@pdef*\SKV@testoptf#1{\SKV@testoptc{\SKV@testopt#1{,}}}
+\SKV@pdef*\SKV@testoptg#1{\SKV@ifright{\SKV@rttrue#1}{\SKV@rtfalse#1}}
+\SKV@pdef*\SKV@t@stoptg#1{\SKV@ifleft{\SKV@lttrue#1}{\SKV@ltfalse#1}}
+\SKV@pdef*\SKV@testopth#1#2{\SKV@if@left{#1}{#1<{#2}>}}
+\SKV@pdef*\SKV@testoptp#1#2{\SKV@if@paren{#1}{#1({#2})}}
+\SKV@def*\SKV@Test@pt#1{\@nameuse{SKV@\SKV@ifempty{#1}{1}{2}of2}}
+\SKV@def*\SKV@IfBrack#1#2#3{\SKV@IfBr@ck#1&[&{#2}{#3{#1}}}
+\SKV@def*\SKV@IfBr@ck#1[#2&#3#{\SKV@Test@pt{#1#2}}
+\SKV@def*\SKV@TestOpt#1#2#3{\SKV@IfBr@ck#1&[&{#2#1}{#2[{#3}]{#1}}}
+\SKV@def*\SKV@IfStar#1#2#3{\SKV@IfSt@r#1&*&{#2}{#3{#1}}}
+\SKV@def*\SKV@IfSt@r#1*#2&#3#{\SKV@Test@pt{#1#2}}
+\SKV@def*\SKV@IfPlus#1#2#3{\SKV@IfPl@s#1&+&{#2}{#3{#1}}}
+\SKV@def*\SKV@IfPl@s#1+#2&#3#{\SKV@Test@pt{#1#2}}
+\SKV@def*\SKV@IfAsk#1#2#3{\SKV@IfA@k#1&?&{#2}{#3{#1}}}
+\SKV@def*\SKV@IfA@k#1?#2&#3#{\SKV@Test@pt{#1#2}}
+\SKV@def*\SKV@csalloc#1{\@nameuse{new#1\SKV@aftercs}}
+\SKV@pdef*\csnewif{\SKV@csalloc{if}}
+\SKV@pdef*\csnewtoks{\SKV@csalloc{toks}}
+\SKV@pdef*\csnewcount{\SKV@csalloc{count}}
+\SKV@pdef*\csnewdimen{\SKV@csalloc{dimen}}
+\SKV@pdef*\csnewbox{\SKV@csalloc{box}}
+\SKV@pdef*\csnewwrite{\SKV@csalloc{write}}
+\SKV@pdef*\csnewread{\SKV@csalloc{read}}
+\SKV@pdef*\NewWrites{\SKV@swtrue\SKV@testopt\SKV@NewWrites{}}
+\SKV@pdef*\DefWrites{\SKV@swfalse\SKV@testopt\SKV@NewWrites{}}
+\SKV@def*\SKV@NewWrites[#1]#2{%
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \ifSKV@sw
+ \SKV@csifdefinable{#1\SKV@tempa}\relax
+ \else
+ \SKV@ifcsundef{#1\SKV@tempa}{}{%
+ \SKV@vbmsg{warn}{Write stream '\@backslashchar
+ #1\SKV@tempa' redefined\on@line}%
+ }%
+ \fi
+ \csnewwrite{#1\SKV@tempa}%
+ }%
+}
+\SKV@pdef*\NewReads{\SKV@swtrue\SKV@testopt\SKV@NewReads{}}
+\SKV@pdef*\DefReads{\SKV@swfalse\SKV@testopt\SKV@NewReads{}}
+\SKV@def*\SKV@NewReads[#1]#2{%
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \ifSKV@sw
+ \SKV@csifdefinable{#1\SKV@tempa}\relax
+ \else
+ \SKV@ifcsundef{#1\SKV@tempa}{}{%
+ \SKV@vbmsg{warn}{Read stream '\@backslashchar
+ #1\SKV@tempa' redefined\on@line}%
+ }%
+ \fi
+ \csnewread{#1\SKV@tempa}%
+ }%
+}
+\SKV@pdef*\NewIfs{\SKV@swtrue\SKV@testopt\SKV@NewIfs{}}
+\SKV@pdef*\DefIfs{\SKV@swfalse\SKV@testopt\SKV@NewIfs{}}
+\SKV@def*\SKV@NewIfs[#1]#2{\SKV@testopt{\SKV@N@wIfs[#1]{#2}}{false}}
+\SKV@def*\SKV@N@wIfs[#1]#2[#3]{%
+ \ifSKV@sw
+ \SKV@getswstate\NewIfs{#3}%
+ \else
+ \SKV@getswstate\DefIfs{#3}%
+ \fi
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \begingroup
+ \SKV@oifstrequal{\SKV@tempa}{x}{\SKV@swnameerr{x}}%
+ {\SKV@oifstrequal{\SKV@tempa}{on}{\SKV@swnameerr{on}}%
+ {\SKV@oifstrequal{\SKV@tempa}{off}{\SKV@swnameerr{off}}%
+ {\SKV@oifstrequal{\SKV@tempa}{tog}{\SKV@swnameerr{tog}}%
+ {\SKV@oifstrequal{\SKV@tempa}{switch}{\SKV@swnameerr{switch}}%
+ {}}}}}\endgroup
+ \ifSKV@sw
+ \SKV@csifdefinable{if#1\SKV@tempa}\relax
+ \else
+ \SKV@ifcsundef{if#1\SKV@tempa}{}{%
+ \SKV@vbmsg{warn}{Boolean '\@backslashchar
+ if#1\SKV@tempa' redefined\on@line}%
+ }%
+ \fi
+ \SKV@aftercs\SKV@N@wIf@{if#1\SKV@tempa}%
+ \@nameuse{#1\SKV@tempa\SKV@swval}%
+ }%
+}
+\SKV@def*\SKV@N@wIf@#1{%
+ \@tempcnta\escapechar\escapechar\m@ne
+ \let#1\iffalse
+ \SKV@If#1\iftrue
+ \SKV@If#1\iffalse
+ \let\ifon\iftrue
+ \let\ifoff\iffalse
+ \SKV@If#1\ifon
+ \SKV@If#1\ifoff
+ \escapechar\@tempcnta
+}
+\def\SKV@If#1#2{%
+ \SKV@aftercs\def{\expandafter\@gobbletwo\string#1%
+ \expandafter\@gobbletwo\string#2}{\let#1#2}%
+}
+\SKV@pdef*\NewBooleans{\SKV@swtrue\SKV@testopt\SKV@NewBooleans{}}
+\SKV@pdef*\DefBooleans{\SKV@swfalse\SKV@testopt\SKV@NewBooleans{}}
+\SKV@def*\SKV@NewBooleans[#1]#2{%
+ \SKV@testopt{\SKV@B@oleans[#1]{#2}}{false}}
+\SKV@def*\SKV@B@oleans[#1]#2[#3]{%
+ \ifSKV@sw
+ \SKV@getswstate\NewBooleans{#3}%
+ \else
+ \SKV@getswstate\DefBooleans{#3}%
+ \fi
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \SKV@oifstrequal{\SKV@tempa}{tog}{%
+ \SKV@err{'tog' not allowed as a boolean name}\@ehc
+ }{%
+ \SKV@oifstrequal{\SKV@tempa}{switch}{%
+ \SKV@err{'switch' not allowed as a boolean name}\@ehc
+ }{}%
+ }%
+ \SKV@ifstrnotequal{#1\SKV@tempa}{x}{}{%
+ \SKV@err{'\string\ifx' is a TeX primitive}%
+ {Why do you want to redefine '\string\ifx'? This is dangerous.}%
+ }%
+ \ifSKV@sw
+ \SKV@csifdefinable{if#1\SKV@tempa}\relax
+ \else
+ \SKV@ifcsundef{if#1\SKV@tempa}{}{%
+ \SKV@vbmsg{warn}{Switch '\@backslashchar if#1\SKV@tempa'
+ redefined\on@line}%
+ }%
+ \fi
+ \csnewif{if#1\SKV@tempa}%
+ \@nameuse{#1\SKV@tempa\SKV@swval}%
+ }%
+}
+\SKV@pdef*\NewTogs{\SKV@swtrue\SKV@testopt\SKV@NewTogs{}}
+\SKV@pdef*\DefTogs{\SKV@swfalse\SKV@testopt\SKV@NewTogs{}}
+\SKV@def*\SKV@NewTogs[#1]#2{\SKV@testopt{\SKV@NewT@gs[#1]{#2}}{false}}
+\SKV@def*\SKV@NewT@gs[#1]#2[#3]{%
+ \ifSKV@sw
+ \SKV@getswstate\NewTogs{#3}%
+ \else
+ \SKV@getswstate\DefTogs{#3}%
+ \fi
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \edef\SKV@tempa{#1\SKV@tempa}%
+ \ifSKV@sw
+ \SKV@expnext\newtog\SKV@tempa
+ \else
+ \SKV@expnext\deftog\SKV@tempa
+ \fi
+ \SKV@expargs{0}{\@nameuse{tog\SKV@swval}}\SKV@tempa\@nil
+ }%
+}
+\SKV@pdef*\NewToks{\SKV@swtrue\SKV@testopt\SKV@NewToks{}}
+\SKV@pdef*\DefToks{\SKV@swfalse\SKV@testopt\SKV@NewToks{}}
+\SKV@def*\SKV@NewToks[#1]#2{%
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \ifSKV@sw
+ \SKV@csifdefinable{#1\SKV@tempa}\relax
+ \else
+ \SKV@ifcsundef{#1\SKV@tempa}{}{%
+ \SKV@vbmsg{warn}{Token register '\@backslashchar
+ #1\SKV@tempa' redefined\on@line}%
+ }%
+ \fi
+ \csnewtoks{#1\SKV@tempa}%
+ }%
+}
+\SKV@pdef*\NewCounts{\SKV@swtrue\SKV@testopt\SKV@NewCounts{}}
+\SKV@pdef*\DefCounts{\SKV@swfalse\SKV@testopt\SKV@NewCounts{}}
+\SKV@def*\SKV@NewCounts[#1]#2{%
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \ifSKV@sw
+ \SKV@csifdefinable{#1\SKV@tempa}\relax
+ \else
+ \SKV@ifcsundef{#1\SKV@tempa}{}{%
+ \SKV@vbmsg{warn}{Counter register '\@backslashchar
+ #1\SKV@tempa' redefined\on@line}%
+ }%
+ \fi
+ \csnewcount{#1\SKV@tempa}%
+ }%
+}
+\SKV@pdef*\NewDimens{\SKV@swtrue\SKV@testopt\SKV@NewDimens{}}
+\SKV@pdef*\DefDimens{\SKV@swfalse\SKV@testopt\SKV@NewDimens{}}
+\SKV@def*\SKV@NewDimens[#1]#2{%
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \ifSKV@sw
+ \SKV@csifdefinable{#1\SKV@tempa}\relax
+ \else
+ \SKV@ifcsundef{#1\SKV@tempa}{}{%
+ \SKV@vbmsg{warn}{Dimension register '\@backslashchar
+ #1\SKV@tempa' redefined\on@line}%
+ }%
+ \fi
+ \csnewdimen{#1\SKV@tempa}%
+ }%
+}
+\SKV@pdef*\NewBoxes{\SKV@swtrue\SKV@testopt\SKV@NewBoxes{}}
+\SKV@pdef*\DefBoxes{\SKV@swfalse\SKV@testopt\SKV@NewBoxes{}}
+\SKV@def*\SKV@NewBoxes[#1]#2{%
+ \SKV@for[,]{#2}\SKV@tempa{%
+ \SKV@expnext\SKV@ensurenoscape\SKV@tempa
+ \ifSKV@sw
+ \SKV@csifdefinable{#1\SKV@tempa}\relax
+ \else
+ \SKV@ifcsundef{#1\SKV@tempa}{}{%
+ \SKV@vbmsg{warn}{Box register '\@backslashchar
+ #1\SKV@tempa' redefined\on@line}%
+ }%
+ \fi
+ \csnewbox{#1\SKV@tempa}%
+ }%
+}
+\SKV@def\SKV@expnext#1#2{%
+ \SKV@ifblank{#1}{%
+ \SKV@badargerr{SKV@expnext}{first}%
+ }{%
+ \SKV@ifblank{#2}{%
+ \SKV@badargerr{SKV@expnext}{second}%
+ }{%
+ \ifcat$\detokenize\expandafter{\SKV@cdr#1\@nil}$%
+ \SKV@afterelsefi
+ \expandafter#1\expandafter{#2}%
+ \else
+ \SKV@afterfi
+ \SKV@badargerr{SKV@expnext}{first}%
+ \fi
+ }%
+ }%
+}
+\SKV@pdef*\SKV@ifnewcmd{\SKV@savstate\SKV@t@stopte\SKV@ifn@wcmd}
+\SKV@def*\SKV@ifn@wcmd[#1]#2{%
+ \ifSKV@st
+ \ifSKV@pl
+ \def\SKV@ndl{\SKV@for*[#1]#2}%
+ \else
+ \def\SKV@ndl{\SKV@tfor*#2}%
+ \fi
+ \else
+ \ifSKV@pl
+ \def\SKV@ndl{\SKV@for[#1]{#2}}%
+ \else
+ \def\SKV@ndl{\SKV@tfor{#2}}%
+ \fi
+ \fi
+ \SKV@ndl\SKV@ndl{%
+ \ifSKV@pl
+ \SKV@despacectt\SKV@ndl
+ \SKV@csifdefinable\SKV@ndl\relax
+ \else
+ \expandafter\SKV@ifdefinable\SKV@ndl\relax
+ \fi
+ }%
+ \SKV@resstate
+}
+\let\SKV@no\z@
+\SKV@pdef*\SKV@aftergroup{%
+ \SKV@ifstar{\SKV@aft@rgroup\@firstofone}%
+ {\SKV@aft@rgroup\unexpanded}%
+}
+\SKV@def\SKV@aft@rgroup#1#2{%
+ \edef\SKV@no{\the\numexpr\SKV@no+1}%
+ \SKV@aftercs\xdef{SKV@aft@rgr@up\SKV@no}{%
+ \SKV@csgundef{SKV@aft@rgr@up\SKV@no}%
+ #1{#2}%
+ }%
+ \SKV@aftercs\aftergroup{SKV@aft@rgr@up\SKV@no}%
+}
+\SKV@pdef*\SKV@afterassignment{%
+ \SKV@ifstar{\SKV@aft@rassignment\@firstofone}%
+ {\SKV@aft@rassignment\unexpanded}%
+}
+\SKV@def\SKV@aft@rassignment#1#2{%
+ \begingroup
+ \edef\SKV@no{\the\numexpr\SKV@no+1}%
+ \SKV@aftercs\xdef{SKV@aft@rassignm@nt\SKV@no}{%
+ \SKV@csgundef{SKV@aft@rassignm@nt\SKV@no}%
+ #1{#2}%
+ }%
+ \expandafter\endgroup\expandafter\afterassignment
+ \csname SKV@aft@rassignm@nt\SKV@no\endcsname
+}
+\SKV@def*\SKV@sp@def#1#2{%
+ \edef\@sp@def{\the\SKV@toks}%
+ \SKV@toks\expandafter{%
+ \romannumeral-`\q\SKV@sp@d@f\noexpand\noexpand#1& &}%
+ \edef#2{\the\SKV@toks}%
+ \SKV@toks\expandafter{\@sp@def}%
+ \SKV@undef\@sp@def
+}
+\SKV@def*\SKV@sp@d@f#1 &{\SKV@sp@d@f@#1&}
+\SKV@def*\SKV@sp@d@f@#1&#2{\romannumeral-`\q#1}
+\SKV@def*\SKV@expox#1{\unexpanded\expandafter{#1}}
+\SKV@def*\SKV@csexpox#1{\SKV@aftercs\SKV@expox{#1}}
+\SKV@def*\SKV@exptx#1{\unexpanded\SKV@threexp{#1}}
+\SKV@def*\SKV@csexptx#1{\SKV@aftercs\SKV@exptx{#1}}
+\SKV@def\SKV@noexpcs#1{\unexpanded\expandafter{\csname#1\endcsname}}
+\SKV@pdef*\SKV@undef#1{\let#1\SKV@undefined}
+\SKV@pdef*\SKV@gundef{\global\SKV@undef}
+\SKV@pdef*\SKV@csundef#1{\SKV@aftercs\SKV@undef{#1}}
+\SKV@pdef*\SKV@csgundef{\global\SKV@csundef}
+\SKV@def*\SKV@undeflist{\SKV@savstate\SKV@t@st@p@a\SKV@und@flist}
+\SKV@def*\SKV@und@flist#1{%
+ \ifSKV@cl\let\gl@l@x\global\else\let\gl@l@x\relax\fi
+ \XKV@for@n{#1}\SKV@resvd{%
+ \SKV@expnext\SKV@ensurescape\SKV@resvd
+ \gl@l@x\expandafter\SKV@undef\SKV@resvd
+ }%
+ \SKV@resstate
+}
+\SKV@pdef*\SKV@Undef{\SKV@savstate\SKV@testopte\SKV@Und@f}
+\SKV@def*\SKV@Und@f[#1]#2{%
+ \ifSKV@st
+ \ifSKV@pl
+ \def\SKV@ndl{\SKV@for*[#1]#2}%
+ \else
+ \def\SKV@ndl{\SKV@tfor*#2}%
+ \fi
+ \else
+ \ifSKV@pl
+ \def\SKV@ndl{\SKV@for[#1]{#2}}%
+ \else
+ \def\SKV@ndl{\SKV@tfor{#2}}%
+ \fi
+ \fi
+ \SKV@ndl\SKV@ndl{%
+ \ifSKV@pl
+ \SKV@despacectt\SKV@ndl
+ \ifSKV@cl\expandafter\global\fi
+ \SKV@threexp\let
+ \expandafter\csname\SKV@ndl\endcsname\SKV@undefined
+ \else
+ \ifSKV@cl\expandafter\global\fi
+ \expandafter\let\SKV@ndl\SKV@undefined
+ \fi
+ }%
+ \SKV@resstate
+}
+\SKV@def*\SKV@ifdef#1{%
+ \SKV@ifdefined{#1}%
+ {\@nameuse{SKV@\SKV@ifx{#1}\relax{2}{1}of2}}\@secondoftwo
+}
+\SKV@def*\SKV@ifundef#1{\@nameuse{SKV@\SKV@ifdef{#1}{2}{1}of2}}
+\SKV@def*\SKV@ifcsdef#1{%
+ \SKV@ifcsname{#1}%
+ {\@nameuse{SKV@\expandafter\SKV@ifx\csname#1\endcsname
+ \relax{2}{1}of2}}\@secondoftwo
+}
+\SKV@def*\SKV@ifcsundef#1{\@nameuse{SKV@\SKV@ifcsdef{#1}{2}{1}of2}}
+\SKV@def*\SKV@ifonedef#1{%
+ \def\SKV@resvda{#1}\SKV@swtrue
+ \XKV@whilist\SKV@resvda\SKV@resvdb\ifSKV@sw\fi{%
+ \SKV@oifdefined\SKV@resvdb\SKV@swfalse\SKV@swtrue
+ }%
+ \@nameuse{SKV@\ifSKV@sw2\else1\fi of2}%
+}
+\SKV@def\DeclarePackageCommand#1#2{%
+ \SKV@ensurescape{#2}%
+ \SKV@ifdef#2{%
+ \edef\resvd@a{\expandafter\@gobble\string#2}%
+ \SKV@cslet{Saved\resvd@a}#2%
+ \edef\resvd@a##1{\SKV@AtEndAfterPackageEnd%
+ {##1Saved\resvd@a\noexpand\endcsname}}%
+ \resvd@a{\expandafter\let\expandafter#2\csname}%
+ \SKV@undef\resvd@a
+ }{\SKV@AtEndAfterPackageEnd{\SKV@Undef!#2}}%
+ #1#2%
+}
+\SKV@pdef*\SKV@providedef{\@star@or@long{\SKV@pr@videdef{}}}
+\SKV@pdef*\SKV@providerobustdef{\@star@or@long{\SKV@pr@videdef\protected}}
+\SKV@def\SKV@pr@videdef#1#2{%
+ \SKV@ensurescape{#2}%
+ \edef\SKV@prov@d{\expandafter\@gobble\string#2}%
+ \SKV@aftercs\let{SKV@test@\SKV@prov@d}\SKV@undefined
+ \SKV@ifdef#2{%
+ \SKV@vbmsg{info}{Command '\string#2' already defined:\SKV@MB
+ Not redefined\on@line}%
+ \SKV@afterassignment{\SKV@gundef\SKV@pr@vid}%
+ \def\SKV@pr@vid
+ }{%
+ \SKV@afterassignment{%
+ \SKV@aftercs\edef{SKV@test@\SKV@prov@d}%
+ {\expandafter\strip@prefix\meaning#2}%
+ }%
+ \l@ngrel@x#1\def#2%
+ }%
+}
+\SKV@def\TestProvidedCommand#1{%
+ \SKV@ensurescape{#1}%
+ \begingroup
+ \SKV@ifmacro#1{%
+ \edef\SKV@resvda{\expandafter\@gobble\string#1}%
+ \edef\SKV@resvdb{\expandafter\strip@prefix\meaning#1}%
+ \expandafter\aftergroup\csname SKV@\expandafter
+ \ifx\expandafter\SKV@resvdb
+ \csname SKV@test@\SKV@resvda\endcsname
+ 1\else2\fi of2\endcsname
+ }{\aftergroup\@secondoftwo}%
+ \endgroup
+}
+\SKV@pdef*\SKV@newdef{\SKV@def}
+\SKV@providerobustdef*\newdef{\SKV@def}
+\SKV@providerobustdef*\redef{\SKV@redef}
+\SKV@pdef*\SKV@robustdef{\SKV@pdef}
+\SKV@providerobustdef*\robustdef{\SKV@pdef}
+\SKV@providerobustdef*\robustredef{\SKV@predef}
+\SKV@providerobustdef*\providedef{\SKV@providedef}
+\SKV@providerobustdef*\providerobustdef{\SKV@providerobustdef}
+\SKV@providerobustdef*\aftercommission{\SKV@afterassignment}
+\SKV@providerobustdef*\aftercoterie{\SKV@aftergroup}
+\SKV@def*\SKV@ifmacro#1{%
+ \begingroup
+ \edef\SKV@tempa##1{\def##1####1\detokenize{macro}:####2&}%
+ \SKV@tempa\SKV@tempa{\expandafter\aftergroup
+ \csname SKV@\SKV@ifblank{##2}{2}{1}of2\endcsname}%
+ \edef\SKV@tempb##1{##1\detokenize{macro}:&}%
+ \SKV@tempb{\expandafter\SKV@tempa\meaning#1}%
+ \endgroup
+}
+\SKV@def\SKV@csifmacro{\SKV@aftercs\SKV@ifmacro}
+\SKV@def\SKV@ifnotmacro#1{\SKV@ifmacro{#1}\@secondoftwo\@firstoftwo}
+\SKV@def*\SKV@simplecmdpatch{\begingroup\@makeother{\#}%
+ \SKV@testopt\SKV@simpl@cmdpatch{########1}}
+\SKV@def*\SKV@simpl@cmdpatch[#1]#2#3#4{%
+ \edef\SKV@resvda##1##2{%
+ \def##1####1\detokenize{macro:}####2->####3&{%
+ #1\def\string#2####2{##2####3&}%
+ }%
+ \def##2####1\detokenize{#3}####2&{####1\detokenize{#4}####2}%
+ \edef##1{##1\meaning#2&}%
+ }%
+ \SKV@resvda\SKV@resvda\SKV@resvdb
+ \everyeof{\noexpand}\endlinechar\m@ne\makeatletter
+ \catcode`\#=6\relax
+ \scantokens\expandafter{\SKV@resvda}%
+ \global\let#2#2%
+ \endgroup
+}
+\SKV@def*\SKV@ifrelax#1{%
+ \SKV@ensurescape{#1}%
+ \SKV@ifdefined{#1}%
+ {\@nameuse{SKV@\SKV@ifx{#1}\relax{1}{2}of2}}\@secondoftwo
+}
+\SKV@def*\SKV@ifcsrelax#1{%
+ \SKV@ensurenoscape{#1}%
+ \SKV@ifcsname{#1}%
+ {\@nameuse{SKV@\expandafter\SKV@ifx\csname#1\endcsname
+ \relax{1}{2}of2}}\@secondoftwo
+}
+\SKV@def*\SKV@ifdefax#1{%
+ \SKV@ensurescape{#1}%
+ \SKV@ifdefined{#1}%
+ {\@nameuse{SKV@\SKV@ifx{#1}\relax{2}{1}of3}}\@thirdofthree
+}
+\SKV@def*\SKV@ifcsdefax#1{%
+ \SKV@ensurenoscape{#1}%
+ \SKV@ifcsname{#1}%
+ {\@nameuse{SKV@\expandafter\SKV@ifx\csname#1\endcsname
+ \relax{2}{1}of3}}\@thirdofthree
+}
+\SKV@def*\SKV@despacectt#1{%
+ \SKV@ensurescape{#1}%
+ \SKV@expnext\SKV@sp@def{#1}#1%
+}
+\SKV@def\SKV@detokdespace#1{%
+ \edef#1{\detokenize\expandafter{#1}}%
+ \SKV@despacectt#1%
+}
+\SKV@def\SKV@ifblank#1{\SKV@ifbl@nk#1&&\@secondoftwo\@firstoftwo:}
+\SKV@def\SKV@ifbl@nk#1#2&#3#4#5:{#4}
+\SKV@def\SKV@ifnotblank#1{\SKV@ifbl@nk#1&&\@firstoftwo\@secondoftwo:}
+\SKV@def\SKV@oifblank#1{\expandafter\SKV@ifblank\expandafter{#1}}
+\SKV@def\SKV@xifblank#1{\SKV@expargs{0}\SKV@ifblank{#1}\@nil}
+\SKV@def\SKV@ifstrequal#1#2{%
+ \begingroup
+ \edef\resvd@a{\detokenize{#1}}%
+ \edef\resvd@b{\detokenize{#2}}%
+ \SKV@despacectt\resvd@a\SKV@despacectt\resvd@b
+ \expandafter\aftergroup
+ \csname SKV@\SKV@ifx\resvd@a\resvd@b{1}{2}of2\endcsname
+ \endgroup
+}
+\SKV@def\SKV@ifstrnotequal#1#2{%
+ \SKV@ifstrequal{#1}{#2}\@secondoftwo\@firstoftwo}
+\SKV@def\SKV@oifstrequal#1#2{%
+ \@expandtwoargs\SKV@ifstrequal{\SKV@expox{#1}}{\SKV@expox{#2}}}
+\SKV@def\SKV@xifstrequal#1#2{\@expandtwoargs\SKV@ifstrequal{#1}{#2}}
+\SKV@def\SKV@ifempty#1{\@nameuse{SKV@\ifcat$\detokenize{#1}$1\else2\fi of2}}
+\SKV@def\SKV@ifnotempty#1{\@nameuse{SKV@\SKV@ifempty{#1}{2}{1}of2}}
+\SKV@def\SKV@oifempty#1{\SKV@expnext\SKV@ifempty{#1}}
+\SKV@def\SKV@xifempty#1{\SKV@expargs{0}\SKV@ifempty{#1}\@nil}
+\SKV@def*\SKV@remparser{\SKV@testopt\SKV@remp@rser{,}}
+\SKV@def\SKV@remp@rser[#1]#2{%
+ \begingroup
+ \ifx#2\@empty\else
+ \edef#2{#1\SKV@expox{#2}}%
+ \def\SKV@tempa#1##1\@nil{%
+ \gdef#2{##1}\futurelet\@temptoks\SKV@t@mp##1\@nil
+ }%
+ \def\SKV@t@mp##1\@nil{%
+ \ifx\@temptoks\@sptoken
+ \SKV@expnext\SKV@sp@def{#2}#2%
+ \expandafter\SKV@tempa\expandafter#1#2\@nil
+ \else
+ \if#1\@temptoks\expandafter\SKV@tempa#2\@nil\fi
+ \fi
+ }%
+ \expandafter\SKV@tempa#2\@nil
+ \fi
+ \endgroup
+}
+\SKV@pdef*\SKV@appto{\SKV@savstate\SKV@testoptb{\SKV@hooktomac{>}}}
+\SKV@pdef*\SKV@prepto{\SKV@savstate\SKV@testoptb{\SKV@hooktomac{<}}}
+\SKV@def\SKV@hooktomac#1#2#3{%
+ \ifSKV@st\let\SKV@iii\SKV@expox\else\let\SKV@iii\unexpanded\fi
+ \ifSKV@pl
+ \let\@ifundef\SKV@ifcsundef\let\SKV@iv\SKV@csexpox
+ \def\SKV@i##1{\def\SKV@ii####1{\SKV@aftercs##1{####1}}}%
+ \ifSKV@cl\SKV@i\xdef\else\SKV@i\edef\fi
+ \else
+ \let\@ifundef\SKV@ifundef\let\SKV@iv\SKV@expox
+ \ifSKV@cl\def\SKV@ii##1{\xdef##1}\else
+ \def\SKV@ii##1{\edef##1}\fi
+ \fi
+ \@ifundef{#2}{%
+ \SKV@ii{#2}{\SKV@iii{#3}}%
+ }{%
+ \SKV@ifstrequal{#1}{>}%
+ {\SKV@ii{#2}{\SKV@iv{#2}\SKV@iii{#3}}}%
+ {\SKV@ii{#2}{\SKV@iii{#3}\SKV@iv{#2}}}%
+ }%
+ \SKV@resstate
+ \SKV@undeflist!{\SKV@i,\SKV@ii,\SKV@iii,\SKV@iv}%
+}
+\SKV@pdef\apptomac#1#2{%
+ \SKV@ifundef{#1}{\edef#1{\unexpanded{#2}}}%
+ {\edef#1{\SKV@expox{#1}\unexpanded{#2}}}%
+}
+\SKV@pdef*\gapptomac{\global\apptomac}
+\SKV@pdef*\csapptomac{\SKV@aftercs\apptomac}
+\SKV@pdef*\csgapptomac{\global\csapptomac}
+\SKV@pdef\preptomac#1#2{%
+ \SKV@ifundef{#1}{\edef#1{\unexpanded{#2}}}%
+ {\edef#1{\unexpanded{#2}\SKV@expox{#1}}}%
+}
+\SKV@pdef*\gpreptomac{\global\preptomac}
+\SKV@pdef*\cspreptomac{\SKV@aftercs\preptomac}
+\SKV@pdef*\csgpreptomac{\global\cspreptomac}
+\SKV@pdef*\SKV@addtolist{\SKV@savstate\SKV@testoptc{%
+ \SKV@t@stoptg{\SKV@testopt\SKV@addt@list{,}}}}
+\SKV@def*\SKV@addt@list[#1]{%
+ \def\parser{#1}%
+ \ifSKV@cl\let\glob@l@def\xdef\else\let\glob@l@def\edef\fi
+ \ifSKV@pl
+ \def\SKV@next##1{\SKV@aftercs\SKV@addt@l@st{##1}}%
+ \else
+ \let\SKV@next\SKV@addt@l@st
+ \fi
+ \SKV@next
+}
+\SKV@def\SKV@addt@l@st#1#2{%
+ \SKV@ifundef{#1}{%
+ \glob@l@def#1{\SKV@expox{#2}}%
+ }{%
+ \SKV@ifx#1\@empty{%
+ \glob@l@def#1{\SKV@expox{#2}}%
+ }{%
+ \ifSKV@lt
+ \glob@l@def#1{\SKV@expox{#2}\parser\SKV@expox{#1}}%
+ \else
+ \glob@l@def#1{\SKV@expox{#1}\parser\SKV@expox{#2}}%
+ \fi
+ }%
+ }%
+ \SKV@resstate
+}
+\SKV@pdef*\SKV@relax#1{\let#1\relax}
+\SKV@pdef*\SKV@grelax{\global\SKV@relax}
+\SKV@pdef*\SKV@csrelax{\SKV@aftercs\SKV@relax}
+\SKV@pdef*\SKV@csgrelax{\global\SKV@csrelax}
+\@ifpackageloaded{atveryend}{%
+ \@ifpackagecurrent{atveryend}{2010/03/24}{}{%
+ \SKV@err{Your loaded version of atveryend package is
+ not current}\@ehc}}{\RequirePackage{atveryend}[2010/03/24]}
+\SKV@pdef*\SKV@notprerr{%
+ \SKV@err{You have issued a preamble command here}%
+ {Move shown command to document preamble.}%
+}
+\SKV@pdef*\SKV@notenderr{%
+ \SKV@err{You've called an \string\enddocument\space command\SKV@MB
+ at the wrong place}{Move command to before \string\enddocument.}%
+}
+\SKV@pdef*\SKV@AtDocumentStart{\AtBeginDocument}
+\SKV@pdef*\SKV@BeforeDocumentStart{\SKV@appto!\SKV@beforedocstart}
+\def\SKV@beforedocstart{}
+\SKV@prepto\document{%
+ \endgroup
+ \let\SKV@BeforeDocumentStart\@firstofone
+ \SKV@beforedocstart
+ \let\SKV@BeforeDocumentStart\SKV@notprerr
+ \SKV@gundef\SKV@beforedocstart
+ \begingroup
+}
+\SKV@pdef*\SKV@AfterDocumentStart{\SKV@appto!\SKV@afterdocstart}
+\def\SKV@afterdocstart{}
+\SKV@appto\document{%
+ \let\SKV@AfterDocumentStart\@firstofone
+ \SKV@afterdocstart
+ \let\SKV@AfterDocumentStart\SKV@notprerr
+ \SKV@gundef\SKV@afterdocstart\ignorespaces
+}
+\SKV@BeforeDocumentStart{\let\SKV@AtDocumentStart\@firstofone}
+\SKV@pdef*\SKV@AtDocumentEnd{\AtEndDocument}
+\SKV@pdef*\SKV@BeforeLastPage{\SKV@appto!\SKV@beforelastpage}
+\def\SKV@beforelastpage{}
+\SKV@AtDocumentEnd{%
+ \let\SKV@bef@relastpage\AtVeryEnd@BeforeClearDocumentHook
+ \def\AtVeryEnd@BeforeClearDocumentHook{%
+ \let\SKV@BeforeLastPage\@firstofone
+ \SKV@beforelastpage\SKV@bef@relastpage
+ \let\SKV@BeforeLastPage\SKV@notenderr
+ \SKV@Undef!{\SKV@beforelastpage\SKV@bef@relastpage}%
+ }%
+}
+\SKV@pdef*\SKV@AfterLastPage{\SKV@appto!\SKV@afterlastpage}
+\def\SKV@afterlastpage{}
+\SKV@AtDocumentEnd{%
+ \let\SKV@afterl@stpage\AtVeryEnd@AfterLastShipoutHook
+ \def\AtVeryEnd@AfterLastShipoutHook{%
+ \let\SKV@AfterLastPage\@firstofone
+ \SKV@afterlastpage\SKV@afterl@stpage
+ \let\SKV@AfterLastPage\SKV@notenderr
+ \SKV@Undef!{\SKV@afterlastpage\SKV@afterl@stpage}%
+ }%
+}
+\SKV@pdef*\SKV@AfterDocumentEnd{\SKV@appto!\SKV@afterenddoc}
+\def\SKV@afterenddoc{}
+\SKV@AtDocumentEnd{%
+ \let\SKV@aft@renddoc\AtVeryEnd@AtVeryEndDocumentHook
+ \def\AtVeryEnd@AtVeryEndDocumentHook{%
+ \let\SKV@AfterDocumentEnd\@firstofone
+ \SKV@afterenddoc\SKV@aft@renddoc
+ \let\SKV@AfterDocumentEnd\SKV@notenderr
+ \SKV@Undef!{\SKV@afterenddoc\SKV@aft@renddoc}%
+ }%
+}
+\SKV@pdef\SKV@AtPackageEnd{\AtEndOfPackage}
+\SKV@pdef*\SKV@BeforePackageEnd{%
+ \SKV@prepto+{\@currname.\@currext-h@@k}%
+}
+\SKV@pdef*\SKV@AfterPackageEnd{%
+ \SKV@appto+{\@currname.\@currext-skvh@@k}%
+}
+\let\SKV@AtClassEnd\SKV@AtPackageEnd
+\let\SKV@BeforeClassEnd\SKV@BeforePackageEnd
+\let\SKV@AfterClassEnd\SKV@AfterPackageEnd
+\SKV@prepto\@popfilename{%
+ \SKV@csuse{\@currname.\@currext-skvh@@k}%
+ \SKV@csgundef{\@currname.\@currext-skvh@@k}%
+}
+\SKV@pdef\@afterpackageloaded#1{%
+ \SKV@AtDocumentStart{%
+ \SKV@ifcsdef{ver@#1.\@pkgextension}{}{%
+ \SKV@warn{Package '#1' was never loaded}%
+ }%
+ }
+ \SKV@ifcsdef{ver@#1.\@pkgextension}{%
+ \let\SKV@next\@firstofone
+ }{%
+ \def\SKV@next{\SKV@appto+{#1.\@pkgextension-skvh@@k}}%
+ }%
+ \SKV@next
+}
+\let\SKV@steno\z@
+\SKV@pdef*\SKV@for{\SKV@savstate\SKV@testoptd\SKV@f@r}
+\SKV@pdef*\SKV@f@r[#1]{%
+ \let\SKV@steno\@ne
+ \ifSKV@st
+ \def\SKV@next{\SKV@for@b[#1]}%
+ \else
+ \def\SKV@next{\SKV@CommandGenParser{#1}\SKV@for@a}%
+ \fi
+ \SKV@next
+}
+\SKV@pdef*\SKV@CommandGenParser#1{%
+ \def\parser{#1}%
+ \protected\long\def\SKV@for@a##1##2##3{%
+ \SKV@ifblank{##1}\SKV@fornoop\SKV@forloop
+ ##2{##3}##1#1\@nil
+ }%
+ \long\def\SKV@forloop##1##2##3#1##4\@nil{%
+ \edef##1{\unexpanded{##3}}%
+ \SKV@ifstrequal{##3}{\listbreak}{%
+ \SKV@keylistrema##4\@nil#1%
+ }{%
+ \SKV@ifblank{##4}{%
+ ##2\relax
+ \ifnum\SKV@steno=\@ne\expandafter\SKV@resstate\fi
+ \let\SKV@steno\z@
+ }{%
+ ##2\relax\SKV@forloop##1{##2}##4\@nil
+ }%
+ }%
+ }%
+ \long\def\SKV@fornoop##1\@nil{}%
+}
+\SKV@pdef*\SKV@for@b{\SKV@testopt\SKV@f@r@b{,}}
+\SKV@def\SKV@f@r@b[#1]#2{%
+ \SKV@CommandGenParser{#1}\SKV@expnext\SKV@for@a{#2}%
+}
+\SKV@pdef*\SKV@tfor{\SKV@ifstar\SKV@tfor@b\SKV@tfor@a}
+\SKV@pdef*\SKV@tfor@a#1#2#3{%
+ \SKV@ifblank{#1}{%
+ \SKV@vbmsg{warn}{Empty list for '\string\SKV@tfor@a'\on@line}%
+ }{%
+ \SKV@ifblank{#3}{%
+ \SKV@vbmsg{warn}%
+ {Empty function for '\string\SKV@tfor@a'\on@line}%
+ }{%
+ \SKV@tforloop#1\@nil\@nil&#2{#3}%
+ }%
+ }%
+}
+\SKV@def\SKV@tforloop#1#2&#3#4{%
+ \long\def#3{#1}%
+ \SKV@ifstrequal{#1}{\listbreak}{%
+ \let\SKV@next\SKV@tforrema
+ }{%
+ \SKV@ifstrequal{#1}{\@nil}{%
+ \let\SKV@next\SKV@tfornoop
+ }{%
+ #4\relax\let\SKV@next\SKV@tforloop
+ }%
+ }%
+ \SKV@next#2&#3{#4}%
+}
+\SKV@def\SKV@tfornoop#1&#2#3{}
+\SKV@pdef*\SKV@tforrema#1\@nil\@nil&#2#3{%
+ \long\edef\SKV@remainder{\unexpanded{#1}}%
+}
+\SKV@pdef*\SKV@tfor@b#1#2#3{\SKV@expnext\SKV@tfor@a{#1}#2{#3}}
+\SKV@def*\SKV@preamblecmds{}
+\SKV@pdef*\SKV@onlypreamble{\SKV@savstate\SKV@t@st@pta\SKV@onlypre@mble}
+\SKV@pdef*\SKV@onlypre@mble#1{%
+ \SKV@for[,]{#1}\SKV@resvd{%
+ \SKV@despacectt\SKV@resvd
+ \ifSKV@pl
+ \SKV@expnext\SKV@ensurenoscape\SKV@resvd
+ \edef\SKV@resvd##1##2{\SKV@appto!##1{##2\SKV@noexpcs{\SKV@resvd}}}%
+ \else
+ \SKV@expnext\SKV@ensurescape\SKV@resvd
+ \edef\SKV@resvd##1##2{\SKV@appto!##1{##2\SKV@expox{\SKV@resvd}}}%
+ \fi
+ \SKV@resvd\SKV@preamblecmds\SKV@dopreamble
+ }%
+ \SKV@resstate
+}
+\SKV@AfterDocumentStart{%
+ \gdef\SKV@dopreamble#1{%
+ \gdef#1{\SKV@err{'\string#1' is a preamble command}%
+ {Move command '\string#1' to document preamble.}}%
+ }%
+ \SKV@preamblecmds
+ \global\let\SKV@dopreamble\@gobble
+}
+\SKV@pdef*\SKV@onlypackage{%
+ \SKV@xifempty{\@currname\@currext}{%
+ \SKV@err{Not in package environment}%
+ {The command at top level of this message\SKV@MB
+ is available only in package environment.}%
+ }{}%
+}
+\def\SKV@aftergroupdef#1#2{%
+ \expandafter\endgroup\expandafter\def\expandafter#1%
+ \expandafter{#2}%
+}
+\SKV@def*\SKV@noexpparse#1{%
+ \begingroup
+ \def\SKV@resa{}%
+ \edef\SKV@tempa{\detokenize\expandafter{#1}\@backslashchar&}%
+ \edef\SKV@tempb##1{\def##1####1\@backslashchar####2&}%
+ \SKV@tempb\SKV@tempb{%
+ \SKV@ifempty{##2}{%
+ \edef\SKV@resa{\SKV@expox\SKV@resa##1}%
+ }{%
+ \edef\SKV@resa{\SKV@expox\SKV@resa##1%
+ \string\noexpand\@backslashchar}%
+ \SKV@tempb##2&%
+ }%
+ }%
+ \expandafter\SKV@tempb\SKV@tempa
+ \expandafter\endgroup\expandafter\toks@\expandafter{\SKV@resa}%
+ \edef#1{\the\toks@}%
+}
+\SKV@def*\SKV@CommandKeyParser#1{%
+ \long\def\SKV@d@fine@keylist##1{%
+ \global\let\ifSKV@st\ifSKV@st
+ \endgroup
+ \SKV@undeflist!{\skif,\skifx,\skifcase,\skor,\skelse,\skfi}%
+ \ifSKV@st
+ \edef\@keylist{\detokenize\expandafter{##1}}%
+ \else
+ \edef\@keylist{\detokenize{##1}}%
+ \fi
+ \SKV@scantoksa\@keylist
+ \SKV@resstate
+ \SKV@expnext\SKV@checksanitizec\@keylist\SKV@tempa
+ \expandafter\SKV@readkeylist\SKV@tempa#1\@nil
+ }%
+ \long\def\SKV@readkeylist##1#1##2\@nil{%
+ \SKV@ifblank{##1}{}%
+ {%
+ \SKV@ifstrequal{##1}{\listbreak}{%
+ \SKV@keylistrema##2\@nil#1%
+ }{%
+ \SKV@define@multkeys##1\@nil
+ \SKV@ifblank{##2}\relax{\SKV@readkeylist##2\@nil}%
+ }%
+ }%
+ }%
+}
+\SKV@def*\SKV@checksanitizec#1#2{%
+ \XKV@ch@cksanitize{#1}#2;%
+ \ifin@\else\XKV@ch@cksanitize{#1}#2,\fi
+ \ifin@\@selective@sanitize[0]{,;}#2\fi
+}
+\SKV@pdef\SKV@checkchoice#1#2#3#4{%
+ \XKV@savstate\XKV@sttrue\XKV@pltrue
+ \SKV@expargs{3}{\XKV@checkchoice[\val\nr]}{{#1}{#2}}{{#3}{#4}}\@nil
+ \XKV@resstate
+}
+\SKV@simplecmdpatch\XKV@ch@ckch@ice{%
+ \XKV@err{value `\the\XKV@toks' is not allowed}%
+}{%
+ \SKV@err{Value '\the\XKV@toks' is not allowed}%
+ {You have submitted an invalid value for a key.\SKV@MB
+ You may proceed if you like but expect funny results.}%
+}
+\SKV@simplecmdpatch\XKV@@ch@ckchoice{%
+ \XKV@err{value `\the\XKV@toks' is not allowed}%
+}{%
+ \SKV@err{Value '\the\XKV@toks' is not allowed}%
+ {You have submitted an invalid value for a key.\SKV@MB
+ You may proceed if you like but expect funny results.}%
+}
+\SKV@pdef*\SKV@inputerr#1#2{%
+ \SKV@err{Erroneous value '#1' for key '#2'}%
+ {Please use the correct value for key '#2'\SKV@MB
+ of families '\XKV@fams'.}%
+}
+\SKV@def*\SKV@despacelist{\SKV@savstate\SKV@testoptd\SKV@desp@celist}
+\SKV@def*\SKV@desp@celist[#1]#2{%
+ \begingroup
+ \let\SKV@resa\@empty
+ \ifSKV@st
+ \def\SKV@dsl{\SKV@for*[#1]#2}%
+ \else
+ \def\SKV@dsl{\SKV@for[#1]{#2}}%
+ \fi
+ \SKV@dsl\SKV@dsl{%
+ \SKV@despacectt\SKV@dsl
+ \SKV@appto*\SKV@resa{\expandafter#1\SKV@dsl}%
+ }%
+ \ifx\SKV@resa\@empty\else\SKV@remparser[#1]\SKV@resa\fi
+ \ifSKV@st\global\let#2\SKV@resa\fi
+ \endgroup
+ \SKV@resstate
+}
+\SKV@def*\SKV@tdespacelt#1{%
+ \SKV@tfor{#1}\SKV@dsl{\expandafter\SKV@despacectt\SKV@dsl}%
+}
+\SKV@pdef*\ReserveKeyPrefixNames{\SKV@ifstar\SKV@rkpn@m@s\SKV@rkpn@mes}
+\SKV@def*\SKV@rkpn@mes#1{\SKV@appto!\SKV@rkpnames{,#1}}
+\SKV@def*\SKV@rkpn@m@s#1{\SKV@AfterPackageEnd{\SKV@appto!\SKV@rkpnames{,#1}}}
+\SKV@pdef*\ReserveMacroPrefixNames{\SKV@ifstar\SKV@rmpn@m@s\SKV@rmpn@mes}
+\SKV@def*\SKV@rmpn@mes#1{\SKV@appto!\SKV@rmpnames{,#1}}
+\SKV@def*\SKV@rmpn@m@s#1{\SKV@AfterPackageEnd{\SKV@appto!\SKV@rmpnames{,#1}}}
+\SKV@pdef*\ReserveFamilyNames{\SKV@ifstar\SKV@rfn@m@s\SKV@rfn@mes}
+\SKV@def*\SKV@rfn@mes#1{\SKV@appto!\SKV@rfnames{,#1}}
+\SKV@def*\SKV@rfn@m@s#1{\SKV@AfterPackageEnd{\SKV@appto!\SKV@rfnames{,#1}}}
+\SKV@def*\SKV@rkpnames{XKV}
+\SKV@def*\SKV@rmpnames{XKV}
+\SKV@def*\SKV@rfnames{XKV}
+\ReserveKeyPrefixNames*{SKV}
+\ReserveMacroPrefixNames*{SKV}
+\ReserveFamilyNames*{skeyval}
+\SKV@def*\SKV@newlet{\SKV@savstate\SKV@t@stopta\SKV@n@wlet}
+\SKV@def*\SKV@n@wlet#1#2{%
+ \SKV@ifdef#1{%
+ \ifSKV@st
+ \SKV@ifdef#2{%
+ \let#1#2%
+ \SKV@vbmsg{info}{Command '\string#1' redefined\on@line}%
+ }{%
+ \SKV@err{Command '\string#2' undefined}%
+ {I can't let '\string#1' to '\string#2'.}%
+ }%
+ \else
+ \SKV@err{Command '\string#1' already defined}%
+ {I can't let '\string#1' to '\string#2'.}%
+ \fi
+ }{%
+ \SKV@ifdef#2{\let#1#2}{%
+ \SKV@err{Command '\string#2' undefined}%
+ {I can't let '\string#1' to '\string#2'.}%
+ }%
+ }%
+ \SKV@resstate
+}
+\AtEndOfPackage{\SKV@providedef*\NewLet{\SKV@newlet}}
+\SKV@pdef*\SKV@cslet{\SKV@savstate\SKV@t@stopta\SKV@csl@t}
+\SKV@def*\SKV@csl@t#1#2{%
+ \ifSKV@st
+ \def\SKV@next{\SKV@aftercs\let{#1}#2}%
+ \else
+ \def\SKV@next{%
+ \SKV@ifdef{#2}{%
+ \SKV@aftercs\let{#1}#2%
+ }{%
+ \SKV@err{Command '\string#2' undefined}%
+ {You may use the starred version of \string\SKV@cslet.}%
+ }%
+ }%
+ \fi
+ \SKV@resstate\SKV@next
+}
+\SKV@pdef*\SKV@letcs{\SKV@savstate\SKV@t@stopta\SKV@l@tcs}
+\SKV@def*\SKV@l@tcs#1#2{%
+ \ifSKV@st
+ \def\SKV@next{%
+ \begingroup\expandafter\endgroup
+ \expandafter\let\expandafter#1\csname#2\endcsname
+ }%
+ \else
+ \def\SKV@next{%
+ \SKV@ifcsdef{#2}{%
+ \expandafter\let\expandafter#1\csname#2\endcsname
+ }{%
+ \SKV@err{Command '\@backslashchar#2' undefined}%
+ {You may use the starred version of \string\SKV@letcs.}%
+ }%
+ }%
+ \fi
+ \SKV@resstate\SKV@next
+}
+\SKV@pdef*\SKV@csletcs{\SKV@savstate\SKV@t@stopta\SKV@csl@tcs}
+\SKV@def*\SKV@csl@tcs#1#2{%
+ \ifSKV@st
+ \def\SKV@next{%
+ \begingroup\expandafter\endgroup
+ \expandafter\let\csname#1\SKV@aftercs\endcsname{#2}%
+ }%
+ \else
+ \def\SKV@next{%
+ \SKV@ifcsdef{#2}{%
+ \SKV@aftercs\let{#1\SKV@aftercs}{#2}%
+ }{%
+ \SKV@err{Command '\@backslashchar#2' undefined}%
+ {You may use the starred version of \string\SKV@csletcs.}%
+ }%
+ }%
+ \fi
+ \SKV@resstate\SKV@next
+}
+\SKV@pdef*\SKV@numdef{\SKV@savstate\SKV@testoptc{\SKV@expr{num}}}
+\SKV@pdef*\SKV@dimdef{\SKV@savstate\SKV@testoptc{\SKV@expr{dim}}}
+\SKV@def*\SKV@expr#1{%
+ \ifSKV@cl\let\gl@l@x\global\else\let\gl@l@x\relax\fi
+ \ifSKV@pl
+ \def\SKV@next##1{%
+ \edef\resvd@a####1{####1{#1}\SKV@csexpox{##1}}%
+ \resvd@a\SKV@ex@r
+ }%
+ \else
+ \def\SKV@next{\SKV@ex@r{#1}}%
+ \fi
+ \SKV@resstate\SKV@next
+}
+\SKV@def*\SKV@ex@r#1#2#3{%
+ \SKV@ensurescape@ne{#2}{#3}%
+ \SKV@ifstrequal{#1}{num}%
+ {\def\resvd@a{count}}{\def\resvd@a{dimen}}%
+ \SKV@ifundef{#2}{%
+ \@nameuse{new\resvd@a}#2%
+ \gl@l@x#2=\@nameuse{#1expr}#3\relax
+ }{%
+ \gl@l@x#2=\@nameuse{#1expr}#3\relax
+ }%
+}
+\SKV@def*\SKV@ensurescape@ne#1#2{%
+ \SKV@ensurescape{#1}%
+ \SKV@ifnotempty{#2}{}%
+ {\SKV@err{Argument '\string#2' is empty}%
+ {Empty argument '\string#2' is invalid.\SKV@MB
+ I expected a nonempty argument here.}%
+ }%
+}
+\SKV@def*\SKV@badkeylistparser{%
+ \SKV@err{Key list parser '\SKV@keyparser' not allowed}%
+ {Use semicolon (preferable) or colon as parser.}%
+}
+\define@boolkey+[KV]{skeyval}[SKV@]{xchoicelist}[true]{}{%
+ \SKV@inputerr{#1}{xchoicelist}%
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{genparser}[,]{%
+ \@onelevel@sanitize\SKV@genparser
+ \SKV@despacectt\SKV@genparser
+ \SKV@expargs{0}\SKV@CommandGenParser\SKV@genparser\@nil
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{keyparser}[;]{%
+ \@onelevel@sanitize\SKV@keyparser
+ \SKV@xifblank\SKV@keyparser\SKV@badkeylistparser\relax
+ \SKV@despacectt\SKV@keyparser
+ \begingroup
+ \def\SKV@tempa{,}\SKV@detokdespace\SKV@tempa
+ \SKV@ifx\SKV@keyparser\SKV@tempa
+ {\aftergroup\SKV@badkeylistparser}{}%
+ \endgroup
+ \SKV@expargs{0}\SKV@CommandKeyParser\SKV@keyparser\@nil
+}
+\SKV@def*\SKV@keyprefix@err{%
+ \SKV@err{Key prefix '\SKV@keyprefix' is not allowed}%
+ {Use another prefix name instead of '\SKV@keyprefix'.}%
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{keyprefix}[KV]{%
+ \SKV@xifblank\SKV@keyprefix\SKV@keyprefix@err\relax
+ \SKV@despacectt\SKV@keyprefix
+ \SKV@expargs{3}\XKV@checksanitizeb{{\SKV@rkpnames}}%
+ \SKV@tempa\@nil
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@ifx\SKV@keyprefix\SKV@tempa\SKV@keyprefix@err\relax
+ }%
+}
+\SKV@def*\SKV@keyfamily@err{%
+ \SKV@err{Key family '\SKV@keyfamily' is not allowed}%
+ {Use another family name instead of '\SKV@keyfamily'.}%
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{keyfamily}[fam]{%
+ \SKV@xifblank\SKV@keyfamily\SKV@keyfamily@err\relax
+ \SKV@despacectt\SKV@keyfamily
+ \SKV@expargs{3}\XKV@checksanitizeb{{\SKV@rfnames}}%
+ \SKV@tempa\@nil
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@ifx\SKV@keyfamily\SKV@tempa\SKV@keyfamily@err\relax
+ }%
+}
+\SKV@def*\SKV@macroprefix@err{%
+ \SKV@err{Macro prefix '\SKV@macroprefix' is not allowed}%
+ {Use another macro prefix name instead of '\SKV@macroprefix'.}%
+}
+\define@cmdkey[KV]{skeyval}[SKV@]{macroprefix}[mp@]{%
+ \SKV@xifblank\SKV@macroprefix\SKV@macroprefix@err\relax
+ \SKV@despacectt\SKV@macroprefix
+ \SKV@expargs{3}\XKV@checksanitizeb{{\SKV@rmpnames}}%
+ \SKV@tempa\@nil
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@ifx\SKV@macroprefix\SKV@tempa\SKV@macroprefix@err\relax
+ }%
+}
+\SKV@BeforePackageEnd{\deftog{draft}\deftog{final}}
+\define@boolkey+[KV]{skeyval}[SKV@]{draft}[true]{%
+ \ifSKV@draft
+ \setkeys[KV]{skeyval}{final=false}%
+ \SKV@AtPackageEnd{\ifSKV@draft\togon{draft}\else
+ \togoff{draft}\fi}%
+ \fi
+}{%
+ \SKV@inputerr{#1}{draft}%
+}
+\define@boolkey+[KV]{skeyval}[SKV@]{final}[true]{%
+ \ifSKV@final
+ \setkeys[KV]{skeyval}{draft=false}%
+ \SKV@AtPackageEnd{\ifSKV@final\togon{final}\else
+ \togoff{final}\fi}%
+ \fi
+}{%
+ \SKV@inputerr{#1}{final}%
+}
+\DeclareOptionX*{\SKV@warn{Unknown option '\CurrentOption' ignored}}
+\ExecuteOptionsX[KV]<skeyval>{genparser,keyparser,keyprefix,
+ keyfamily,macroprefix,final}
+\ProcessOptionsX*[KV]<skeyval>\relax
+\SKV@pdef*\skvoptions#1{\setkeys[KV]{skeyval}{#1}}
+\SKV@pdef*\SKV@ifdraft{\@nameuse{SKV@\ifSKV@draft1\else2\fi of2}}
+\SKV@pdef*\SKV@iffinal{\@nameuse{SKV@\ifSKV@final1\else2\fi of2}}
+\SKV@pdef*\SKV@ifnotdraft{\@nameuse{SKV@\SKV@ifdraft2\else1\fi of2}}
+\SKV@pdef*\SKV@ifnotfinal{\@nameuse{SKV@\SKV@iffinal2\else1\fi of2}}
+\def\SKV@useinfo#1{Not using '\@backslashchar#1' of 'skyeval' package}
+\SKV@pdef*\SKV@in@#1#2{%
+ \def\in@@##1#1##2##3\in@@{\ifx\in@##2\in@false\else\in@true\fi}%
+ \in@@#2\@mil#1\in@\in@@
+}
+\SKV@pdef*\SKV@in@n#1#2{%
+ \SKV@in@{#1}{#2}%
+ \@nameuse{SKV@\ifin@1\else2\fi of2}%
+}
+\SKV@pdef*\SKV@in@o#1#2{%
+ \@expandtwoargs\SKV@in@{\SKV@expox{#1}}{\SKV@expox{#2}}%
+ \@nameuse{SKV@\ifin@1\else2\fi of2}%
+}
+\SKV@pdef*\SKV@in@x#1#2{%
+ \@expandtwoargs\SKV@in@{#1}{#2}%
+ \@nameuse{SKV@\ifin@1\else2\fi of2}%
+}
+\SKV@pdef*\in@tog#1#2{%
+ \SKV@in@{#1}{#2}%
+ \ifin@\togon{in@}\else\togoff{in@}\fi
+}
+\AtEndOfPackage{\deftog{in@}}
+\SKV@pdef*\in@tok#1#2{%
+ \begingroup
+ \SKV@expnext\SKV@sp@def{\detokenize{#1}}\SKV@tempa
+ \SKV@expnext\SKV@sp@def{\detokenize{#2}}\SKV@tempb
+ \@expandtwoargs\SKV@in@\SKV@tempa\SKV@tempb
+ \global\let\ifin@\ifin@
+ \endgroup
+}
+\AtBeginDocument{%
+ \SKV@ifundef\ifdraft
+ {\SKV@pdef*\ifdraft{\SKV@ifdraft}}%
+ {\SKV@vbmsg{info}{\SKV@useinfo{ifdraft}}}%
+}
+\SKV@ifundef\ifnotdraft
+ {\SKV@pdef*\ifnotdraft{\SKV@ifnotdraft}}%
+ {\SKV@vbmsg{info}{\SKV@useinfo{ifnotdraft}}}
+\SKV@ifundef\iffinal
+ {\SKV@pdef*\iffinal{\SKV@iffinal}}%
+ {\SKV@vbmsg{info}{\SKV@useinfo{iffinal}}}
+\SKV@ifundef\ifnotfinal
+ {\SKV@pdef*\ifnotfinal{\SKV@ifnotfinal}}%
+ {\SKV@vbmsg{info}{\SKV@useinfo{ifnotfinal}}}
+\SKV@def\SKV@star@or@long#1{%
+ \SKV@ifstar
+ {\let\l@ngrel@x\relax\def\@star@or@none{*}#1}%
+ {\let\l@ngrel@x\long\def\@star@or@none{}#1}%
+}
+\SKV@pdef\requirecmd{\SKV@star@or@long\SKV@require@cmd}
+\SKV@def\SKV@require@cmd#1{%
+ \SKV@ensurescape{#1}%
+ \SKV@ifdefined{#1}%
+ {\CheckCommand\@star@or@none}{\newcommand\@star@or@none}{#1}%
+}
+\SKV@redef\@check@eq#1#2{%
+ \SKV@ifx{#1}{#2}{}{%
+ \SKV@vbmsg{warn}{%
+ Previous definition of '\string#1'\SKV@MB
+ doesn't match your new definition.\SKV@MB
+ * I haven't redefined '\string#1' *}%
+ }%
+}
+\SKV@def*\SKV@getswstate#1#2{%
+ \SKV@checkchoice{#2}{true,on,false,off}{%
+ \ifcase\nr\relax
+ \def\SKV@swval{true}%
+ \or
+ \def\SKV@swval{true}%
+ \or
+ \def\SKV@swval{false}%
+ \or
+ \def\SKV@swval{false}%
+ \fi
+ }{%
+ \SKV@swvalerr{#1}{#2}%
+ }%
+}
+\SKV@pdef*\newswitch{\SKV@swtrue\SKV@testopt\SKV@newswitch{}}
+\SKV@pdef*\defswitch{\SKV@swfalse\SKV@testopt\SKV@newswitch{}}
+\SKV@def*\SKV@newswitch[#1]#2{\SKV@testopt{\SKV@n@wswitch[#1]{#2}}{false}}
+\SKV@def*\SKV@n@wswitch[#1]#2[#3]{%
+ \SKV@in@n{,}{#2}{%
+ \SKV@err{%
+ Command \ifSKV@sw'\string\newswitch'\else'\string\defswitch'\fi\space
+ doesn't accept list
+ }{%
+ Please submit only one switch to \ifSKV@sw'\string\newswitch'\else
+ '\string\defswitch'\fi\SKV@MB at a time. You may consider using
+ \ifSKV@sw'\string\NewSwitches'\else'\string\DefSwitches'\fi\SKV@MB
+ if you really want to define a set of switches.
+ }%
+ }{}%
+ \SKV@ensurenoscape{#2}%
+ \SKV@ifstrnotequal{#1#2}{x}{}{%
+ \SKV@err{'\string\ifx' is a TeX primitive}%
+ {You can't redefine '\string\ifx'! This is dangerous.}%
+ }%
+ \ifSKV@sw
+ \SKV@getswstate\newswitch{#3}%
+ \SKV@csifdefinable{if#1#2}\relax
+ \else
+ \SKV@getswstate\defswitch{#3}%
+ \SKV@ifcsundef{if#1#2}{}{%
+ \SKV@vbmsg{warn}{Switch '\@backslashchar if#1#2' redefined\on@line}%
+ }%
+ \fi
+ \csnewif{if#1#2}%
+ \@nameuse{#1#2\SKV@swval}%
+}
+\SKV@newlet\NewSwitches\NewBooleans
+\SKV@newlet\DefSwitches\DefBooleans
+\SKV@def*\setswitch#1#2{%
+ \SKV@ensurenoscape{#1}%
+ \SKV@ifcsundef{if#1}{%
+ \SKV@noswerr{#1}%
+ }{%
+ \SKV@getswstate\setswitch{#2}%
+ \csname#1\SKV@swval\endcsname
+ }%
+}
+\SKV@def*\switchon#1{%
+ \SKV@ensurenoscape{#1}%
+ \SKV@ifcsundef{if#1}{\SKV@noswerr{#1}}{\@nameuse{#1true}}%
+}
+\SKV@newlet\switchtrue\switchon
+\SKV@def*\switchoff#1{%
+ \SKV@ensurenoscape{#1}%
+ \SKV@ifcsundef{if#1}{\SKV@noswerr{#1}}{\@nameuse{#1false}}%
+}
+\SKV@newlet\switchfalse\switchoff
+\SKV@def*\ifswitchon#1{%
+ \SKV@ensurenoscape{#1}%
+ \SKV@ifcsundef{if#1}{\SKV@noswerr{#1}\@gobbletwo}%
+ {\@nameuse{SKV@\@nameuse{if#1}1\else2\fi of2}}%
+}
+\SKV@newlet\ifswitchtrue\ifswitchon
+\SKV@def*\ifswitchoff#1{%
+ \SKV@ensurenoscape{#1}%
+ \SKV@ifcsundef{if#1}{\SKV@noswerr{#1}\@gobbletwo}%
+ {\@nameuse{SKV@\@nameuse{if#1}2\else1\fi of2}}%
+}
+\SKV@newlet\ifswitchfalse\ifswitchoff
+\SKV@pdef*\SKV@noswerr#1{%
+ \SKV@err{Switch '\string#1' is undefined}%
+ {You need to first define the switch '\string#1'.}%
+}
+\SKV@pdef*\SKV@swnameerr#1{%
+ \SKV@err{'\string\if#1' not allowed as a boolean}%
+ {Invalid boolean name '\string#1'.}%
+}
+\SKV@def*\SKV@swvalerr#1#2{%
+ \SKV@err{\string#1\space error: invalid boolean value '#2'}%
+ {Valid boolean values are 'true', 'on', 'false', and 'off'.}%
+}
+\SKV@pdef*\SKV@undeftog@err#1{%
+ \SKV@err{Toggle '#1' undefined}%
+ {You need to first define '#1' before use.}%
+}
+\SKV@pdef*\newtog{\SKV@swtrue\SKV@testopt\SKV@newtog{}}
+\SKV@pdef*\deftog{\SKV@swfalse\SKV@testopt\SKV@newtog{}}
+\SKV@def*\SKV@newtog[#1]#2{\SKV@testopt{\SKV@n@wtog[#1]{#2}}{false}}
+\SKV@def*\SKV@n@wtog[#1]#2[#3]{%
+ \SKV@in@n{,}{#2}{%
+ \SKV@err{%
+ Command \ifSKV@sw'\string\newtog'\else'\string\deftog'\fi\space
+ doesn't accept list
+ }{%
+ Please submit only one tog to \ifSKV@sw'\string\newtog'\else
+ '\string\deftog'\fi\space at a time.\SKV@MB You can use
+ \ifSKV@sw'\string\NewTogs'\else'\string\DefTogs'\fi\space
+ to define a set of togs.
+ }%
+ }{}%
+ \SKV@ensurenoscape{#2}%
+ \ifSKV@sw
+ \SKV@getswstate\newtog{#3}%
+ \SKV@ifcsdef{SKV@toggle@#1#2}{%
+ \SKV@err{Toggle '#1#2' already defined}%
+ {Please provide a new toggle or use '\string\deftog'.}%
+ }{}%
+ \else
+ \SKV@getswstate\deftog{#3}%
+ \SKV@ifcsundef{SKV@toggle@#1#2}{}{%
+ \SKV@vbmsg{warn}{Toggle '#1#2' redefined\on@line}%
+ }%
+ \fi
+ \SKV@csletcs{SKV@toggle@#1#2}{SKV@t@ggle\SKV@swval}
+}
+\SKV@pdef*\providetog#1{%
+ \SKV@ifcsdef{SKV@toggle@#1}{%
+ \SKV@vbmsg{info}%
+ {Toggle '#1' already defined.\SKV@MB Not redefined\on@line}%
+ }{\SKV@cslet{SKV@toggle@#1}\@secondoftwo}%
+}
+\SKV@pdef*\requiretog#1{\SKV@aftercs\requirecmd{SKV@toggle@#1}[2]{##2}}
+\SKV@def*\settog#1#2{%
+ \SKV@ifcsdef{SKV@toggle@#1}{%
+ \SKV@ifcsdef{SKV@t@ggle#2}{%
+ \SKV@csletcs{SKV@toggle@#1}{SKV@t@ggle#2}%
+ }{%
+ \SKV@err{Inadmissible value '#2' for toggle '#1'}%
+ {Valid values for toggles are 'true', 'or', 'false', and 'off'.}%
+ }%
+ }{\SKV@undeftog@err{#1}}%
+}
+\SKV@def*\togon#1{%
+ \SKV@ifcsdef{SKV@toggle@#1}{%
+ \SKV@cslet{SKV@toggle@#1}\SKV@t@ggleon
+ }{\SKV@undeftog@err{#1}}%
+}
+\SKV@def*\togoff#1{%
+ \SKV@ifcsdef{SKV@toggle@#1}{%
+ \SKV@cslet{SKV@toggle@#1}\SKV@t@ggleoff
+ }{\SKV@undeftog@err{#1}}%
+}
+\SKV@newlet\togtrue\togon
+\SKV@newlet\togfalse\togoff
+\SKV@newlet\SKV@t@ggleon\@firstoftwo
+\SKV@newlet\SKV@t@ggleoff\@secondoftwo
+\SKV@newlet\SKV@t@ggletrue\@firstoftwo
+\SKV@newlet\SKV@t@gglefalse\@secondoftwo
+\SKV@def*\iftogon#1{%
+ \SKV@ifcsdef{SKV@toggle@#1}{\@nameuse{SKV@toggle@#1}}%
+ {\SKV@undeftog@err{#1}}%
+}
+\SKV@def*\iftogoff#1{%
+ \SKV@ifcsdef{SKV@toggle@#1}{%
+ \@nameuse{SKV@toggle@#1}\@secondoftwo\@firstoftwo}%
+ {\SKV@undeftog@err{#1}\@gobbletwo}%
+}
+\SKV@newlet\iftogtrue\iftogon
+\SKV@newlet\iftogfalse\iftogoff
+\deftog{pdf}
+\SKV@ifundef\pdfoutput{}{%
+ \ifnum\pdfoutput<\@ne
+ \SKV@pdef*\SKV@ifpdf{\@secondoftwo}%
+ \else
+ \togon{pdf}%
+ \SKV@pdef*\SKV@ifpdf{\@firstoftwo}%
+ \fi
+ \SKV@pdef*\SKV@ifnotpdf{\SKV@ifpdf\@secondoftwo\@firstoftwo}%
+}
+\SKV@ifundef\ifnotpdf
+ {\let\ifnotpdf\SKV@ifnotpdf}%
+ {\SKV@vbmsg{info}{\SKV@useinfo{ifnotpdf}}}
+\SKV@AtDocumentStart{%
+ \SKV@ifundef\ifpdf
+ {\SKV@pdef*\ifpdf{\SKV@ifpdf}}%
+ {\SKV@vbmsg{info}{\SKV@useinfo{ifpdf}}}%
+}
+\SKV@pdef*\SKV@definedkey@err#1{%
+ \SKV@ifcsundef{\XKV@header#1}{}{%
+ \SKV@err{Key '#1' already defined in family '\XKV@tfam'\SKV@MB
+ with prefix '\SKV@pref'}{Use another key name instead of '#1'.}%
+ }%
+}
+\SKV@pdef*\define@togkey{\SKV@skfalse
+ \XKV@t@stopta{\XKV@testoptd\SKV@define@togkey{}}}
+\SKV@def*\SKV@define@togkey#1#2[#3]{%
+ \SKV@findkeypointers{#2}%
+ \SKV@ifcsundef{\XKV@header\SKV@resa}{}{%
+ \SKV@vbmsg{warn}{%
+ Key '\SKV@resa' in family '\XKV@tfam' with\SKV@MB
+ prefix '\SKV@pref' redefined\on@line}
+ \SKV@Undef+{\XKV@header\SKV@resa,SKV@toggle@#1\SKV@resa}%
+ }%
+ \SKV@expnext\SKV@reservkey@err\SKV@resa
+ \SKV@expnext\SKV@suspkey@err\SKV@resa
+ \ifXKV@pl
+ \def\SKV@next{\SKV@aftercs\SKV@d@f@ne@togkey}%
+ \else
+ \def\SKV@next{\SKV@aftercs\SKV@d@fine@togkey}%
+ \fi
+ \begingroup
+ \edef\SKV@tempa{\endgroup
+ {\XKV@header\SKV@resa}{\SKV@resa}{#1\SKV@resa}{#3}}%
+ \aftergroup\SKV@next\SKV@tempa
+}
+\SKV@def*\SKV@d@fine@togkey#1#2#3#4#5{%
+ \SKV@d@f@ne@t@gkey#1{#2}{#3}{#4}%
+ {{\SKV@expargs{0}{\SKV@getswstate\SKV@d@fine@togkey}\XKV@resa\@nil
+ \settog{#3}{\SKV@swval}#5}}%
+}
+\SKV@def*\SKV@d@f@ne@togkey#1#2#3#4#5#6{%
+ \SKV@d@f@ne@t@gkey#1{#2}{#3}{#4}%
+ {{\SKV@expargs{0}{\SKV@getswstate\SKV@d@f@ne@togkey}\XKV@resa\@nil
+ \settog{#3}{\SKV@swval}#5}{#6}}%
+}
+\SKV@def*\SKV@d@f@ne@t@gkey#1#2#3#4#5{%
+ \deftog{#3}%
+ \ifXKV@st\XKV@define@default{#2}{#4}\fi
+ \edef#1##1{%
+ \def#1####1{##1\unexpanded{\XKV@sttrue\XKV@checkchoice[\XKV@resa]}%
+ {####1}{true,false,on,off}\unexpanded{#5}%
+ }%
+ }%
+ \ifXKV@pl#1\XKV@pltrue\else#1\XKV@plfalse\fi
+}
+\SKV@pdef*\define@togkeys{\SKV@skfalse
+ \XKV@plfalse\XKV@testoptd\SKV@define@togkeys{}}
+\SKV@def*\SKV@define@togkeys#1#2[#3]{%
+ \SKV@despacelist{#2}%
+ \SKV@for*[,]\SKV@resa\SKV@tempa{%
+ \SKV@expargs{3}%
+ \SKV@d@fine@togkeys{{\SKV@tempa}}{{#1}{#3}}\@nil
+ }%
+}
+\SKV@def*\SKV@d@fine@togkeys#1#2#3{%
+ \SKV@findkeypointers{#1}%
+ \SKV@ifcsundef{\XKV@header\SKV@resa}{}{%
+ \SKV@vbmsg{warn}{%
+ Key '\SKV@resa' in family '\XKV@tfam' with\SKV@MB
+ prefix '\SKV@pref' redefined\on@line}
+ \SKV@Undef+{\XKV@header\SKV@resa,SKV@toggle@#2\SKV@resa}%
+ }%
+ \SKV@expnext\SKV@reservkey@err\SKV@resa
+ \SKV@expnext\SKV@suspkey@err\SKV@resa
+ \edef\SKV@tempa##1##2##3{%
+ ##1\@nameuse{\XKV@header\SKV@resa}%
+ {\SKV@resa}{#2\SKV@resa}{#3}{{##2{#2\SKV@resa}{##3}}}%
+ }%
+ \SKV@tempa\SKV@d@f@ne@t@gkey\settog\XKV@resa
+}
+\SKV@pdef*\newordkey{\SKV@skfalse\XKV@testoptb\SKV@newordkey}
+\SKV@def*\SKV@newordkey#1{%
+ \SKV@findkeypointers{#1}%
+ \SKV@expnext\SKV@definedkey@err\SKV@resa
+ \begingroup
+ \edef\SKV@tempa{\endgroup
+ \SKV@if@brack{\noexpand\XKV@d@fine@key{\SKV@resa}}%
+ {\noexpand\SKV@d@fine@key{\SKV@resa}}%
+ }%
+ \SKV@tempa
+}
+\SKV@pdef*\newcmdkey{\SKV@skfalse\XKV@testoptd\SKV@newcmdkey{cmd}}
+\SKV@def*\SKV@newcmdkey#1#2[#3]#4{%
+ \SKV@reservmp{#1}\SKV@rmpnames
+ \SKV@findkeypointers{#2}%
+ \SKV@expnext\SKV@definedkey@err\SKV@resa
+ \ifXKV@st
+ \SKV@afterfi
+ \SKV@expnext\XKV@define@default\SKV@resa{#3}%
+ \fi
+ \begingroup
+ \edef\SKV@tempa{\def\SKV@noexpcs{\XKV@header\SKV@resa}####1}%
+ \edef\SKV@tempb{\def\SKV@noexpcs{#1\SKV@resa}\unexpanded{{##1}#4}}%
+ \expandafter\expandafter\expandafter\endgroup
+ \expandafter\SKV@tempa\expandafter{\SKV@tempb}%
+}
+\SKV@pdef*\newcmdkeys{\SKV@skfalse\XKV@testoptd\SKV@newcmdkeys{cmd}}
+\SKV@def*\SKV@newcmdkeys#1#2[#3]{%
+ \SKV@despacelist{#2}%
+ \SKV@for*[,]\SKV@resa\SKV@tempa{%
+ \edef\SKV@tempa{\noexpand\SKV@newcmdkey{#1}{\SKV@tempa}}%
+ \SKV@tempa[#3]{}%
+ }%
+}
+\SKV@pdef*\newchoicekey{\SKV@skfalse
+ \XKV@testopta{\XKV@testoptb\SKV@newchoicekey}}
+\SKV@def*\SKV@newchoicekey#1{%
+ \SKV@findkeypointers{#1}%
+ \SKV@expnext\SKV@definedkey@err\SKV@resa
+ \begingroup
+ \edef\SKV@tempa##1{\endgroup\SKV@testopt{##1{\SKV@resa}}{}}%
+ \SKV@tempa\XKV@d@fine@choicekey
+}
+\let\newmenukey\newchoicekey
+\SKV@pdef*\newboolkey{\SKV@skfalse
+ \XKV@t@stopta{\XKV@testoptd\SKV@newboolkey{}}}
+\SKV@def*\SKV@newboolkey#1#2[#3]{%
+ \SKV@findkeypointers{#2}%
+ \SKV@expnext\SKV@definedkey@err\SKV@resa
+ \ifXKV@pl
+ \def\SKV@next{\SKV@aftercs\XKV@d@f@ne@boolkey}%
+ \else
+ \def\SKV@next{\SKV@aftercs\XKV@d@fine@boolkey}%
+ \fi
+ \edef\SKV@tempa{{\XKV@header\SKV@resa}{\SKV@resa}{#1\SKV@resa}{#3}}%
+ \expandafter\SKV@next\SKV@tempa
+}
+\SKV@pdef*\newboolkeys{\SKV@skfalse
+ \XKV@plfalse\XKV@testoptd\SKV@newboolkeys{}}
+\SKV@def*\SKV@newboolkeys#1#2[#3]{%
+ \SKV@despacelist{#2}%
+ \SKV@for*[,]\SKV@resa\SKV@tempa{%
+ \SKV@definedkey@err\SKV@tempa
+ \SKV@expargs{3}%
+ \XKV@d@fine@boolkeys{{\SKV@tempa}}{{#1}{#3}}\@nil
+ }%
+}
+\SKV@pdef*\newtogkey{\SKV@skfalse
+ \XKV@t@stopta{\XKV@testoptd\SKV@newtogkey{}}}
+\SKV@def*\SKV@newtogkey#1#2[#3]{%
+ \SKV@findkeypointers{#2}%
+ \SKV@expnext\SKV@definedkey@err\SKV@resa
+ \ifXKV@pl
+ \def\SKV@next{\SKV@aftercs\SKV@d@f@ne@togkey}%
+ \else
+ \def\SKV@next{\SKV@aftercs\SKV@d@fine@togkey}%
+ \fi
+ \begingroup
+ \edef\SKV@tempa{\endgroup
+ {\XKV@header\SKV@resa}{\SKV@resa}{#1\SKV@resa}{#3}}%
+ \aftergroup\SKV@next\SKV@tempa
+}
+\SKV@pdef*\newtogkeys{\SKV@skfalse
+ \XKV@plfalse\XKV@testoptd\SKV@newtogkeys{}%
+}
+\SKV@def*\SKV@newtogkeys#1#2[#3]{%
+ \SKV@despacelist{#2}%
+ \SKV@for*[,]\SKV@resa\SKV@tempa{%
+ \SKV@definedkey@err\SKV@tempa
+ \SKV@expargs{3}\SKV@d@fine@togkeys{{\SKV@tempa}}{{#1}{#3}}\@nil
+ }%
+}
+\SKV@pdef*\define@biboolkeys{\SKV@compopta\define@boolkey\SKV@biboolkeys}
+\SKV@pdef*\newbiboolkeys{\SKV@compopta\newboolkey\SKV@biboolkeys}
+\SKV@pdef*\define@uniboolkeys{\SKV@compopta\define@boolkey\SKV@uniboolkeys}
+\SKV@pdef*\newuniboolkeys{\SKV@compopta\newboolkey\SKV@uniboolkeys}
+\SKV@pdef*\define@biuniboolkeys{%
+ \SKV@savstate
+ \SKV@t@stoptb{\SKV@compopta\define@boolkey\SKV@biuniboolkeys}%
+}
+\SKV@pdef*\newbiuniboolkeys{%
+ \SKV@savstate
+ \SKV@t@stoptb{\SKV@compopta\newboolkey\SKV@biuniboolkeys}%
+}
+\SKV@pdef*\define@bitogkeys{\SKV@compopta\define@togkey\SKV@bitogkeys}
+\SKV@pdef*\newbitogkeys{\SKV@compopta\newtogkey\SKV@bitogkeys}
+\SKV@pdef*\define@unitogkeys{\SKV@compopta\define@togkey\SKV@unitogkeys}
+\SKV@pdef*\newunitogkeys{\SKV@compopta\newtogkey\SKV@unitogkeys}
+\SKV@pdef*\define@biunitogkeys{%
+ \SKV@savstate
+ \SKV@t@stoptb{\SKV@compopta\define@togkey\SKV@biunitogkeys}%
+}
+\SKV@pdef*\newbiunitogkeys{%
+ \SKV@savstate
+ \SKV@t@stoptb{\SKV@compopta\newtogkey\SKV@biunitogkeys}%
+}
+\SKV@def*\SKV@compopta#1#2{%
+ \let\SKV@c@mpkey#1\let\SKV@co@pkey#2%
+ \SKV@testopt{\SKV@compoptb}{KV}%
+}
+\SKV@def*\SKV@compoptb[#1]#2{\SKV@testopt{\SKV@compoptc[#1]{#2}}{mp@}}
+\SKV@def*\SKV@compoptc[#1]#2[#3]#4{%
+ \SKV@testopt{\SKV@co@pkey[#1]{#2}[#3]{#4}}{true}%
+}
+\SKV@def*\SKV@biboolkeys[#1]#2[#3]#4[#5]#6#7#8{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax
+ \ifswitchon{#3#4}{\switchoff{#3#6}}{\switchon{#3#6}#8\relax}%
+ }%
+ \@namedef{#1@#2@#6@func}{%
+ #8\relax
+ \ifswitchon{#3#6}{\switchoff{#3#4}}{\switchon{#3#4}#7\relax}%
+ }%
+ \SKV@compk@y{#1}{#2}{#3}{#4}{#5}{#6}%
+}
+\SKV@def*\SKV@uniboolkeys[#1]#2[#3]#4[#5]#6#7#8{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax
+ \ifswitchon{#3#4}{\switchon{#3#6}#8\relax}{\switchoff{#3#6}}%
+ }%
+ \@namedef{#1@#2@#6@func}{%
+ #8\relax
+ \ifswitchon{#3#6}{\switchon{#3#4}#7\relax}{\switchoff{#3#4}}%
+ }%
+ \SKV@compk@y{#1}{#2}{#3}{#4}{#5}{#6}%
+}
+\SKV@def*\SKV@biuniboolkeys[#1]#2[#3]#4[#5]#6#7#8{%
+ \SKV@aftercs\def{#1@#2@#6@func}{#8\relax}%
+ \ifswitchon{SKV@st}{%
+ \ifswitchon{SKV@pl}{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax\ifswitchon{#3#4}{}{\switchoff{#3#6}}%
+ }%
+ }{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax
+ \ifswitchon{#3#4}{}{\switchon{#3#6}\@nameuse{#1@#2@#6@func}}%
+ }%
+ }%
+ }{%
+ \ifswitchon{SKV@pl}{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax\ifswitchon{#3#4}{\switchoff{#3#6}}{}%
+ }%
+ }{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax
+ \ifswitchon{#3#4}{\switchon{#3#6}\@nameuse{#1@#2@#6@func}}{}%
+ }%
+ }%
+ }%
+ \SKV@resstate
+ \SKV@compk@y{#1}{#2}{#3}{#4}{#5}{#6}%
+}
+\SKV@def*\SKV@bitogkeys[#1]#2[#3]#4[#5]#6#7#8{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax
+ \iftogon{#3#4}{\togoff{#3#6}}{\togon{#3#6}#8\relax}%
+ }%
+ \@namedef{#1@#2@#6@func}{%
+ #8\relax
+ \iftogon{#3#6}{\togoff{#3#4}}{\togon{#3#4}#7\relax}%
+ }%
+ \SKV@compk@y{#1}{#2}{#3}{#4}{#5}{#6}%
+}
+\SKV@def*\SKV@unitogkeys[#1]#2[#3]#4[#5]#6#7#8{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax
+ \iftogon{#3#4}{\togon{#3#6}#8\relax}{\togoff{#3#6}}%
+ }%
+ \@namedef{#1@#2@#6@func}{%
+ #8\relax
+ \iftogon{#3#6}{\togon{#3#4}#7\relax}{\togoff{#3#4}}%
+ }%
+ \SKV@compk@y{#1}{#2}{#3}{#4}{#5}{#6}%
+}
+\SKV@def*\SKV@biunitogkeys[#1]#2[#3]#4[#5]#6#7#8{%
+ \@namedef{#1@#2@#6@func}{#8}%
+ \ifswitchon{SKV@st}{%
+ \ifswitchon{SKV@pl}{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax\iftogoff{#3#4}{\togoff{#3#6}}{}%
+ }%
+ }{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax\iftogoff{#3#4}{\togon{#3#6}#8\relax}{}%
+ }%
+ }%
+ }{%
+ \ifswitchon{SKV@pl}{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax\iftogon{#3#4}{\togoff{#3#6}}{}%
+ }%
+ }{%
+ \@namedef{#1@#2@#4@func}{%
+ #7\relax\iftogon{#3#4}{\togon{#3#6}#8\relax}{}%
+ }%
+ }%
+ }%
+ \SKV@resstate
+ \SKV@compk@y{#1}{#2}{#3}{#4}{#5}{#6}%
+}
+\SKV@def*\SKV@compk@y#1#2#3#4#5#6{%
+ \SKV@c@mpkey+[#1]{#2}[#3]{#4}[#5]{\@nameuse{#1@#2@#4@func}}%
+ {\SKV@inputerr{##1}{#4}}%
+ \SKV@c@mpkey+[#1]{#2}[#3]{#6}[#5]{\@nameuse{#1@#2@#6@func}}%
+ {\SKV@inputerr{##1}{#6}}%
+}
+\SKV@pdef*\SKV@keylistrema#1\@nil#2{%
+ \long\edef\SKV@remainder{\unexpanded{#1}}%
+ \SKV@oifblank{\SKV@remainder}{}{%
+ \def\SKV@tempa##1#2\@nil{\def\SKV@remainder{##1}}%
+ \expandafter\SKV@tempa\SKV@remainder\@nil
+ }%
+}
+\SKV@pdef*\define@keylist{%
+ \SKV@define@keylist\define@key\define@cmdkey
+ \define@boolkey\define@togkey\define@choicekey
+}
+\SKV@pdef*\newkeylist{%
+ \SKV@define@keylist\newordkey\newcmdkey
+ \newboolkey\newtogkey\newchoicekey
+}
+\newcommand*\SKV@define@keylist[5]{%
+ \let\SKV@def@ordkey#1%
+ \let\SKV@def@cmdkey#2%
+ \let\SKV@def@boolkey#3%
+ \let\SKV@def@togkey#4%
+ \let\SKV@def@choicekey#5%
+ \SKV@savstate
+ \begingroup
+ \@makeother{\#}%
+ \SKV@t@stopta\SKV@d@fine@keylist
+}
+\SKV@def*\choicekeyvalues{%
+ \SKV@t@stopta{\SKV@testopt\SKV@choic@keyvalues\SKV@keyprefix}}
+\SKV@def*\SKV@choic@keyvalues[#1]{%
+ \SKV@testopt{\SKV@choic@keyv@lues[#1]}\SKV@keyfamily}
+\SKV@def*\SKV@choic@keyv@lues[#1][#2]#3#4{%
+ \ifSKV@st
+ \SKV@csedef{#1@#2@#3@altlist}{#4}%
+ \else
+ \SKV@ifcsundef{#1@#2@#3@altlist}{%
+ \SKV@csedef{#1@#2@#3@altlist}{#4}%
+ }{%
+ \SKV@err
+ {Problem with \string\choicekeyvalues\space for key '#3'}%
+ {You have attempted to set two \string\choicekeyvalues\SKV@MB
+ for choice key '#3' in the same family '#2'\SKV@MB
+ with the same prefix '#1'. You can only do\SKV@MB
+ that if you use the starred variant of \string\choicekeyvalues.}%
+ }%
+ \fi
+}
+\SKV@newlet\CKVS\choicekeyvalues
+\SKV@def*\SKV@detok@z@p#1{%
+ \edef#1{\detokenize\expandafter{#1}\space}%
+ \edef#1{\expandafter\zap@space#1\@empty}%
+}
+\SKV@def*\SKV@detok@zsp#1{%
+ \SKV@ensurescape{#1}%
+ \begingroup
+ \SKV@for*[,]#1\SKV@tempa{%
+ \edef\SKV@tempa{\detokenize\expandafter{\SKV@tempa}\space}%
+ \edef\SKV@tempa{\expandafter\zap@space\SKV@tempa\@empty}%
+ \SKV@csxdef*{SKV@zsp@\expandafter\@gobble\SKV@tempa}%
+ {\SKV@expox{\SKV@tempa}}%
+ }%
+ \endgroup
+}
+\SKV@def*\SKV@detok@dsp#1{%
+ \SKV@ensurescape{#1}%
+ \begingroup
+ \SKV@for*[,]#1\SKV@tempa{%
+ \edef\SKV@tempa{\detokenize\expandafter{\SKV@tempa}}%
+ \SKV@despacectt\SKV@tempa
+ \SKV@csxdef*{SKV@dsp@\expandafter\@gobble\SKV@tempa}%
+ {\SKV@expox{\SKV@tempa}}%
+ }%
+ \endgroup
+}
+\SKV@def*\SKV@exceplist{%
+ \par,\if,\ifcase,\or,\else,\skif,\iftog,\ifswitch}
+\SKV@detok@dsp\SKV@exceplist
+\SKV@def*\SKV@noiferr#1#2{%
+ \SKV@err{You can't use '\@backslashchar #1' in\SKV@MB
+ key macro within keylist}%
+ {Use '\@backslashchar #2' instead of '\@backslashchar #1'.}%
+}
+\SKV@pdef*\uservalue{\uservalue}
+\SKV@pdef*\guservalue{\guservalue}
+\SKV@pdef*\savevalue{\savevalue}
+\SKV@pdef*\gsavevalue{\gsavevalue}
+\SKV@def\SKV@define@multkeys#1,#2,#3,#4\@nil{%
+ \let\SKV@altlisterr\z@
+ \SKV@sp@def{#1}\SKV@tempa
+ \SKV@checkchoice{\SKV@tempa}{ord,cmd,bool,tog,choice,menu}{%
+ \ifnum\nr=5%
+ \let\SKV@keytype\nr
+ \else
+ \edef\SKV@keytype{\the\numexpr\nr+1}%
+ \fi
+ }{%
+ \SKV@checkchoice{\SKV@tempa}{1,2,3,4,5}{%
+ \edef\SKV@keytype{\the\numexpr\nr+1}%
+ }{%
+ \SKV@err{Unknown key type/identifier '\string#1'}%
+ {Valid key types are 'ord', 'cmd', 'bool', 'tog',
+ 'choice', 'menu',\SKV@MB and '1', '2', '3', '4', '5'}%
+ }%
+ }%
+ \SKV@ifnotempty{#2}{}{%
+ \SKV@err{No key name specified for key type '\string#1'}%
+ {\string\define@keylist: key name required for all keys}%
+ }%
+ \begingroup
+ \SKV@ifblank{#4}{}{%
+ \edef\SKV@tempb{\detokenize{#4}\space}%
+ \edef\SKV@tempb{\expandafter\zap@space\SKV@tempb\@empty}%
+ \@expandtwoargs\SKV@in@\SKV@dsp@if\SKV@tempb
+ \ifin@
+ \@expandtwoargs\SKV@in@\SKV@dsp@iftog\SKV@tempb
+ \ifin@\else
+ \@expandtwoargs\SKV@in@\SKV@dsp@ifswitch\SKV@tempb
+ \ifin@\else\SKV@noiferr{if}{skif}\fi
+ \fi
+ \fi
+ \@expandtwoargs\SKV@in@\SKV@dsp@par\SKV@tempb
+ \ifin@\SKV@afterfi\SKV@noiferr{par}{endgraf}\fi
+ \@expandtwoargs\SKV@in@\SKV@dsp@ifcase\SKV@tempb
+ \ifin@\SKV@afterfi\SKV@noiferr{ifcase}{skifcase}\fi
+ \@expandtwoargs\SKV@in@\SKV@dsp@or\SKV@tempb
+ \ifin@\SKV@afterfi\SKV@noiferr{or}{skor}\fi
+ \@expandtwoargs\SKV@in@\SKV@dsp@else\SKV@tempb
+ \ifin@\SKV@afterfi\SKV@noiferr{else}{skelse}\fi
+ }%
+ \protected@edef\SKV@tempa{\endgroup
+ \ifcase\SKV@keytype\relax
+ \or
+ \noexpand\SKV@def@ordkey[\SKV@keyprefix]{\SKV@keyfamily}%
+ {#2}[#3]{\unexpanded{#4}}%
+ \or
+ \noexpand\SKV@def@cmdkey[\SKV@keyprefix]{\SKV@keyfamily}%
+ [\SKV@macroprefix]{#2}[#3]{\unexpanded{#4}}%
+ \or
+ \noexpand\SKV@def@boolkey+[\SKV@keyprefix]{\SKV@keyfamily}%
+ [\SKV@macroprefix]{#2}[#3]{\unexpanded{#4}}{%
+ \unexpanded{\SKV@inputerr{##1}{#2}}%
+ }%
+ \or
+ \noexpand\SKV@def@togkey+[\SKV@keyprefix]{\SKV@keyfamily}%
+ [\SKV@macroprefix]{#2}[#3]{\unexpanded{#4}}{%
+ \unexpanded{\SKV@inputerr{##1}{#2}}%
+ }%
+ \or
+ \SKV@ifcsdef{\SKV@keyprefix @\SKV@keyfamily @#2@altlist}{}%
+ {\let\SKV@altlisterr\@ne}%
+ \noexpand\SKV@def@choicekey*+[\SKV@keyprefix]{\SKV@keyfamily}{#2}%
+ [\unexpanded{\val\nr}]{%
+ \SKV@csuse{\SKV@keyprefix @\SKV@keyfamily @#2@altlist}%
+ }[#3]{\unexpanded{#4}}{\unexpanded{\SKV@inputerr{##1}{#2}}}%
+ \fi
+ }%
+ \SKV@tempa
+ \ifnum\SKV@altlisterr=\@ne
+ \SKV@afterfi
+ \SKV@err{%
+ Choice key '#2' can't be defined.\SKV@MB
+ Alternate key values list for '#2' is empty
+ }{%
+ You need to first define admissible\SKV@MB
+ key values through '\string\choicekeyvalues'\SKV@MB
+ for choice key '#2'.
+ }%
+ \fi
+}
+\SKV@def*\SKV@resvfampf#1#2{%
+ \begingroup
+ \SKV@expnext\XKV@checksanitizeb#2\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \XKV@knftrue
+ \XKV@whilist\SKV@tempa\SKV@tempa\ifXKV@knf\fi{%
+ \SKV@aftercs\ifx{XKV@#1}\SKV@tempa\XKV@knffalse\fi
+ }%
+ \unless\ifXKV@knf
+ \SKV@afterfi
+ \SKV@err{Key #1 '\SKV@tempa' is reserved}%
+ {You have used a reserved key #1: '\SKV@tempa'.\SKV@MB
+ Use another #1 name instead of '\SKV@tempa'.}%
+ \fi
+ \endgroup
+}
+\SKV@redef*\XKV@makepf#1{%
+ \SKV@sp@def{#1}\XKV@prefix
+ \unless\ifSKV@sk
+ \SKV@resvfampf{prefix}\SKV@rkpnames
+ \fi
+ \edef\SKV@pref{\ifx\XKV@prefix\@empty\else\XKV@prefix\fi}%
+ \edef\XKV@prefix{\ifx\XKV@prefix\@empty\else\XKV@prefix @\fi}%
+}
+\SKV@redef*\XKV@makehd#1{%
+ \SKV@expargs{3}\SKV@sp@def{{#1}}\XKV@header\@nil
+ \unless\ifSKV@sk
+ \SKV@resvfampf{family}\SKV@rfnames
+ \fi
+ \edef\XKV@header{%
+ \XKV@prefix\ifx\XKV@header\@empty\else\XKV@header @\fi}%
+}
+\SKV@def*\SKV@resolvekey#1#2\@nil#3{%
+ \def\SKV@resolve##1#2##2##3\@nil##4{%
+ \edef##4{\unexpanded{##2}}%
+ \ifx##4\@nnil
+ \edef##4{\unexpanded{##1}}%
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+ }%
+ \SKV@resolve#1#2{\@nil}\@nil#3%
+}
+\SKV@def*\SKV@addtouserval{%
+ \SKV@addtolist+{SKV@\XKV@header uservalue}\SKV@resa}
+\SKV@def*\SKV@gaddtouserval{%
+ \SKV@addtolist+!{SKV@\XKV@header uservalue}\SKV@resa}
+\SKV@def*\SKV@addtosave{\SKV@addtolist+{XKV@\XKV@header save}\SKV@resa}
+\SKV@def*\SKV@gaddtosave{\begingroup
+ \edef\SKV@tempa{\endgroup
+ \SKV@addtolist+!{XKV@\XKV@header save}{\global{\SKV@resa}}}%
+ \SKV@tempa
+}
+\SKV@def*\SKV@findkeypointers#1{%
+ \SKV@resolvekey{#1}\uservalue\savevalue\@nil\SKV@resa
+ {\SKV@addtouserval\SKV@addtosave}%
+ {\SKV@resolvekey{#1}\guservalue\savevalue\@nil\SKV@resa
+ {\SKV@gaddtouserval\SKV@addtosave}%
+ {\SKV@resolvekey{#1}\savevalue\uservalue\@nil\SKV@resa
+ {\SKV@addtouserval\SKV@addtosave}%
+ {\SKV@resolvekey{#1}\gsavevalue\uservalue\@nil\SKV@resa
+ {\SKV@addtouserval\SKV@gaddtosave}%
+ {\SKV@resolvekey{#1}\guservalue\gsavevalue\@nil\SKV@resa
+ {\SKV@gaddtouserval\SKV@gaddtosave}%
+ {\SKV@resolvekey{#1}\gsavevalue\guservalue\@nil\SKV@resa
+ {\SKV@gaddtouserval\SKV@gaddtosave}%
+ {\SKV@resolvekey{#1}\uservalue\@nil\SKV@resa
+ {\SKV@addtouserval}%
+ {\SKV@resolvekey{#1}\guservalue\@nil\SKV@resa
+ {\SKV@gaddtouserval}%
+ {\SKV@resolvekey{#1}\savevalue\@nil\SKV@resa
+ {\SKV@addtosave}%
+ {\SKV@resolvekey{#1}\gsavevalue\@nil\SKV@resa
+ {\SKV@gaddtosave}%
+ {}}}}}}}}}}%
+}
+\SKV@predef*\define@key{\SKV@skfalse\XKV@testoptb\XKV@define@key}
+\def\XKV@define@key#1{%
+ \SKV@findkeypointers{#1}%
+ \SKV@ifcsundef{\XKV@header\SKV@resa}{}{%
+ \SKV@vbmsg{warn}{%
+ Key '\SKV@resa' in family '\XKV@tfam' with\SKV@MB
+ prefix '\SKV@pref' redefined\on@line}
+ \SKV@csundef{\XKV@header\SKV@resa}%
+ }%
+ \SKV@expnext\SKV@reservkey@err\SKV@resa
+ \SKV@expnext\SKV@suspkey@err\SKV@resa
+ \begingroup
+ \edef\SKV@tempa{\endgroup
+ \SKV@if@brack{\noexpand\XKV@d@fine@key{\SKV@resa}}%
+ {\noexpand\SKV@d@fine@key{\SKV@resa}}%
+ }%
+ \SKV@tempa
+}
+\def\XKV@d@fine@key#1[#2]#3{%
+ \XKV@define@default{#1}{#2}%
+ \@namedef{\XKV@header#1}##1{#3}%
+}
+\def\SKV@d@fine@key#1#2{\@namedef{\XKV@header#1}##1{#2}}
+\SKV@def*\SKV@reservmp#1#2{%
+ \begingroup
+ \SKV@sp@def{#1}\SKV@tempb
+ \SKV@expnext\XKV@checksanitizeb#2\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \XKV@knftrue
+ \XKV@whilist\SKV@tempa\SKV@tempa\ifXKV@knf\fi{%
+ \ifx\SKV@tempb\SKV@tempa\XKV@knffalse\fi
+ }%
+ \unless\ifXKV@knf
+ \SKV@afterfi
+ \SKV@err{Macro prefix '\SKV@tempa' is reserved}%
+ {You have used a reserved macro prefix: '\SKV@tempa'.\SKV@MB
+ Use another macro prefix name instead of '\SKV@tempa'.}%
+ \fi
+ \endgroup
+}
+\SKV@predef*\define@cmdkey{%
+ \SKV@skfalse\XKV@testoptd\XKV@define@cmdkey{cmd}}
+\SKV@predef*\define@cmdkeys{%
+ \SKV@skfalse\XKV@testoptd\XKV@define@cmdkeys{cmd}}
+\def\XKV@define@cmdkey#1#2[#3]#4{%
+ \SKV@reservmp{#1}\SKV@rmpnames
+ \SKV@findkeypointers{#2}%
+ \SKV@ifcsundef{\XKV@header\SKV@resa}{}{%
+ \SKV@vbmsg{warn}{%
+ Key '\SKV@resa' in family '\XKV@tfam' with\SKV@MB
+ prefix '\SKV@pref' redefined\on@line}
+ \SKV@Undef+{\XKV@header\SKV@resa,#1\SKV@resa}%
+ }%
+ \SKV@expnext\SKV@reservkey@err\SKV@resa
+ \SKV@expnext\SKV@suspkey@err\SKV@resa
+ \ifXKV@st
+ \SKV@afterfi
+ \SKV@expnext\XKV@define@default\SKV@resa{#3}%
+ \fi
+ \begingroup
+ \def\SKV@tempa{%
+ \expandafter\def\csname\XKV@header\SKV@resa\endcsname####1}%
+ \SKV@threexp\endgroup\expandafter\SKV@tempa\expandafter%
+ {\expandafter\def\csname#1\SKV@resa\endcsname{##1}#4}%
+}
+\SKV@predef*\define@choicekey{\SKV@skfalse
+ \XKV@testopta{\XKV@testoptb\XKV@define@choicekey}}
+\SKV@newlet\define@menukey\define@choicekey
+\def\XKV@define@choicekey#1{%
+ \SKV@findkeypointers{#1}%
+ \SKV@ifcsundef{\XKV@header\SKV@resa}{}{%
+ \SKV@vbmsg{warn}{%
+ Key '\SKV@resa' in family '\XKV@tfam' with\SKV@MB
+ prefix '\SKV@pref' redefined\on@line}
+ \SKV@csundef{\XKV@header\SKV@resa}%
+ }%
+ \SKV@expnext\SKV@reservkey@err\SKV@resa
+ \SKV@expnext\SKV@suspkey@err\SKV@resa
+ \begingroup
+ \edef\SKV@tempa{\endgroup
+ \SKV@testopt{\noexpand\XKV@d@fine@choicekey{\SKV@resa}}{}%
+ }%
+ \SKV@tempa
+}
+\SKV@predef*\define@boolkey{\SKV@skfalse
+ \XKV@t@stopta{\XKV@testoptd\XKV@define@boolkey{}}}
+\SKV@predef*\define@boolkeys{\SKV@skfalse
+ \XKV@plfalse\XKV@testoptd\XKV@define@boolkeys{}}
+\def\XKV@define@boolkey#1#2[#3]{%
+ \SKV@findkeypointers{#2}%
+ \SKV@ifcsundef{\XKV@header\SKV@resa}{}{%
+ \SKV@vbmsg{warn}{%
+ Key '\SKV@resa' in family '\XKV@tfam' with\SKV@MB
+ prefix '\SKV@pref' redefined\on@line}%
+ \SKV@Undef+{\XKV@header\SKV@resa,#1\SKV@resa}%
+ }%
+ \SKV@expnext\SKV@reservkey@err\SKV@resa
+ \SKV@expnext\SKV@suspkey@err\SKV@resa
+ \ifXKV@pl
+ \def\SKV@next{\SKV@aftercs\XKV@d@f@ne@boolkey}%
+ \else
+ \def\SKV@next{\SKV@aftercs\XKV@d@fine@boolkey}%
+ \fi
+ \edef\SKV@tempa{{\XKV@header\SKV@resa}{\SKV@resa}{#1\SKV@resa}{#3}}%
+ \expandafter\SKV@next\SKV@tempa
+}
+\def\XKV@d@fine@boolkey#1#2#3#4#5{%
+ \XKV@d@f@ne@b@olkey#1{#2}{#3}{#4}%
+ {{\SKV@expargs{0}{\SKV@getswstate\XKV@d@fine@boolkey}\XKV@resa\@nil
+ \csname#3\SKV@swval\endcsname#5}}%
+}
+\def\XKV@d@f@ne@boolkey#1#2#3#4#5#6{%
+ \XKV@d@f@ne@b@olkey#1{#2}{#3}{#4}%
+ {{\SKV@expargs{0}{\SKV@getswstate\XKV@d@f@ne@boolkey}\XKV@resa\@nil
+ \csname#3\SKV@swval\endcsname#5}{#6}}%
+}
+\def\XKV@d@f@ne@b@olkey#1#2#3#4#5{%
+ \csnewif{if#3}%
+ \ifXKV@st\XKV@define@default{#2}{#4}\fi
+ \edef#1##1{%
+ \def#1####1{##1\unexpanded{\XKV@sttrue\XKV@checkchoice[\XKV@resa]}%
+ {####1}{true,false,on,off}\unexpanded{#5}%
+ }%
+ }%
+ \ifXKV@pl#1\XKV@pltrue\else#1\XKV@plfalse\fi
+}
+\def\XKV@d@fine@boolkeys#1#2#3{%
+ \SKV@findkeypointers{#1}%
+ \SKV@ifcsundef{\XKV@header\SKV@resa}{}{%
+ \SKV@vbmsg{warn}{%
+ Key '\SKV@resa' in family '\XKV@tfam' with\SKV@MB
+ prefix '\SKV@pref' redefined\on@line}
+ \SKV@Undef+{\XKV@header\SKV@resa,#2\SKV@resa}%
+ }%
+ \SKV@expnext\SKV@reservkey@err\SKV@resa
+ \SKV@expnext\SKV@suspkey@err\SKV@resa
+ \edef\SKV@tempa##1##2##3{%
+ ##1\@nameuse{\XKV@header\SKV@resa}{\SKV@resa}%
+ {#2\SKV@resa}{#3}{{##2{#2\SKV@resa##3}}}%
+ }%
+ \SKV@tempa\XKV@d@f@ne@b@olkey\@nameuse\XKV@resa
+}
+\SKV@pdef*\reserve@keys{\@testopt\SKV@reserve@keys{KV}}
+\SKV@def*\SKV@reserve@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@res@rve@keys\SKV@tempa{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@res@rve@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@despacelist*\XKV@fams
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@res@rve@k@ys{#3}%
+ }%
+}
+\SKV@def*\SKV@res@rve@k@ys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifcsdef{\XKV@header\SKV@tempa}{%
+ \SKV@err{%
+ Key '\SKV@tempa' with prefix '\SKV@pref' in family
+ \SKV@MB '\XKV@tfam' is already defined
+ }{%
+ Key '\SKV@tempa' in family '\XKV@tfam' can't be reserved.
+ \SKV@MB You may wish to remove it before reserving it.
+ \SKV@MB In that case, you can use '\string\remove@keys'.
+ }%
+ }{%
+ \SKV@csedef*{\XKV@header\SKV@tempa}{%
+ \SKV@err{%
+ Key '\SKV@tempa' with prefix '\SKV@pref' in family
+ '\XKV@tfam'\SKV@MB was reserved\on@line
+ }{%
+ Unreserve '\SKV@tempa' before use.
+ }%
+ }%
+ \SKV@csdef*{\XKV@header\SKV@tempa @reser}{}%
+ }%
+ }%
+}
+\SKV@def*\SKV@reservkey@err#1{%
+ \SKV@ifcsdef{\XKV@header#1@reser}\SKV@err\@gobbletwo
+ {Key '#1' with prefix '\SKV@pref'\SKV@MB
+ is reserved in family '\XKV@tfam'}{Unreserve '#1' before use.}%
+}
+\SKV@def*\ifkeyreserved{\@testopt\SKV@ifkeyreserved{KV}}
+\SKV@def*\SKV@ifkeyreserved[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@swtrue
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@ifkey@reserved\SKV@tempa{#2}{#3}%
+ }%
+ \@nameuse{SKV@\ifSKV@sw2\else1\fi of2}%
+}
+\SKV@def*\SKV@ifkey@reserved#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@despacelist*\XKV@fams
+ \SKV@sp@def{#3}\XKV@tkey
+ \XKV@whilist\XKV@fams\XKV@tfam\ifSKV@sw\fi{%
+ \XKV@makehd\XKV@tfam
+ \SKV@ifcsdef{\XKV@header\XKV@tkey @reser}\SKV@swfalse\relax
+ }%
+}
+\SKV@def*\ifkeysuspended{\@testopt\SKV@ifkeysuspended{KV}}
+\SKV@def*\SKV@ifkeysuspended[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@swtrue
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@ifkey@suspended\SKV@tempa{#2}{#3}%
+ }%
+ \@nameuse{SKV@\ifSKV@sw2\else1\fi of2}%
+}
+\SKV@def*\SKV@ifkey@suspended#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@despacelist*\XKV@fams
+ \SKV@sp@def{#3}\XKV@tkey
+ \XKV@whilist\XKV@fams\XKV@tfam\ifSKV@sw\fi{%
+ \XKV@makehd\XKV@tfam
+ \SKV@ifcsdef{\XKV@header\XKV@tkey @susp}\SKV@swfalse\relax
+ }%
+}
+\SKV@def*\ifkeydefined{\@testopt\SKV@ifkeydefined{KV}}
+\SKV@def*\SKV@ifkeydefined[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@swtrue
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@ifk@ydefined\SKV@tempa{#2}{#3}%
+ }%
+ \@nameuse{SKV@\ifSKV@sw2\else1\fi of2}%
+}
+\SKV@def*\SKV@ifk@ydefined#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@despacelist*\XKV@fams
+ \SKV@sp@def{#3}\XKV@tkey
+ \XKV@whilist\XKV@fams\XKV@tfam\ifSKV@sw\fi{%
+ \XKV@makehd\XKV@tfam
+ \SKV@ifcsdef{\XKV@header\XKV@tkey}\SKV@swfalse\relax
+ }%
+}
+\SKV@def*\SKV@disabledkey@err{%
+ \SKV@err{%
+ Key '\SKV@disabledkey' with prefix '\SKV@pref' in family
+ \SKV@MB '\XKV@tfam' was disabled\on@line
+ }{%
+ You can't set or reset '\SKV@disabledkey' at this\SKV@MB
+ late stage. Perhaps you're required to set it \SKV@MB
+ earlier, within a package or in the document's preamble.
+ }%
+}
+\def\disable@keys{%
+ \SKV@ifstar{\@testopt\XKV@disable@keys{KV}}%
+ {\@testopt\SKV@disable@keys{KV}}%
+}
+\SKV@def*\SKV@disable@keys[#1]#2#3{%
+ \SKV@locfalse
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@dis@ble@keys\SKV@tempa{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@dis@ble@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@despacelist*\XKV@fams
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@dis@ble@k@ys{#3}%
+ }%
+}
+\SKV@def*\SKV@dis@ble@k@ys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifcsundef{\XKV@header\SKV@tempa}{%
+ \ifSKV@verbose\SKV@disabledkey@warn\fi
+ }{%
+ \SKV@dis@ble@k@y@\SKV@tempa
+ }%
+ }%
+}
+\def\SKV@disabledkey@warn{%
+ \SKV@warn{Key '\SKV@tempa' with prefix '\SKV@pref'
+ \SKV@MB is undefined in family '\XKV@tfam':
+ \SKV@MB can't be \ifSKV@loc localized
+ \else disabled\fi\on@line
+ }%
+}
+\def\SKV@disabledkey@info{%
+ \SKV@info{Key '\SKV@disabledkey' with prefix '\SKV@pref'
+ in family '\XKV@tfam'\SKV@MB was \ifSKV@loc localized
+ \else disabled\fi\on@line
+ }%
+}
+\SKV@def*\SKV@dis@ble@k@y@#1{%
+ \edef\SKV@disabledkey{#1}%
+ \SKV@ifcsundef{\XKV@header#1@default}{%
+ \edef#1{\noexpand\XKV@define@key{#1}}%
+ }{%
+ \edef#1{\noexpand\XKV@define@key{#1}[]}%
+ }%
+ \SKV@expargs{0}#1\SKV@disabledkey@err\@nil
+ \ifSKV@verbose\SKV@disabledkey@info\fi
+}
+\SKV@pdef*\localize@keys{%
+ \SKV@onlypackage\SKV@savstate
+ \SKV@t@stopta{\@testopt\SKV@localize@keys{KV}}%
+}
+\SKV@def*\SKV@localize@keys[#1]#2#3{%
+ \SKV@loctrue
+ \ifSKV@st
+ \expandafter\SKV@BeforeDocumentStart
+ \else
+ \expandafter\SKV@AfterPackageEnd
+ \fi
+ {%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@dis@ble@keys\SKV@tempa{#2}{#3}%
+ }%
+ }%
+ \SKV@resstate
+}
+\SKV@def*\SKV@suspkey@err#1{%
+ \SKV@ifcsdef{\XKV@header#1@susp}\SKV@err\@gobbletwo
+ {Key '#1' was suspended from family '\XKV@tfam'}%
+ {You can use \string\restore@key\space to restore '#1'.}%
+}
+\SKV@def*\SKV@suspkey@e@r{%
+ \SKV@err{Key '\SKV@suspkey' in family '\XKV@tfam' was\SKV@MB
+ suspended\on@line}{You can use \string\restore@key\space
+ to restore '\SKV@suspkey'.}%
+}
+\SKV@pdef*\suspend@keys{\@testopt\SKV@suspend@keys{KV}}
+\SKV@def*\SKV@suspend@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@s@spend@keys\SKV@tempa{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@s@spend@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@despacelist*\XKV@fams
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@s@sp@nd@keys{#3}%
+ }%
+}
+\SKV@def*\SKV@s@sp@nd@keys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifcsundef{\XKV@header\SKV@tempa}{%
+ \SKV@vbmsg{warn}{%
+ Key '\SKV@tempa' with prefix '\SKV@pref'
+ \SKV@MB is undefined in family '\XKV@tfam':
+ \SKV@MB can't be suspended\on@line}%
+ }{%
+ \SKV@s@sp@nd@k@ys\SKV@tempa
+ }%
+ }%
+}
+\SKV@def*\SKV@s@sp@nd@k@ys#1{%
+ \SKV@ifcsdef{\XKV@header#1@susp}{%
+ \SKV@err{%
+ Key '#1' with prefix '\SKV@pref'
+ was suspended from family '\XKV@tfam'
+ }{%
+ You can use \string\restore@key\space to restore '#1'.
+ }%
+ }{%
+ \edef\SKV@suspkey{#1}%
+ \global\SKV@csletcs{\XKV@header#1@susp}{\XKV@header#1}%
+ \SKV@csedef*{\XKV@header#1}{\SKV@suspkey@e@r}%
+ \SKV@vbmsg{info}{Key '\SKV@suspkey' with prefix '\SKV@pref' in
+ \SKV@MB family '\XKV@tfam' was suspended\on@line}%
+ }%
+}
+\SKV@pdef*\restore@keys{\@testopt\SKV@restore@keys{KV}}
+\SKV@def*\SKV@restore@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@r@store@keys\SKV@tempa{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@r@store@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@despacelist*\XKV@fams
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@r@st@re@keys{#3}%
+ }%
+}
+\SKV@def*\SKV@r@st@re@keys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifcsundef{\XKV@header\SKV@tempa}{%
+ \SKV@vbmsg{warn}{Key '\SKV@tempa' with prefix '\SKV@pref'
+ \SKV@MB is undefined in family '\XKV@tfam':
+ \SKV@MB can't be restored\on@line}%
+ }{%
+ \SKV@r@st@re@k@ys\SKV@tempa
+ }%
+ }%
+}
+\SKV@def*\SKV@r@st@re@k@ys#1{%
+ \SKV@ifcsundef{\XKV@header#1@susp}{%
+ \SKV@err{Key '#1' wasn't suspended from family
+ \SKV@MB '\XKV@tfam': can't be restored\on@line}%
+ {I can't restore unsuspended key '#1'}%
+ }{%
+ \edef\SKV@restoredkey{#1}%
+ \SKV@csletcs{\XKV@header#1}{\XKV@header#1@susp}%
+ \SKV@csundef{\XKV@header#1@susp}%
+ \SKV@vbmsg{info}{Key '\SKV@restoredkey' with prefix
+ '\SKV@pref' in family \SKV@MB '\XKV@tfam' restored\on@line}%
+ }%
+}
+\SKV@pdef*\remove@keys{\@testopt\SKV@remove@keys{KV}}
+\SKV@def*\SKV@remove@keys[#1]#2#3{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for*[,]\SKV@tempa\SKV@tempa{%
+ \SKV@expnext\SKV@r@move@keys\SKV@tempa{#2}{#3}%
+ }%
+}
+\SKV@def*\SKV@r@move@keys#1#2#3{%
+ \XKV@makepf{#1}%
+ \XKV@checksanitizeb{#2}\XKV@fams
+ \SKV@despacelist*\XKV@fams
+ \SKV@for@b\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam
+ \SKV@r@m@ve@keys{#3}%
+ }%
+}
+\SKV@def*\SKV@r@m@ve@keys#1{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@despacelist*\SKV@tempa
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@ifcsundef{\XKV@header\SKV@tempa @susp}{}{%
+ \SKV@err{Key '\SKV@tempa' with prefix '\SKV@pref'
+ \SKV@MB was suspended from family '\XKV@tfam':
+ \SKV@MB I can't remove/unreserve it\on@line.
+ \SKV@MB You need to first restore key '\SKV@tempa'
+ \SKV@MB before you can remove/unreserve it}%
+ {First restore key '\SKV@tempa' before removing it.}%
+ }%
+ \SKV@ifcsundef{\XKV@header\SKV@tempa}{%
+ \SKV@vbmsg{warn}{Key '\SKV@tempa' with prefix '\SKV@pref'
+ \SKV@MB is undefined in family '\XKV@tfam':
+ \SKV@MB I can't remove or unreserve it\on@line}%
+ }{%
+ \SKV@r@m@ve@k@ys\SKV@tempa
+ }%
+ }%
+}
+\SKV@def*\SKV@r@m@ve@k@ys#1{%
+ \begingroup
+ \edef\SKV@tempa{\XKV@header#1,\XKV@header#1@default,
+ \XKV@header#1@func,\XKV@header#1@altlist,
+ \XKV@header#1@reser
+ }%
+ \SKV@for@b\SKV@tempa\SKV@tempa{%
+ \SKV@despacectt\SKV@tempa
+ \SKV@csgundef{\SKV@tempa}%
+ }%
+ \endgroup
+ \SKV@vbmsg{info}{Key '#1' with prefix '\SKV@pref' in family\SKV@MB
+ '\XKV@tfam' was removed\on@line}%
+}
+\SKV@newlet\unreserve@keys\remove@keys
+\SKV@def*\uservaluekeys{\XKV@testoptb\SKV@uservaluekeys}
+\SKV@def*\SKV@uservaluekeys#1{%
+ \SKV@ifcsundef{SKV@\XKV@header uservalue}{%
+ \XKV@checksanitizeb{#1}\SKV@tempa
+ \SKV@csxdef*{SKV@\XKV@header uservalue}{\SKV@expox{\SKV@tempa}}%
+ }{%
+ \SKV@aftercs\XKV@merge{SKV@\XKV@header uservalue}{#1}\XKV@getsg
+ }%
+}
+\SKV@def*\SKV@undefinedkeys#1#2#3{%
+ \edef\SKV@resvd##1{\SKV@addtolist![;]##1{(#1:#2:#3)}}%
+ \SKV@resvd\SKV@und@finedkeys
+}
+\SKV@predef*\ExecuteOptionsX{%
+ \SKV@sktrue\XKV@stfalse\XKV@plfalse\XKV@t@stopte\XKV@setkeys}
+\SKV@predef*\setkeys{\SKV@sktrue\XKV@testopta{\XKV@testoptc\XKV@setkeys}}
+\SKV@newlet\SKVSetKeys\setkeys
+\SKV@pdef*\UseSkeyvalSetkeys{%
+ \SKV@ifx\setkeys\SKVSetKeys\relax{\let\setkeys\SKVSetKeys}%
+}
+\SKV@redef*\XKV@setkeys[#1]#2{%
+ \def\skif##1{%
+ \SKV@ensurenoscape{##1}%
+ \SKV@ifcsdef{if##1}{}{%
+ \SKV@err{Undefined boolean '##1'}%
+ {'\string\skif' error: boolean '##1' undefined.}%
+ }%
+ \csname if##1\endcsname
+ }%
+ \let\skifx\ifx
+ \let\skifcase\ifcase
+ \let\skor\or
+ \let\skelse\else
+ \let\skfi\fi
+ \let\SKV@und@finedkeys\@empty
+ \XKV@checksanitizea{#2}\XKV@resb
+ \SKV@normalizea\XKV@resb
+ \let\XKV@naa\@empty
+ \XKV@for@o\XKV@resb\XKV@tempa{%
+ \expandafter\XKV@g@tkeyname\XKV@tempa=\@nil\XKV@tempa
+ \XKV@addtolist@x\XKV@naa\XKV@tempa
+ }%
+ \ifnum\XKV@depth=\z@\let\XKV@rm\@empty\fi
+ \XKV@usepresetkeys{#1}{preseth}%
+ \SKV@expnext\XKV@s@tkeys\XKV@resb{#1}%
+ \XKV@usepresetkeys{#1}{presett}%
+ \let\CurrentOption\@empty
+ \SKV@skfalse
+ \SKV@ifx\SKV@und@finedkeys\@empty{}{%
+ \def\SKV@tempa{stop}%
+ \SKV@warn{\string\setkeys\space error: Unknown keys:\SKV@MB
+ \SKV@expox\SKV@und@finedkeys}%
+ \typein[\answer]{%
+ ^^JThe following keys are undefined and couldn't be set:
+ ^^J\SKV@expox\SKV@und@finedkeys
+ ^^JEnter 'stop' or 'go' and <return> to continue.}%
+ \ifx\answer\SKV@tempa\stop\fi
+ }%
+}
+\SKV@redef*\XKV@s@tk@ys#1=#2=#3\@nil{%
+ \XKV@g@tkeyname#1=\@nil\XKV@tkey
+ \SKV@expnext\SKV@sp@def\XKV@tkey\XKV@tkey
+ \SKV@ifx\XKV@tkey\@empty{%
+ \SKV@ifempty{#2}{}{%
+ \SKV@err{No key specified for value '#2'}%
+ {You have supplied a value '#2' without key name.\SKV@MB
+ This is certainly an error on your part.\SKV@MB
+ I can't process this value without key name.\SKV@MB
+ Please enter 'X' and <return>. Correct the error and rerun.}
+ }%
+ }{%
+ \@expandtwoargs\in@{,\XKV@tkey,}{,\XKV@na,}%
+ \unless\ifin@
+ \XKV@knftrue
+ \SKV@sp@def{#2}\XKV@tempa
+ \ifXKV@preset
+ \XKV@s@tk@ys@{#3}%
+ \else
+ \ifXKV@pl
+ \XKV@for@eo\XKV@fams\XKV@tfam{%
+ \XKV@makehd\XKV@tfam\XKV@s@tk@ys@{#3}%
+ }%
+ \else
+ \XKV@whilist\XKV@fams\XKV@tfam\ifXKV@knf\fi{%
+ \XKV@makehd\XKV@tfam\XKV@s@tk@ys@{#3}%
+ }%
+ \fi
+ \fi
+ \ifXKV@knf
+ \ifXKV@inpox
+ \SKV@ifx\XKV@doxs\relax{%
+ \unless\ifx\@currext\@clsextension
+ \let\CurrentOption\XKV@tkey\@unknownoptionerror
+ \fi
+ }{%
+ \XKV@doxs
+ }%
+ \else
+ \ifXKV@st
+ \XKV@addtolist@o\XKV@rm\CurrentOption
+ \else
+ \SKV@undefinedkeys\SKV@pref\XKV@fams\XKV@tkey
+ \fi
+ \fi
+ \else
+ \ifXKV@inpox\ifx\XKV@testclass\XKV@documentclass
+ \SKV@expnext\XKV@useoption\CurrentOption
+ \fi\fi
+ \fi
+ \fi
+ }%
+}
+\SKV@redef*\XKV@s@tk@ys@#1{%
+ \SKV@ifcsundef{\XKV@header\XKV@tkey}{%
+ \SKV@vbmsg{warn}{No key macro for key '\XKV@tkey'\SKV@MB
+ in families '\XKV@fams'}%
+ }{%
+ \XKV@knffalse
+ \SKV@ifcsundef{SKV@\XKV@header uservalue}{}{%
+ \SKV@aftercs\SKV@testuservaluekey
+ {SKV@\XKV@header uservalue}\XKV@tkey
+ \ifSKV@uv
+ \SKV@ifnotblank{#1}{}{%
+ \SKV@err{You're required to supply a value\SKV@MB
+ for key '\XKV@tkey' in families '\XKV@fams'}%
+ {Please supply a value for key '\XKV@tkey'\SKV@MB
+ of families '\XKV@fams' and rerun.\SKV@MB
+ The originator of this key meant it to\SKV@MB
+ require a user value.}%
+ }%
+ \fi
+ }%
+ \SKV@ifcsundef{XKV@\XKV@header save}{}{%
+ \SKV@aftercs\XKV@testsavekey{XKV@\XKV@header save}\XKV@tkey
+ }%
+ \ifXKV@rkv
+ \ifXKV@sg\expandafter\global\fi
+ \SKV@aftercs\let{XKV@\XKV@header\XKV@tkey @value}\XKV@tempa
+ \fi
+ \SKV@expnext\XKV@replacepointers\XKV@tempa
+ \SKV@ifblank{#1}{%
+ \SKV@ifcsundef{\XKV@header\XKV@tkey @default}{%
+ \SKV@err{'\XKV@tkey' in family '\XKV@tfam' with\SKV@MB
+ prefix '\XKV@pref' has no default value and\SKV@MB
+ you haven't supplied a value for it either}%
+ {Supply a value for key '\XKV@tkey' and rerun.}%
+ }{%
+ \SKV@xaftercs\XKV@default{\XKV@header\XKV@tkey @default}\@nil
+ }%
+ }{%
+ \XKV@savstate
+ \csname\XKV@header\XKV@tkey\expandafter
+ \endcsname\expandafter{\XKV@tempa}\relax
+ \XKV@resstate
+ }%
+ }%
+}
+\SKV@def*\SKV@testuservaluekey#1#2{%
+ \SKV@swtrue\SKV@uvfalse
+ \XKV@whilist#1\SKV@tempa\ifSKV@sw\fi{%
+ \ifx#2\SKV@tempa\SKV@uvtrue\SKV@swfalse\fi
+ }%
+}
+\SKV@def*\SKV@remspaceletter#1#2{%
+ \begingroup
+ \SKV@toks\expandafter{#2 #1}%
+ \def\SKV@tempa##1 #1##2\@nil{%
+ \SKV@ifblank{##2}{%
+ \SKV@toks{##1}%
+ }{%
+ \SKV@toks{##1#1##2}%
+ \expandafter\SKV@tempa\the\SKV@toks\@nil
+ }%
+ }%
+ \expandafter\SKV@tempa\the\SKV@toks\@nil
+ \xdef#2{\the\SKV@toks}%
+ \endgroup
+}
+\SKV@def*\SKV@remletterspace#1#2{%
+ \begingroup
+ \SKV@toks\expandafter{#2#1 }%
+ \def\SKV@tempa##1#1 ##2\@nil{%
+ \SKV@ifblank{##2}{%
+ \SKV@toks{##1}%
+ }{%
+ \SKV@toks{##1#1##2}%
+ \expandafter\SKV@tempa\the\SKV@toks\@nil
+ }%
+ }%
+ \expandafter\SKV@tempa\the\SKV@toks\@nil
+ \xdef#2{\the\SKV@toks}%
+ \endgroup
+}
+\SKV@def*\SKV@remletterletter#1#2{%
+ \begingroup
+ \SKV@toks\expandafter{#2#1#1}%
+ \def\SKV@tempa##1#1#1##2\@nil{%
+ \SKV@toks{##1#1##2}%
+ \SKV@ifblank{##2}{}{%
+ \expandafter\SKV@tempa\the\SKV@toks\@nil}%
+ }%
+ \expandafter\SKV@tempa\the\SKV@toks\@nil
+ \def\SKV@tempa##1#1#1\@nil{\gdef#2{##1}}%
+ \expandafter\SKV@tempa\the\SKV@toks#1\@nil
+ \endgroup
+}
+\SKV@def*\SKV@remcommaequal#1#2{%
+ \begingroup
+ \SKV@toks\expandafter{#2#1}%
+ \def\SKV@tempa##1#1##2\@nil{%
+ \SKV@ifblank{##2}{%
+ \SKV@toks{##1}%
+ }{%
+ \SKV@toks{##1=##2}%
+ \expandafter\SKV@tempa\the\SKV@toks\@nil
+ }%
+ }%
+ \expandafter\SKV@tempa\the\SKV@toks\@nil
+ \xdef#2{\the\SKV@toks}%
+ \endgroup
+}
+\SKV@def*\SKV@normalizea#1{%
+ \@expandtwoargs\SKV@in@{ ,}{\SKV@expox{#1}}%
+ \ifin@\SKV@remspaceletter{,}#1\fi
+ \@expandtwoargs\SKV@in@{, }{\SKV@expox{#1}}%
+ \ifin@\SKV@remletterspace{,}#1\fi
+ \@expandtwoargs\SKV@in@{,,}{\SKV@expox{#1}}%
+ \ifin@\SKV@remletterletter{,}#1\fi
+ \@expandtwoargs\SKV@in@{ =}{\SKV@expox{#1}}%
+ \ifin@\SKV@remspaceletter{=}#1\fi
+ \@expandtwoargs\SKV@in@{= }{\SKV@expox{#1}}%
+ \ifin@\SKV@remletterspace{=}#1\fi
+ \@expandtwoargs\SKV@in@{==}{\SKV@expox{#1}}%
+ \ifin@\SKV@remletterletter{=}#1\fi
+ \@expandtwoargs\SKV@in@{,=}{\SKV@expox{#1}}%
+ \ifin@\SKV@remcommaequal{,=}#1\fi
+ \@expandtwoargs\SKV@in@{=,}{\SKV@expox{#1}}%
+ \ifin@\SKV@remcommaequal{=,}#1\fi
+}
+\SKV@def*\SKV@gobblescape{%
+ \ifnum\escapechar>255\else
+ \ifnum\escapechar<0\else
+ \expandafter\expandafter
+ \csname @gobble\ifnum\escapechar=32 space\fi
+ \SKV@threexp\endcsname
+ \fi\fi
+ \string%
+}
+\SKV@def*\SKV@save#1{%
+ \SKV@ensurescape{#1}%
+ \edef\SKV@tempa{saved\SKV@gobblescape#1}%
+ \SKV@ifcsdef\SKV@tempa{%
+ \SKV@err{%
+ \string#1\space already saved. You've to restore\SKV@MB
+ it or undefine '\SKV@csexpox{\SKV@tempa}' before\SKV@MB
+ you can save \string#1\space again
+ }\@ehc
+ }{%
+ \SKV@ifdef{#1}{%
+ \SKV@cslet\SKV@tempa{#1}%
+ }{%
+ \SKV@err{Undefined '\string#1' can't be saved\on@line}%
+ {You can't restore undefined commands.\SKV@MB
+ So why save undefined '\string#1' here?}%
+ }%
+ }%
+}
+\SKV@def*\SKV@restore#1{%
+ \SKV@ensurescape{#1}%
+ \edef\SKV@tempa{saved\SKV@gobblescape#1}%
+ \SKV@ifcsdef\SKV@tempa{%
+ \def\SKV@next{\SKV@letcs#1\SKV@tempa\SKV@csundef\SKV@tempa}%
+ }{%
+ \SKV@err{%
+ '\@nameuse\SKV@tempa' is undefined:\SKV@MB
+ '\string#1' can't be restored\on@line
+ }{%
+ '\string#1' can't be restored\on@line.\SKV@MB
+ Note that each call to \string\SKV@restore\space
+ undefines\SKV@MB the saved command.
+ }%
+ }%
+ \SKV@next
+}
+\SKV@providedef*\input@path{}
+\SKV@pdef*\InputFileOnce{%
+ \def\SKV@inputfile##1##2{%
+ \InputIfFileExists{##2}{%
+ \SKV@cslet{##2@read}\@empty
+ \let\SKV@inp@tfile\relax
+ }{%
+ \typein[\answer]{^^J! File '\string##2' does not exist.^^J
+ Enter filename or 'no' and <return> to continue.}%
+ \SKV@oifstrequal{\answer}{no}{%
+ \let\SKV@inp@tfile\relax
+ }{%
+ \def\SKV@inp@tfile{%
+ \SKV@expargs{0}{\SKV@InputFileOnce[##1]}\answer\@nil
+ }}}}%
+ \let\SKV@no\z@
+ \SKV@save\input@path
+ \SKV@t@stopta{\SKV@testopt\SKV@InputFileOnce{.}}%
+}
+\SKV@def*\SKV@InputFileOnce[#1]#2{%
+ \SKV@appto!\input@path{{#1/}}%
+ \ifSKV@st
+ \SKV@afterelsefi
+ \SKV@inputfile{#1}{#2}%
+ \else
+ \SKV@afterfi
+ \SKV@ifcsdef{#2@read}{%
+ \SKV@vbmsg{warn}{File '#2' already read:\SKV@MB
+ File '#2' can't be read again}%
+ }{%
+ \SKV@inputfile{#1}{#2}%
+ }%
+ \fi
+ \SKV@inp@tfile
+ \ifnum\SKV@no=\z@\SKV@restore\input@path\fi
+ \let\SKV@no\@ne
+}
+\SKV@pdef*\SKV@notloadederr#1{%
+ \SKV@ifcsdef{ver@#1.\@pkgextension}{}{%
+ \SKV@err{Package '#1' wasn't loaded}%
+ {Document has begun and package '#1' wasn't loaded.\SKV@MB
+ You wanted package '#1' loaded.}%
+ }%
+}
+\SKV@def*\SKV@notloaded{}
+\SKV@pdef*\@ensurepackageloaded#1{%
+ \SKV@for[,]{#1}\SKV@resvd{%
+ \edef\SKV@resvd##1##2{\SKV@appto!##1{##2{\SKV@resvd}}}%
+ \SKV@resvd\SKV@notloaded\SKV@doloaded
+ }%
+}
+\SKV@AtDocumentStart{%
+ \let\SKV@doloaded\SKV@notloadederr
+ \SKV@notloaded
+ \global\let\SKV@doloaded\@gobble
+}
+\SKV@onlypreamble{%
+ \SKV@preamblecmds,\SKV@onlypreamble,\@afterpackageloaded,
+ \@ifpackagecurrent,\@ifpackagenotcurrent,\@ifloadedandcurrent,
+ \@ensurepackageloaded,\SKV@AtPackageEnd,\SKV@AtClassEnd,
+ \SKV@BeforePackageEnd,\SKV@BeforeClassEnd,\SKV@AfterPackageEnd,
+ \SKV@AfterClassEnd,\SKV@BeforeLastPage,\SKV@AfterLastPage,
+ \SKV@AfterDocumentEnd,\UseSkeyvalSetkeys
+}
+
+\endinput
+
+%%% End of file skeyval.sty %%%
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-core.tex b/macros/latex/contrib/skeyval/tex/skeyval-core.tex
new file mode 100644
index 0000000000..e0ae452a73
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-core.tex
@@ -0,0 +1,8466 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-core.tex', version 1.3, 2013/05/15. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\csname skeyval-core-loaded\endcsname
+\expandafter\let\csname skeyval-core-loaded\endcsname\endinput
+
+\begingroup
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode044 12 % ,
+\def\skv@prova{\endgroup
+ \def\do##1,{%
+ \ifx\do##1\else
+ \catcode##1\string=\the\catcode##1\relax
+ \expandafter\do
+ \fi
+ }%
+ \edef\skv@core@restorecodes{\do35,64,123,125,61,59,13,\do,}%
+}
+\skv@prova
+
+\edef\skv@core@restorecodes{%
+ \unexpanded\expandafter{\skv@core@restorecodes}%
+ \endlinechar\the\endlinechar\relax
+ \catcode`\^^M=\the\catcode`\^^M\relax
+}
+\endlinechar13 %
+\catcode013 05 % ^^M
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode061 12 % =
+\catcode044 12 % ,
+\def\do#1=#2,{%
+ \ifx\do#1\else
+ \edef\skv@core@restorecodes{%
+ \unexpanded\expandafter{\skv@core@restorecodes}%
+ \catcode#1=\the\catcode#1\relax
+ }%
+ \catcode#1=#2\relax
+ \expandafter\do
+ \fi
+}
+\do 032=10,033=12,036=03,038=04,040=12,041=12,042=12,043=12,%
+ 059=12,045=12,047=12,058=12,063=12,091=12,093=12,126=13,13=5,\do=,%
+
+\newdimen\skvz@\skvz@=0pt\relax
+\newcount\skvm@ne\skvm@ne=-1\relax
+\ifcase
+ \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
+
+\newif\ifskv@latex
+\newif\ifskv@tempst
+\ifx\ProvidesFile\@undefined
+ \skv@latexfalse
+ \message{File 'skeyval-core.tex' 2013/05/15 v1.3:
+ Core of 'skeyval' key-value parser (AM)}
+ \input skeyval-ltxcmds
+\else
+ \skv@latextrue
+ \ProvidesFile{skeyval-core.tex}
+ [2013/05/15 v1.3 Base file of skeyval package (AM)]
+ \@addtofilelist{skeyval-core.tex}
+ \long\def\@nodocument#1{%
+ \@latex@error{'#1' appeared\on@line\space without
+ \noexpand\begin{document}}\@ehd
+ }
+\fi
+
+% 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{%
+ \ifdefined#1%
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {\@latex@error{Command '\string#1' already defined}\skv@ehd}
+ {#2}%
+}
+% \skvgenloop{<parser>}{<list>}{<1.parameter.callback>}
+%
+% 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\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
+ }%
+ \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@
+}
+\endgroup
+
+\protected\def\skvnewregister#1#2{%
+ \def\skv@prova{#1}%
+ \def\skv@provb{\bool}%
+ % 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
+ \skv@commaact{#2}{%
+ \skvifdefinable##1{%
+ \csname new\expandafter\expandafter\expandafter\@gobble
+ \expandafter\string\skv@prova\endcsname##1%
+ }%
+ }%
+}
+\let\skvnewregisters\skvnewregister
+\skvnewregisters\toks{\skv@temptoks,\skv@toksa}
+
+% Sometimes we change \bgroup temporarily to avoid \futurelet confusing
+% it with explicit \bgroup character. The change does confuse \skvifnextchar
+% if we used \bgroup in \skvifnextchar. Hence let us use \skv@orig@bgroup
+% in \skvifnextchar:
+\let\skv@orig@bgroup\bgroup
+\let\skv@orig@egroup\egroup
+
+\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. \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\skv@nextseen\skv@simpleifnext
+}
+\def\skv@simpleifnext{%
+ \ifx\skv@nextseen\@sptoken
+ \let\skv@letnext\skv@simpleifn@xt
+ \else
+ \ifx\skv@nextseen\reserved@d
+ \let\skv@letnext\reserved@a
+ \else
+ \let\skv@letnext\reserved@b
+ \fi
+ \fi
+ \skv@letnext
+}
+\lowercase{\def\skv@simpleifn@xt} {%
+ \global\futurelet\skv@nextseen\skv@simpleifnext
+}
+
+% 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}%
+ }{%
+ % Test for \egroup, so that, eg, {\loggingall\LoadClass{article}}
+ % doesn't fail because of the closing brace:
+ \skvsimpleifnextchar\skv@orig@egroup{%
+ \skvsimpleifnextchar{#1}{#2}{#3}%
+ }{%
+ \skvifnextisouter{%
+ \skvsimpleifnextchar{#1}{#2}{#3}%
+ }{%
+ \skv@ifnextchar@a{#1}{#2}{#3}%
+ }%
+ }%
+ }%
+}
+\long\def\skv@ifnextchar@a#1#2#3#4{%
+ \edef\reserved@a{\skv@ifnextchar@b{#1}\skv@ifnextchar@b{#4}}%
+ \expandafter\ifx\reserved@a
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {#2}{#3}#4%
+}
+\long\def\skv@ifnextchar@b#1{%
+ \expandafter\skv@ifnextchar@c\string#1\relax\noboundary{#1}%
+}
+\long\def\skv@ifnextchar@c#1#2\noboundary#3{%
+ \ifx\relax#2%
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \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:
+%
+% Eg,
+% \def\macroa{\skvnewxtestopt\macrob{Mr.}}
+% \def\macrob[#1]#2{#1 #2}
+% \edef\testa{\expandafter\macroa\activespace{David Carlisle}}
+% \edef\testb{\macroa[Mr.]{Heiko Oberdiek}}
+%
+\long\def\skvnewxtestopt#1#2#3{%
+ % #3 will be seen as a space only if that space is active. But
+ % \skvifstrcmpTF will detokenize that space before comparison.
+ \skvifstrcmpTF{ }{#3}{%
+ \skvnewxtestopt#1{#2}%
+ }{%
+ \skvifstrcmpTF{#3}{[}%
+ {#1[}{\skvifntypeTF{#3}{#1[#2]#3}{#1[#2]{#3}}}%
+ }%
+}
+
+% Expandable \@ifnextchar:
+%
+% Eg,
+% \def\temp{\skvxifnextchar*{\def\x{T}}{\def\x{F}}}
+% \temp* (star seen) or \temp<some token> (star not seen)
+%
+% ** This can't be used to test the presence of explicit left brace.
+%
+\long\def\skvxifnextchar#1#2#3#4{%
+ % #4 will be seen as a space only if that space is active. But
+ % \skvifstrcmpTF will detokenize that space before comparison.
+ \skvifstrcmpTF{ }{#4}{%
+ \skvxifnextchar#1{#2}{#3}%
+ }{%
+ \skvifstrcmpTF{#4}{#1}{#2}{\skvifntypeTF{#4}{#3#4}{#3{#4}}}%
+ }%
+}
+
+\long\def\skvgobbleleadingspaces{\skvsimpleifnextchar x{}{}}
+\long\protected\def\skvstarorlong#1{%
+ \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}\skv@ehd
+ \fi
+ \fi
+ \ifcat$\detokenize{#2}$\else
+ \ifx#2p\expandafter\expandafter\expandafter\protected\fi
+ \fi
+ \l@ngrel@x\csname#1def\endcsname#3%
+}
+\def\skv@csdef@#1#2#3{%
+ \def\skv@prova{\skv@def@{#1}{#2}}%
+ \expandafter\skv@prova\csname#3\endcsname
+}
+\def\skv@redef@#1#2#3{%
+ \ifcat$\detokenize{#2}$\else
+ \ifx#2p\expandafter\expandafter\expandafter\protected\fi
+ \fi
+ \l@ngrel@x\csname#1def\endcsname#3%
+}
+\protected\def\skvrobustdef{\skvstarorlong{\skv@def@{}{p}}}
+\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}}}
+\skvrobustdef*\skvnewcsdef{\skvstarorlong{\skv@csdef@{}{}}}
+\skvrobustdef*\skvifplus#1{\skvifnextchar+{\@firstoftwo{#1}}}
+
+\skvrobustdef*\skvshowcs#1{%
+ \begingroup\expandafter\endgroup
+ \expandafter\show\csname#1\endcsname
+}
+\skvrobustdef*\skvcomment{%
+ \begingroup
+ \def\do##1{\catcode`##1=12\relax}%
+ \dospecials
+ \skv@endcomment
+}
+\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
+% might have put '=':
+\skvrobustdef*\skvnewlet#1{\skvifdefinable#1\relax\let#1 }
+\skvnewlet\skv@nil\relax
+\skvnewlet\skvrelax\relax
+\skvnewdef*\skv@relaxtoks{\relax}
+\skvnewdef*\skv@truetoks{true}
+\skvnewdef*\skv@falsetoks{false}
+\skvnewdef*\skv@nnil{\skv@nil}
+\skvnewdef\skv@car#1#2\car@nil{#1}
+\skvnewdef\skv@car@detok#1#2\car@nil{\detokenize{#1}}
+\skvnewdef\skv@removetonnil#1\skv@nnil{}
+\skvnewdef\skv@catchtonnil#1\skv@nnil{#1}
+\long\def\@gobblethree#1#2#3{}
+\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
+\skvnewdef*\skv@rej{^skv^}
+\skvnewdef*\skv@dotna{.na}
+\skvnewdef\skvafterfi#1\fi{\fi#1}
+\skvnewdef\skvafterfifi@inneriscond#1\fi#2\fi{\fi#1\fi}
+\skvnewdef\skvafterfifi#1\fi#2\fi{\fi\fi#1}
+\skvnewdef\skvafterelsei#1\else#2\fi{\fi#1}
+\skvnewlet\skvafterelse\skvafterelsei
+\skvnewdef\skvafterelseii#1\else#2\fi{\fi#2}
+\skvnewdef*\skv@simplearg{##1}
+\skvnewlet\skvsanitizemacro\@onelevel@sanitize
+% \skvaddtotoks{<token register>}{<token to add>}
+\skvrobustdef*\skvaddtotoks#1#2{#1\expandafter{\the#1#2}}
+\skvrobustdef*\skvoaddtotoks#1#2{#1\expandafter{\the\expandafter#1#2}}
+\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}}%
+ \expandafter\endgroup
+ \ifx\in@@\@empty\in@false\else\in@true\fi
+ }%
+ \in@@#2{\in@@}#1\in@@
+}
+\skvrobustdef*\skvcsnewif#1{%
+ \skvifstrcmpTF{#1}{x}{%
+ \skv@err{Redefining primitve '\@backslashchar ifx'?}\skv@ehd
+ }{%
+ \csname newif\expandafter\endcsname\csname if#1\endcsname
+ }%
+}
+\skvnewdef*\skv@zapornot#1{%
+ \if#1%
+ \expandafter\skvzapspaces
+ \else
+ \expandafter\@iden
+ \fi
+}
+\skvnewdef\skvzapspaces#1{\skv@zapspaces.#1 \zap@nil}
+\skvnewdef\skv@zapspaces#1 #2\zap@nil{%
+ \skvifblankTF{#2}{%
+ \@gobble#1%
+ }{%
+ \skv@zapspaces#1#2\zap@nil
+ }%
+}
+\skvnewdef\skvxzapspaces#1#2{%
+ \edef#2{.#1}%
+ \edef#2{\expandafter\skv@zapspaces#2 \zap@nil}%
+}
+% \skvifleadspaceTF{<toks>}{<true>}{<false>}
+\newcommand\skvifleadspaceTF[3]{%
+ \romannumeral\csname
+ @\skvifnullTF{#1}{second}{\iffalse{\fi\skv@ifleadspace.#1 x}}%
+ oftwo\endcsname{0 #2}{0 #3}%
+}
+\skvnewdef\skv@ifleadspace#1 {%
+ \expandafter\skvifnullTF\expandafter{\@gobble#1}{first}{second}%
+ \expandafter\@gobble\expandafter{\iffalse}\fi
+}
+
+% \skvifldspaceTF is faster than \skvifleadspaceTF.
+%
+% \skvifldspaceTF{ }{}{} gives <true> as desired.
+\begingroup
+\lccode`\&=0 \catcode`\&=7 \lccode`\!=0 \catcode`\!=8
+\lowercase{\endgroup
+ \skvnewdef\skvifldspaceTF#1{\skv@ifldspace!#1! &}
+ \skvnewdef\skv@ifldspace#1! #2&{\skvifblankFT{#2}}
+ \skvnewdef\skvtrimspace#1{\skv@trimspace@a.#1& &}
+ \skvnewdef\skv@trimspace@a#1 &{\skv@trimspace@b#1&}
+ \skvnewdef\skv@trimspace@b#1&#2{%
+ \unexpanded\expandafter{%
+ \romannumeral0%
+ \expandafter\skvifldspaceTF\expandafter{\@gobble#1}{%
+ \@gobble#1%
+ }{%
+ \expandafter\@space\@gobble#1%
+ }%
+ }%
+ }
+}
+\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}}%
+}
+\skvnewdef*\skvcsuse#1{%
+ \skvifcsname#1\then
+ \csname#1\expandafter\endcsname
+ \fi
+}
+\skvrobustdef*\skvcsdef#1{\expandafter\def\csname#1\endcsname}
+\skvrobustdef*\skvcsgdef#1{\expandafter\gdef\csname#1\endcsname}
+\skvrobustdef*\skvcsedef#1{\expandafter\edef\csname#1\endcsname}
+\skvrobustdef*\skvcsxdef#1{\expandafter\xdef\csname#1\endcsname}
+\skvnewdef\skvaftercsname#1#2{%
+ \expandafter\skvswap\expandafter{\csname#2\endcsname}{#1}%
+}
+\skvnewlet\skvaftercs\skvaftercsname
+\skvnewdef*\skvifdef#1\then{\if0\skvifdefTF{#1}{0}{1}}
+\skvnewdef*\skvifundef#1\then{\if0\skvifdefTF{#1}{1}{0}}
+% \skvifcsname x\then\def\x{T}\else\def\x{F}\fi
+\skvnewdef*\skvifcsname#1\then{\if0\skvifcsdefTF{#1}{0}{1}}
+\skvnewdef*\skvifdefTF#1{%
+ \skvifxTF{#1}\skv@undefined{%
+ \@secondoftwo
+ }{%
+ \ifx\relax#1%
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+ }%
+}
+\skvnewdef*\skvifdefFT#1{\skvifdefTF{#1}\@secondoftwo\@firstoftwo}
+\skvnewdef*\skvifcsdefTF#1{%
+ \skvifblankTF{#1}{%
+ \expandafter\@secondoftwo\@gobble
+ }{%
+ \ifcsname#1\endcsname
+ \expandafter\@firstofone
+ \else
+ \expandafter\expandafter\expandafter
+ \@secondoftwo\expandafter\@gobble
+ \fi
+ }{%
+ \expandafter\ifx\csname#1\endcsname\relax
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+ }%
+}
+\skvnewdef*\skvifcsdefFT#1{\skvifcsdefTF{#1}\@secondoftwo\@firstoftwo}
+% 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
+ first\else second\fi oftwo\endcsname
+}
+\skvnewdef*\skvifxFT#1#2{\skvifxTF{#1}{#2}\@secondoftwo\@firstoftwo}
+\skvnewdef*\skv@ghost{\@gobble\skv@ghost}
+\skvnewdef\skvifemptyTF#1{%
+ \ifx#1\@empty\skv@ghost
+ \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+}
+\skvnewdef\skvifcsemptyTF#1{\expandafter\skvifemptyTF\csname#1\endcsname}
+\skvnewdef\skvifdefemptyTF#1{%
+ \skvifblankTF{#1}\@secondoftwo{%
+ \skvifntypeTF{#1}{%
+ \skvifdefTF{#1}{\skvifxTF#1\@empty}{\@secondoftwo}%
+ }{%
+ \@secondoftwo
+ }%
+ }%
+}
+\begingroup
+% Keep lccode, in case the test occurs in a table:
+\lccode`\&=0 \catcode`\&=8
+\lowercase{\endgroup
+ \skvnewdef\skvifnullTF#1{%
+ \csname @\ifcat&\detokenize{#1}&first\else second\fi oftwo\endcsname
+ }
+ \skvnewdef\skviflacus#1\then{\ifcat&\detokenize{#1}&}
+}
+\skvnewdef\skvifblankTF#1{%
+ \expandafter\skvifnullTF\expandafter{\@gobble#1.}%
+}
+\skvnewdef\skvifblankFT#1{\skvifblankTF{#1}\@secondoftwo\@firstoftwo}
+
+\skvnewdef*\skvifboolTF#1{%
+ \skvifblankTF{#1}{%
+ \@secondoftwo
+ }{%
+ \skvifcsdefTF{if#1}{%
+ \csname @\csname if#1\endcsname
+ first\else second\fi oftwo\endcsname
+ }{%
+ \skv@err{Undefined boolean '#1'}\skv@ehd
+ }%
+ }%
+}
+\skvnewdef*\skvifboolFT#1{\skvifboolTF{#1}\@secondoftwo\@firstoftwo}
+% \skvifbool sw1\then <true> \else <false> \fi
+\skvnewdef*\skvifbool#1\then{\if0\skvifboolTF{#1}01}
+\skvnewdef*\skvifdefboolTF#1{%
+ \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
+ {\detokenize{#1}},}{,\detokenize{true,false},}%
+}
+\skvrobustdef*\skvxifboolvalTF#1{%
+ \begingroup
+ \edef\skv@prova{#1}%
+ \skvdespacecontent\skv@prova
+ \skvexpandtwoargs{\endgroup\skvifinTF}
+ {,\skvoxdetok\skv@prova,}{,\detokenize{true,false},}%
+}
+% Generate error if <toks> is not a valid boolean value, otherwise
+% execute #2:
+% \skvifboolvalT{<toks>}{<true>}
+\skvrobustdef*\skvifboolvalT#1#2{%
+ \skvxifinTF{,\expandafter\skvtrimspace\expandafter
+ {\detokenize{#1}},}{,\detokenize{true,false},}%
+ {#2}{\skv@badboolerr{#1}}%
+}
+% Convert bool value (true or false) to switch value (00 or 01):
+\skvrobustdef*\skvbooltoswitch#1#2{%
+ \begingroup
+ \def\reserved@a##1#1##2##3\skv@nil{%
+ \def#2{##2}%
+ \ifx#2\@nnil
+ \skv@err{Bad boolean value '#1' can't be
+ \MessageBreak converted to switch value}\@ehc
+ \fi
+ }%
+ \reserved@a true{00}false{01}#1{\@nil}\skv@nil
+ \skvaftergroupdef#2\endgroup
+}
+\skvrobustdef*\skv@badboolerr#1{%
+ \skv@err{Invalid boolean value '#1'; expected 'true' or 'false'}\skv@ehd
+}
+
+% Switches have values of either 00 or 01.
+
+% \skvifknobTF, unlike \skvifswitchTF, is for use with plain switches,
+% ie, switches that have no separate namespace.
+\skvnewdef*\skvifknobTF#1{%
+ \if\@nameuse{#1}\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+}
+\skvnewdef*\skvifknobFT#1{%
+ \if\@nameuse{#1}\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
+}
+% Switches and toggles have separate namespaces.
+\skvrobustdef*\skvnewswitches#1{%
+ \skvcommaloop{#1}\skv@prova{%
+ \skvifcsdefTF{skv@switch@\skv@prova}{%
+ \skv@err{Switch '\skvoxdetok\skv@prova' already exists}\skv@ehd
+ }{%
+ \skvcsdef{skv@switch@\skv@prova}{01}%
+ }%
+ }%
+}
+\skvnewlet\skvnewswitch\skvnewswitches
+\skvnewdef*\skvifswitchTF#1{%
+ \if
+ \skvifcsdefTF{skv@switch@#1}{%
+ \csname skv@switch@#1\endcsname
+ }{%
+ 01%
+ }%
+ \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+}
+\skvnewdef*\skvifdefswitchTF#1{%
+ \if\csname skv@switch@#1\endcsname
+ \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+}
+\skvrobustdef*\skvswitchtrue#1{%
+ \skvifcsdefTF{skv@switch@#1}{%
+ \skvcsdef{skv@switch@#1}{00}%
+ }{%
+ \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}'}\skv@ehd
+ }%
+}
+\skvrobustdef*\skvnewtog#1{%
+ \skvcommaloop{#1}\skv@prova{%
+ \skvifcsdefTF{skv@toggle@\skv@prova}{%
+ \skv@err{Switch '\skvoxdetok\skv@prova' already exists}\skv@ehd
+ }{%
+ \skvcslet{skv@toggle@\skv@prova}\@secondoftwo
+ }%
+ }%
+}
+\skvrobustdef*\skvdeftog#1{%
+ \skvcommaloop{#1}\skv@prova{%
+ \skvcslet{skv@toggle@\skv@prova}\@secondoftwo
+ }%
+}
+\skvnewdef*\skviftogTF#1{%
+ \skvifcsdefTF{skv@toggle@#1}{%
+ \csname skv@toggle@#1\endcsname
+ }{%
+ \@secondoftwo
+ }%
+}
+\skvnewdef*\skviftogFT#1{\skviftogTF{#1}\@secondoftwo\@firstoftwo}
+\skvnewdef*\skvifdeftogTF#1{\csname skv@toggle@#1\endcsname}
+\skvrobustdef*\skvsettogtrue#1{%
+ \skvifcsdefTF{skv@toggle@#1}{%
+ \skvcslet{skv@toggle@#1}\@firstoftwo
+ }{%
+ \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}'}\skv@ehd
+ }%
+}
+% Allow 'f' to stop the search for number:
+\skvnewdef\skvifcondTF#1\fi{%
+ \csname @#1first\else second\fi oftwo\endcsname
+}
+\skvnewdef\skvifcondFT#1\fi{\skvifcondTF{#1}\fi\@secondoftwo\@firstoftwo}
+% In case #1 isn't expandable. This is the difference between
+% \skvifcondTF and \skvifconditionTF.
+\skvnewdef\skvifconditionTF#1\fi{%
+ #1\relax
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+\skvnewdef*\skvifnumTF#1#{\skvifcondTF\ifnum#1\fi}
+\skvnewdef*\skvifdim#1#{\skvifcondTF\ifdim#1\fi}
+\skvnewdef*\skvifnumFT#1#{\skvifnumTF#1{\@secondoftwo}{\@firstoftwo}}
+\skvnewdef\skvalloftwo#1#2{#1#2}
+% If '#1' is a single, non-space and non-braced token:
+\skvnewdef\skvifntypeTF#1{%
+ \csname @\if0\skv@strcmp
+ {\skvexpandonce{\skvalloftwo#1{}{}}}{\unexpanded{#1{}}}%
+ first\else second\fi oftwo\endcsname
+}
+\skvnewdef\skvxifntypeTF{\skvexpandarg\skvifntypeTF}
+\skvrobustdef*\skvundef#1{\let#1\@undefined}
+\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{}}%
+}
+% \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
+ \skv@garbagelist
+ \def\skv@garbagelist{}%
+}
+
+\skvifdefTF\pdfstrcmp{%
+ \let\skv@strcmp\pdfstrcmp
+}{%
+ \RequirePackage{pdftexcmds}%
+ \skvifdefTF\pdf@strcmp{%
+ \let\skv@strcmp\pdf@strcmp
+ }{%
+ \skv@err{Neither '\string\pdfstrcmp' nor '\string\pdf@strcmp' exists}\skv@ehd
+ }%
+}
+\skvnewdef\skvifstrcmpTF#1#2{%
+ \csname @\ifnum\skv@strcmp{\detokenize{#1}}%
+ {\detokenize{#2}}=0first\else second\fi oftwo\endcsname
+}
+\skvnewdef*\skvifstrcmpFT#1#2{\skvifstrcmpTF{#1}{#2}\@secondoftwo\@firstoftwo}
+\skvnewdef\skvifstreq#1#2\then{%
+ \ifnum\skv@strcmp{\detokenize{#1}}{\detokenize{#2}}=\skvz@
+}
+\skvnewdef\skvoifstrcmpTF#1#2{%
+ \csname @\ifnum\skv@strcmp{\skvexpandonce{#1}}%
+ {\skvexpandonce{#2}}=0first\else second\fi oftwo\endcsname
+}
+\skvnewdef\skvxifstrcmpTF#1#2{%
+ \csname @\ifnum\skv@strcmp{#1}{#2}=0first\else
+ second\fi oftwo\endcsname
+}
+\skvrobustdef\skvcslet#1#2{\expandafter\let\csname#1\endcsname#2}
+\skvrobustdef\skvnewcslet#1{%
+ \skvifcsdefTF{#1}{%
+ \skv@err{Command '\skvnoexpandcs{#1}' already defined}\skv@ehd
+ }{%
+ \skvcslet{#1}%
+ }%
+}
+\skvrobustdef\skvletcs#1#2{%
+ \begingroup\expandafter\endgroup\expandafter
+ \let\expandafter#1\csname#2\endcsname
+}
+\skvrobustdef\skvnewletcs#1{%
+ \skvifdefTF{#1}{%
+ \skv@err{Command '\string#1' already defined}\skv@ehd
+ }{%
+ \skvletcs#1%
+ }%
+}
+\skvrobustdef*\skvcsletcs#1#2{%
+ \begingroup\expandafter\endgroup
+ \expandafter\let\csname#1\expandafter
+ \endcsname\csname#2\endcsname
+}
+\skvrobustdef\skvnewcsletcs#1{%
+ \skvifcsdefTF{#1}{%
+ \skv@err{Command '\skvnoexpandcs{#1}' already defined}\skv@ehd
+ }{%
+ \skvcsletcs{#1}%
+ }%
+}
+\skvrobustdef*\skvglobalizecs#1{%
+ \begingroup\expandafter\endgroup\expandafter
+ \global\expandafter\let\csname#1\expandafter\endcsname
+ \csname#1\endcsname
+}
+\skvrobustdef*\skvaftergroupdef#1\endgroup{%
+ \skvexpanded{\endgroup\skvcmdexit#1}%
+}
+\skvrobustdef*\skvaftergroupcsdef#1\endgroup{%
+ \skvexpanded{\endgroup\expandafter\skvcmdexit\csname#1\endcsname}%
+}
+
+% Taking commands and booleans out of a local group under \edef:
+\skvnewdef*\skvcmdexit#1{%
+ \skvifdefTF{#1}{%
+ \edef\noexpand#1{\noexpand\unexpanded{\skvexpandonce{#1}}}%
+ }{}%
+}
+\skvnewdef*\skvcsexit#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}
+\skvnewdef*\skv@cmdexitloop#1{%
+ \ifx\end#1\else\skvcmdexit{#1}\expandafter\skv@cmdexitloop\fi
+}
+\skvnewdef*\skvboolexit#1{%
+ \expandafter\noexpand\csname\expandafter\@gobblethree
+ \string#1#1true\else false\fi\endcsname
+}
+% \edef\x{\endgroup\skvboolexitloop{\ifboola\ifboolb}}:
+\skvnewdef*\skvboolexitloop#1{\skv@boolexitloop#1\end}
+\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
+ \ifx\protect\noexpand\skv@protect\unexpanded\fi
+ \ifx\protect\string\skv@protect\detokenize\fi
+ \relax\@firstofone
+}
+\skvnewdef*\skv@protect#1#2\relax\@firstofone{\fi#1}
+\skvnewdef*\skvunexpandable#1{\unexpanded{\skvprotect{#1}}}
+\skvrobustdef\skvifnotnil#1{%
+ \begingroup
+ \edef\skv@prova{\unexpanded{#1}}%
+ \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{%
+ % Raise error if #3 isn't an integer, \chardef'd or \countdef'd:
+ \begingroup
+ \count@#3\relax
+ \endgroup
+ \skvifdefTF#2{%
+ #1\edef#2{\the\numexpr#2+#3\relax}%
+ }{%
+ \skv@err{Number '\string#2' is not defined}\skv@ehd
+ }%
+}
+\skvrobustdef*\skvpushnumber#1{%
+ \skvifdefTF#1{%
+ \edef#1{\the\numexpr#1+1\relax}%
+ }{%
+ \def#1{0}%
+ }%
+}
+\skvrobustdef*\skvpopnumber#1{%
+ \skvifdefTF#1{%
+ \edef#1{\the\numexpr#1+1\relax}%
+ }{%
+ \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}}}
+
+% 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
+\lccode`\&=0 \catcode`\&=7
+\skvnewgdef\skvifbracedTF#1{%
+ \expandafter\skv@ifbraced@a\expandafter{%
+ \romannumeral-`\q\skv@ifbraced@b.#1& &%
+ }%
+}
+\skvnewgdef\skv@ifbraced@a#1{\skv@ifbraced@d#1\brace@nil{#1}}
+\skvnewgdef\skv@ifbraced@b#1 &{\skv@ifbraced@c#1&}
+\skvnewgdef\skv@ifbraced@c#1&#2{%
+ \expandafter\skvifldspaceTF\expandafter{\@gobble#1}%
+ {\@gobble#1}{\expandafter\@space\@gobble#1}%
+}
+\skvnewgdef\skv@ifbraced@d#1\brace@nil#2{%
+ \skvifstrcmpTF{#1}{#2}\@secondoftwo\@firstoftwo
+}
+\endgroup
+
+\skvnewdef\skvifbracedFT#1{\skvifbracedTF{#1}\@secondoftwo\@firstoftwo}
+
+% \skvstripouterbraces{<nr>}<cmd>
+% Example:
+% \def\x{{{{X}}}}
+% \skvstripouterbraces{2}\x
+\skvrobustdef*\skvstripouterbraces#1#2{%
+ \skvifemptyTF#2{}{%
+ \begingroup
+ \@tempcnta\skvz@
+ \expandafter\skv@stripouterbraces#2\strip@nil{#2}{#1}%
+ }%
+}
+\skvrobustdef*\skv@stripouterbraces#1\strip@nil#2#3{%
+ \edef\skv@prova{\unexpanded{#1}}%
+ \skvifxTF#2\skv@prova{%
+ \skvaftergroupdef#2\endgroup
+ }{%
+ \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\skvifescapedFT#1{\skvifescapedTF{#1}\@secondoftwo\@firstoftwo}
+\skvnewdef*\skvremovescape#1{\expandafter\@gobble\string#1}
+\skvnewdef*\skvgobblescape#1{%
+ \skvifblankTF{#1}{}{%
+ \skvifnumTF\escapechar>255{\string#1}{%
+ \skvifnumTF\escapechar<0{\string#1}{%
+ \skvifnumTF\escapechar=32{%
+ \expandafter\@gobblespace\string#1%
+ }{%
+ \skvremovescape{#1}%
+ }%
+ }%
+ }%
+ }%
+}
+\skvnewdef*\skvoxdetok#1{\detokenize\expandafter{#1}}
+\skvnewdef*\skvexpandonce#1{\unexpanded\expandafter{#1}}
+\skvnewlet\skvxonce\skvexpandonce
+\skvnewlet\skvxaft\expandafter
+\skvnewdef*\skvexpandtwice#1{%
+ \unexpanded\expandafter\expandafter\expandafter{#1}%
+}
+\skvnewdef*\skvexpandthrice#1{%
+ \unexpanded\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter\expandafter{#1}%
+}
+\skvnewdef*\skvnoexpandcs#1{\skvexpandonce{\csname#1\endcsname}}
+\skvnewdef*\skvexpandcsonce#1{%
+ \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}}}
+\skvrobustdef\skvexpandargonce#1#2{%
+ \skvexpanded{\unexpanded{#1}{\skvexpandonce{#2}}}%
+}
+\skvrobustdef*\skvexpandtwoargs#1#2#3{\skvexpanded{\unexpanded{#1}{#2}{#3}}}
+\skvrobustdef*\skvexpandtwoargsonce#1#2#3{%
+ \skvexpanded{\unexpanded{#1}{\skvexpandonce{#2}}{\skvexpandonce{#3}}}%
+}
+\skvrobustdef\skvexpandsecond#1#2{\skvexpanded{\unexpanded{#1}#2}}
+\skvrobustdef\skvexpandsecondonce#1#2{%
+ \skvexpanded{\unexpanded{#1}\skvexpandonce{#2}}%
+}
+\skvnewdef\skvexpandnext#1#2{\expandafter\skvswap\expandafter{#2}{#1}}
+\skvnewdef\skvexpandbracenext#1#2{%
+ \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{%
+ \skvtestifin{#1}{#2}%
+ \csname @\ifin@ first\else second\fi oftwo\endcsname
+}
+\skvrobustdef*\skvifinFT#1#2{\skvifinTF{#1}{#2}\@secondoftwo\@firstoftwo}
+\skvrobustdef*\skvxifinTF#1#2{\skvexpandtwoargs\skvifinTF{#1}{#2}}
+\skvrobustdef*\skvxifinFT#1#2{\skvxifinTF{#1}{#2}\@secondoftwo\@firstoftwo}
+\skvrobustdef*\skvifindetokTF#1#2#3{%
+ \skvexpandtwoargs\skvifinTF{#1\skvoxdetok{#2}#1}{#1\skvoxdetok{#3}#1}%
+}
+\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}%
+ \skv@tempa#1==\skv@kvsplit
+}
+\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@slashsplit{%
+ \endgroup#2%
+ }%
+ \skv@tempa#1/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^\skv@slashsplit
+}
+\skvrobustdef*\skv@oslashsplit#1{\skvexpbracenext\skv@slashsplit{#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
+ \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
+ }%
+}
+\skvrobustdef*\skvifmacroFT#1{\skvifmacroTF{#1}\@secondoftwo\@firstoftwo}
+% Note: If there're more than 1 alpha/Alpha character, both \skvifloweralpha
+% and \skvifupperalpha will return false. Hence double (or more) aphabetic
+% characters can't be auto-completed by \skvautocompletelist.
+\skvnewdef*\skvifloweralpha#1{%
+ \skvifblankTF{#1}{%
+ \@secondoftwo
+ }{%
+ \skvifntypeTF{#1}{%
+ \skvifnumTF`#1>96{%
+ \skvifnumTF`#1<123{\@firstoftwo}{\@secondoftwo}%
+ }{%
+ \@secondoftwo
+ }%
+ }{%
+ \@secondoftwo
+ }%
+ }%
+}
+\skvnewdef*\skvifupperalpha#1{%
+ \skvifblankTF{#1}{%
+ \@secondoftwo
+ }{%
+ \skvifntypeTF{#1}{%
+ \skvifnumTF`#1>64{%
+ \skvifnumTF`#1<91{\@firstoftwo}{\@secondoftwo}%
+ }{%
+ \@secondoftwo
+ }%
+ }{%
+ \@secondoftwo
+ }%
+ }%
+}
+% If there is a digit present in #1:
+\skvnewdef*\skvifdigitpresentTF#1{%
+ \skvifcondTF\if0\skvifblankTF{#1}{1}{\skv@ifdigitpresent#1\skv@nnil}\fi
+}
+\skvnewdef*\skv@ifdigitpresent#1{%
+ \skvifxTF#1\skv@nnil{%
+ 1%
+ }{%
+ \skvifnumTF`#1>47{%
+ \skvifnumTF`#1<58{%
+ 0\skv@removetonnil
+ }{%
+ \skv@ifdigitpresent
+ }%
+ }{%
+ \skv@ifdigitpresent
+ }%
+ }%
+}
+
+\skvnewdef*\skvifalldigitTF#1{%
+ \skvifcondTF\if0\skvifblankTF{#1}{1}{\skv@ifalldigit#1\skv@nnil}\fi
+}
+\skvnewdef*\skv@ifalldigit#1{%
+ \skvifxTF#1\skv@nnil{0}{%
+ \skvifnumTF`#1>47{%
+ \skvifnumTF`#1<58{%
+ \skv@ifalldigit
+ }{%
+ 1\skv@removetonnil
+ }%
+ }{%
+ 1\skv@removetonnil
+ }%
+ }%
+}
+
+\skvnewdef*\skvifalphapresentTF#1{%
+ \skvifcondTF\if0\skvifblankTF{#1}{1}{\skv@ifalphapresent#1\skv@nnil}\fi
+}
+\skvnewdef*\skv@ifalphapresent#1{%
+ \skvifxTF#1\skv@nnil{%
+ 1%
+ }{%
+ \skvifnumTF`#1>96{%
+ \skvifnumTF`#1<123{%
+ 0\skv@removetonnil
+ }{%
+ \skv@ifalphapresent
+ }%
+ }{%
+ \skv@ifalphapresent
+ }%
+ }%
+}
+\skvnewdef*\skvifAlphapresentTF#1{%
+ \skvifcondTF\if0\skvifblankTF{#1}{1}{\skv@ifAlphapresent#1\skv@nnil}\fi
+}
+\skvnewdef*\skv@ifAlphapresent#1{%
+ \skvifxTF#1\skv@nnil{%
+ 1%
+ }{%
+ \skvifnumTF`#1>64{%
+ \skvifnumTF`#1<91{%
+ 0\skv@removetonnil
+ }{%
+ \skv@ifAlphapresent
+ }%
+ }{%
+ \skv@ifAlphapresent
+ }%
+ }%
+}
+\skvnewdef*\skvifprimitiveTF#1{%
+ \expandafter\skv@ifprimitive\meaning#1\relax
+}
+\skvnewdef*\skv@ifprimitive#1#2\relax{%
+ \skvifcondTF\if#1\@backslashchar\fi{%
+ \skvifdigitpresentTF{#2}\@secondoftwo\@firstoftwo
+ }{%
+ \@secondoftwo
+ }%
+}
+
+\begingroup
+\catcode`\&=7
+\skvnewgdef*\skvdefregistertester#1#2{%
+ \begingroup
+ \def\x##1{\skvnoexpandcs{skv@\skvremovescape#1test@##1}}%
+ \edef\x{\endgroup
+ \def\noexpand#2####1{%
+ \unexpanded{\skvifxTF#1{##1}\@secondoftwo}{%
+ \unexpanded{\skvifprimitiveTF{##1}\@secondoftwo}%
+ {\noexpand\expandafter\x{a}\noexpand\meaning####1:&}%
+ }%
+ }%
+ \def\x{a}####1:####2&{\x{b}####1\string#1&}%
+ \def\x{b}####1\string#1####2&{\noexpand\skvifblankTF{####1}}%
+ }\x
+}
+\endgroup
+\skvdefregistertester\skip\skvifskipTF
+\skvdefregistertester\count\skvifcountTF
+\skvdefregistertester\dimen\skvifdimenTF
+\skvdefregistertester\toks\skviftoksTF
+
+% Converting units.
+% Examples:
+% \edef\x{\skvconvertunit{10pt}{mm}}
+% \edef\x{\skvconvertunit{1in}{bp}}
+\skvnewdef*\skvconvertunit#1#2{%
+ \strip@pt\dimexpr#1*\p@/\dimexpr1#2\relax\relax#2%
+}
+
+% If all the tokens are digits or arithmetic:
+\skvnewdef*\skvifallarithmeticTF#1{%
+ \begingroup
+ \skv@swatrue
+ \skvifdimensionable{#1}{}{%
+ \ifskv@isinteger\else
+ \def\do##1##2{%
+ \ifx\do##1\else
+ \skvifinTF{##1}{0123456789.+-*/()}{}{%
+ \skvifinTF{,##1##2,}
+ {,em,ex,in,pt,pc,cm,mm,dd,cc,nd,nc,bp,sp,}{}{%
+ \skv@swafalse
+ \def\do####1\skvrelax{}%
+ }%
+ }%
+ \expandafter\do
+ \fi
+ ##2%
+ }%
+ \do#1\do\skvrelax
+ \fi
+ }%
+ \expandafter\endgroup\ifskv@swa
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+
+\skvnewregister\bool{\ifskv@isinteger}
+
+% In case the argument of \skvifintegerTF containes \numexpr:
+\skvnewlet\skv@catch@nil\relax
+% \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}\skv@ehd
+ \fi
+ }%
+ \afterassignment\skv@prova\skv@cnta#2\relax\skv@catch@nil
+ \endgroup
+}
+\skvnewdef*\skv@validunit{em,ex,in,pt,pc,cm,mm,dd,cc,nd,nc,bp,sp}
+\skvrobustdef*\skv@catchremainder#1\skv@catch@nil{%
+ \endgroup\def\skv@elt{#1}%
+}
+\skvrobustdef*\skvifintegerTF#1{%
+ \begingroup
+ % Don't try '\numexpr0+#1' here:
+ \afterassignment\skv@catchremainder
+ \@tempcnta\numexpr0#1\relax\skv@catch@nil
+ \skvifxTF\skv@elt\@empty{%
+ \@firstoftwo
+ }{%
+ \skvifxTF\skv@elt\skv@relaxtoks\@firstoftwo\@secondoftwo
+ }%
+}
+\skvrobustdef\skvoifinteger{\skvexpbracenext\skvifintegerTF}
+
+% Test if a token #1 can be assigned to a \dimendef'd register. We assume
+% that #1 isn't a complicated expression and isn't padded with trailing
+% \relax's. A complicated expression will be something like
+%
+% 2pt+3ex-(3pt/4+1.45cc*3)
+%
+% which is much harder to parse and decide on.
+%
+% Examples:
+%
+% \skvifdimensionable{01}{\def\x{T}}{\def\x{F}}
+% \skvifdimensionable{01pt}{\def\x{T}}{\def\x{F}}
+% \skvifdimensionable{01abpt}{\def\x{T}}{\def\x{F}}
+% \skvifdimensionable\paperwidth{\def\x{T}}{\def\x{F}}
+% \skvifdimensionable{\skip0}{\def\x{T}}{\def\x{F}}
+% \skvifdimensionable{1.2pt}{\def\x{T}}{\def\x{F}}
+% \skvifdimensionable{1.2\relax pt}{\def\x{T}}{\def\x{F}}
+% \skvifdimensionable{1pt\relax\skvrelax}{\def\x{T}}{\def\x{F}}
+%
+\skvrobustdef\skvifdimensionable#1{%
+ \def\skv@dimunit{}%
+ % Does 'pt' mean 0pt or 1pt? Make it an invalid input:
+ \lowercase{\skvifindetokTF{,}{#1}}\skv@validunit{%
+ \skv@err{Illegal step '#1': no number found with it}\skv@ehd
+ }{}%
+ \skv@isintegerfalse
+ \skvifintegerTF{#1}{%
+ \skv@isintegertrue\@secondoftwo
+ }{%
+ \expandafter\skv@ifdimensionable\skv@elt\skv@catch@nil
+ }%
+}
+\skvrobustdef\skv@ifdimensionable#1#2\skv@catch@nil{%
+ \skvifxTF\relax#1{%
+ \skvifblankTF{#2}{%
+ \skv@isintegertrue\@secondoftwo
+ }{%
+ \expandafter\skv@findunit\skv@elt\skv@catch@nil
+ }%
+ }{%
+ \expandafter\skv@findunit\skv@elt\skv@catch@nil
+ }%
+}
+\skvrobustdef\skv@findunit#1#2#3\skv@catch@nil{%
+ \def\skv@provb{%
+ \ifx\relax#2%
+ \if\relax\detokenize{#3}\relax
+ \expandafter\expandafter\expandafter\@firstoftwo
+ \else
+ \expandafter\expandafter\expandafter\@secondoftwo
+ \fi
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ }%
+ \skvifstrcmpTF{.}{#1}{%
+ % In this case, #1 must have come with a trailing \relax.
+ % Remove it and re-start the test:
+ \def\skv@prova##1##2\relax\skv@catch@nil{%
+ \skvifdimensionable{##1##2}%
+ }%
+ \skv@prova#2#3\skv@catch@nil
+ }{%
+ % Check for a valid unit. May be a \dimendef'd token.
+ \skvifinTF{,#1,}{,\hsize,\vsize,}{%
+ \skv@provb
+ }{%
+ \skvifdimenTF{#1}{%
+ \skv@provb
+ }{%
+ \lowercase{\skvifindetokTF{,}{#1#2}}\skv@validunit{%
+ \def\skv@dimunit{#1#2}%
+ % Check if #3 has only one (leading) \relax:
+ \def\skv@prova##1##2##3\skv@catch@nil{%
+ \def\elt{##1}\def\skv@elt{##2}%
+ }%
+ \skv@prova#3\skv@quark\skv@quark\skv@catch@nil
+ \ifx\elt\skv@relaxtoks
+ \def\skv@prova{\skv@quark}%
+ \ifx\skv@elt\skv@prova
+ \expandafter\expandafter\expandafter\@firstoftwo
+ \else
+ % \skv@elt might contain \relax, but never mind; let us end
+ % the search here. The samething can be said of the tests in
+ % \skv@provb.
+ \expandafter\expandafter\expandafter\@secondoftwo
+ \fi
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ }{%
+ \@secondoftwo
+ }%
+ }%
+ }%
+ }%
+}
+
+% Evaluating a dimensionable expression.
+%
+% 1. This can't parse expressions containing both * and / in one component,
+% eg, in 3pt*3/2. But (3pt*3)/2 or (3pt/2)*3 will pass.
+%
+% Examples:
+%
+% \skvifdimexpr{2bp*3/2}{<T>}{<F>} : fails
+% \skvifdimexpr{1pt-2bp*3+(3cc-2ex)/2}{<T>}{<F>} : true
+% \skvifdimexpr{(1pt-2bp+(3cc-2ex)/2)*5}{<T>}{<F>} : true
+% \skvifdimexpr{1+(1pt-2bp+(3cc-2ex)/2)*5}{<T>}{<F>} : false
+%
+\skvrobustdef*\skvifdimexpr#1{%
+ \begingroup
+ \@tempcnta\skvz@
+ \skv@dimexpr@beg
+ \skv@dimexpr@bgroup#1(\skv@catch@nil
+ \skv@dimexpr@end
+ \skv@dimexpr@end@end
+}
+\skvrobustdef*\skv@dimexpr@beg{\begingroup\@tempcnta\skvz@}
+\skvrobustdef*\skv@dimexpr@end{%
+ \skv@dimexpr@end@end
+ \skv@dimexpr@true\skv@dimexpr@false
+}
+\skvrobustdef*\skv@dimexpr@end@end{%
+ \skvifnumTF\@tempcnta<\skvz@
+ {\endgroup\@secondoftwo}{\endgroup\@firstoftwo}%
+}
+\skvrobustdef*\skv@dimexpr@true{\advance\@tempcnta\skvz@}
+\skvrobustdef*\skv@dimexpr@false{\advance\@tempcnta\m@ne}
+\skvrobustdef*\skv@dimexpr@bgroup#1(#2\skv@catch@nil{%
+ \skv@dimexpr@egroup#1)\skv@catch@nil
+ \skvifblankTF{#2}{}{%
+ \skv@dimexpr@beg
+ \skv@dimexpr@bgroup#2\skv@catch@nil
+ }%
+}
+\skvrobustdef*\skv@dimexpr@egroup#1)#2\skv@catch@nil{%
+ \skv@dimexpr@plus#1+\skv@catch@nil
+ \skvifblankTF{#2}{}{%
+ \skv@dimexpr@end
+ \skv@dimexpr@egroup#2\skv@catch@nil
+ }%
+}
+\skvrobustdef*\skv@dimexpr@plus#1+#2\skv@catch@nil{%
+ \skv@dimexpr@minus#1-\skv@catch@nil
+ \skvifblankTF{#2}{}{\skv@dimexpr@plus#2\skv@catch@nil}%
+}
+\skvrobustdef*\skv@dimexpr@minus#1-#2\skv@catch@nil{%
+ \skvifblankTF{#1}{}{%
+ \skvifinTF{*}{#1}{%
+ \skvifinTF{/}{#1}{%
+ \skv@err{I can't parse this: both star (*) and slash
+ \MessageBreak (/) are in '#1'}\skv@ehd
+ }{%
+ \skvifblankTF{#1}{}{\skv@dimexpr@times#1*\skv@catch@nil}%
+ }%
+ }{%
+ \skvifblankTF{#1}{}{\skv@dimexpr@divide#1/\skv@catch@nil}%
+ }%
+ }%
+ \skvifblankTF{#2}{}{\skv@dimexpr@minus#2\skv@catch@nil}%
+}
+% Because of, eg, 2pt*3/2, the test for * is more subtle:
+\skvrobustdef*\skv@dimexpr@times#1*#2\skv@catch@nil{%
+ \skvifblankTF{#1}{}{%
+ \skvifdimensionable{#1}\skv@dimexpr@true\skv@dimexpr@false
+ }%
+ \skvifblankTF{#2}{}{%
+ \def\skv@prova##1*##2\skv@catch@nil{##1}%
+ \skvexpbracenext\skv@dimexpr@integer{\skv@prova#2\skv@catch@nil}%
+ }%
+}
+\skvrobustdef*\skv@dimexpr@divide#1/#2\skv@catch@nil{%
+ \skvifblankTF{#1}{}{%
+ \skvifdimensionable{#1}\skv@dimexpr@true\skv@dimexpr@false
+ }%
+ \skvifblankTF{#2}{}{%
+ \def\skv@prova##1/##2\skv@catch@nil{##1}%
+ \skvexpbracenext\skv@dimexpr@integer{\skv@prova#2\skv@catch@nil}%
+ }%
+}
+\skvrobustdef*\skv@dimexpr@integer#1{%
+ \skvifblankTF{#1}{}{%
+ \skvifintegerTF{#1}\skv@dimexpr@true\skv@dimexpr@false
+ }%
+}
+
+% \skvtrimlastparser{<parser>}<cmd>
+\skvrobustdef\skvtrimlastparser#1#2{%
+ \begingroup
+ % The following \relax will not be cat-12, so it won't appear in #2:
+ \def\skv@trim@a{%
+ \skvxifinTF{\detokenize{#1}\relax}{\skvoxdetok{#2}\relax}{%
+ \def\skv@trim@b####1#1\skv@normal@nil{%
+ \edef#2{\unexpanded{####1}}%
+ \skv@trim@a
+ }%
+ \expandafter\skv@trim@b#2\skv@normal@nil
+ }{}%
+ }%
+ \skv@trim@a
+ \skvaftergroupdef#2\endgroup
+}
+
+% Generate parameter characters from number #1 to #2:
+\skvnewdef*\skvgenerateparameters#1#2{%
+ \ifnum#1<\numexpr#2+1####\number#1%
+ \expandafter\skvgenerateparameters
+ \expandafter{\number\numexpr#1+1\expandafter}%
+ \expandafter{\number#2\expandafter}%
+ \fi
+}
+
+% Normalize non-parser-separated tokenlist. Preserve outer braces.
+% \edef\x{\skvtsvnormalize{ x y {z}}}
+\skvnewdef*\skvtsvnormalize#1{%
+ \unexpanded\expandafter
+ {\romannumeral-`\q\skv@tsvnormalize.#1 \skv@normal@nil}%
+}
+\skvnewdef*\skv@tsvnormalize#1 #2\skv@normal@nil{%
+ \skvifblankTF{#2}
+ {\expandafter\expandafter\expandafter\space
+ \expandafter\noexpand\@gobble#1}
+ {\skv@tsvnormalize#1#2\skv@normal@nil}%
+}
+
+
+% \skvnormalize{<csv/kv>}<parser>{<list>}<cmd>
+\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}\skv@ehd
+ \fi
+ \edef#4{\unexpanded{#3}}%
+ ##2[#2]#4%
+ }%
+ \skv@prova csv\skvcsvnormalize kv\skvkvnormalize#1\skv@nnil\skv@nil
+}
+\skvnewdef*\skv@switch@inkv{01}
+% \skvcsvnormalize[<parser>]<listcmd>
+\skvrobustdef*\skvcsvnormalize{\skv@testopt\skv@csvnormalize,}
+\skvrobustdef*\skv@csvnormalize[#1]#2{%
+ \begingroup
+ \skv@setupnormalizer{#1}%
+ \skvswitchfalse{inkv}%
+ \edef#2{\expandafter\skv@normalizelist\expandafter{#2}}%
+ \skvaftergroupdef#2\endgroup
+}
+% \skvcsvnormalizeset{<cmda>{<token1>,<cmdb2>{<token2>},...}
+\skvrobustdef*\skvcsvnormalizeset{\skv@testopt\skv@csvnormalizeset,}
+\skvrobustdef*\skv@csvnormalizeset[#1]#2{%
+ \begingroup
+ \toks@{}%
+ \skv@setupnormalizer{#1}%
+ \skvswitchfalse{inkv}%
+ \def\do##1##2,{%
+ \skvifnotnil{##1}{%
+ \edef##1{\skv@normalizelist{##2}}%
+ \skvexpanded{\toks@{\the\toks@\skvcmdexit##1}}%
+ \do
+ }%
+ }%
+ \do#2,\skv@nil,%
+ \expandafter\endgroup\the\toks@
+}
+% \skvkvnormalize{<kvlistcmd>}
+\skvrobustdef*\skvkvnormalize#1{%
+ \begingroup
+ \skv@setupnormalizer{,}%
+ \skvswitchtrue{inkv}%
+ % We put '\skv@kvguard' at the end of #1 to preserve any trailing '='.
+ % This can happen if a key has an empty value. But this can leave
+ % a trailing space or <parser> in #1. We remove the trailing space
+ % with \skvtrimspace.
+ \edef#1{\expandafter\skv@normalizelist\expandafter{#1\skv@kvguard}}%
+ \def\skv@kvnorm##1\skv@kvguard##2\skv@normal@nil{%
+ \skv@parserequalerr##1##2,=\skv@normal@nil
+ \edef#1{\skvtrimspace{##1##2}}%
+ \skvtrimlastparser{,}#1%
+ }%
+ \expandafter\skv@kvnorm#1\skv@normal@nil
+ \skvaftergroupdef#1\endgroup
+}
+
+\begingroup
+\catcode`\~=13 \catcode`\!=13
+\skvrobustgdef\skv@setupnormalizer#1{%
+ \begingroup
+ \lccode`\~=`#1 \lccode`\!=`\=
+ \lowercase{\endgroup
+ \def\skv@normalizelist##1{%
+ \unexpanded\expandafter{\romannumeral-`\q
+ \skv@activeparser#1##1#1~\skv@normal@nil}%
+ }%
+ \def\skv@activeparser##1~##2\skv@normal@nil{%
+ \skvifblankTF{##2}{%
+ \skvifdefswitchTF{inkv}{%
+ \skv@activeequal##1!\skv@normal@nil
+ }{%
+ \skv@spaceparser##1 #1\skv@normal@nil
+ }%
+ }{%
+ \skv@activeparser##1#1##2\skv@normal@nil
+ }%
+ }%
+ \def\skv@activeequal##1!##2\skv@normal@nil{%
+ \skvifblankTF{##2}{%
+ \skv@spaceparser##1 #1\skv@normal@nil
+ }{%
+ \skv@activeequal##1=##2\skv@normal@nil
+ }%
+ }%
+ }%
+ \def\skv@spaceparser##1 #1##2\skv@normal@nil{%
+ \skvifblankTF{##2}{%
+ \skv@parserspace##1#1 \skv@normal@nil
+ }{%
+ \skv@spaceparser##1#1##2\skv@normal@nil
+ }%
+ }%
+ \def\skv@parserspace##1#1 ##2\skv@normal@nil{%
+ \skvifblankTF{##2}{%
+ \skvifdefswitchTF{inkv}{%
+ \skv@spaceequal##1 =\skv@normal@nil
+ }{%
+ \skv@doubleparser##1#1#1\skv@normal@nil
+ }%
+ }{%
+ \skv@parserspace##1#1##2\skv@normal@nil
+ }%
+ }%
+ \def\skv@spaceequal##1 =##2\skv@normal@nil{%
+ \skvifblankTF{##2}{%
+ \skv@equalspace##1= \skv@normal@nil
+ }{%
+ \skv@spaceequal##1=##2\skv@normal@nil
+ }%
+ }%
+ \def\skv@equalspace##1= ##2\skv@normal@nil{%
+ \skvifblankTF{##2}{%
+ \skv@doubleparser##1#1#1\skv@normal@nil
+ }{%
+ \skv@equalspace##1=##2\skv@normal@nil
+ }%
+ }%
+ \def\skv@doubleparser##1#1#1##2\skv@normal@nil{%
+ \skvifblankTF{##2}{%
+ \skvifdefswitchTF{inkv}{%
+ \skv@doubleequal##1==\skv@normal@nil
+ }{%
+ \skvifblankTF{##1}{}{%
+ \skv@remleadparser##1\skv@normal@nil
+ }%
+ }%
+ }{%
+ \skv@doubleparser##1#1##2\skv@normal@nil
+ }%
+ }%
+ \def\skv@doubleequal##1==##2\skv@normal@nil{%
+ \skvifblankTF{##2}{%
+ \skvifblankTF{##1}{}{%
+ \skv@remleadparser##1\skv@normal@nil
+ }%
+ }{%
+ \skv@doubleequal##1=##2\skv@normal@nil
+ }%
+ }%
+ \def\skv@remleadparser#1##1\skv@normal@nil{%
+ \expandafter\space\noexpand##1%
+ }%
+ \def\skv@parserequalerr##1#1=##2\skv@normal@nil{%
+ \skvifblankTF{##2}{}{%
+ \skv@err{There is '#1=' in your key-value list}\skv@ehd
+ }%
+ }%
+}
+\endgroup
+
+% Define a special parser normalizer that doesn't replace double parsers
+% with single parser, because a double parser might mean an intentionally
+% missing token/property of a key:
+\begingroup
+\catcode`\~=13
+\skvrobustgdef*\skvdefinekeepdoubleparsernormalizer#1#2{%
+ \begingroup
+ \uccode`\~=`#1
+ \uppercase{\endgroup
+ \long\def#2##1{%
+ \unexpanded\expandafter{\romannumeral-`\q
+ \skv@keepdouble@activeparser##1~\skv@normal@nil}%
+ }%
+ \long\def\skv@keepdouble@activeparser##1~##2\skv@normal@nil{%
+ \skvifblankTF{##2}
+ {\skv@keepdouble@spaceparser##1 #1\skv@normal@nil}
+ {\skv@keepdouble@activeparser##1#1##2\skv@normal@nil}%
+ }%
+ }%
+ \long\def\skv@keepdouble@spaceparser##1 #1##2\skv@normal@nil{%
+ \skvifblankTF{##2}
+ {\skv@keepdouble@parserspace##1#1 \skv@normal@nil}
+ {\skv@keepdouble@spaceparser##1#1##2\skv@normal@nil}%
+ }%
+ \long\def\skv@keepdouble@parserspace##1#1 ##2\skv@normal@nil{%
+ \skvifblankTF{##2}
+ {\skvifblankTF{##1}{}{\expandafter\space\noexpand##1}}
+ {\skv@keepdouble@parserspace##1#1##2\skv@normal@nil}%
+ }%
+}
+\endgroup
+
+\skvdefinekeepdoubleparsernormalizer{/}\skvkeepdoubleslashnormalize
+
+% \skvmacnormalize[<parser>]<listcmd>
+\skvrobustdef*\skvmacnormalize{\skv@testopt\skv@macnormalize,}
+\skvrobustdef*\skv@macnormalize[#1]#2{%
+ \begingroup
+ \skvsetupmacroparsernormalizer{#1}%
+ \edef#2{\expandafter\skvmacroparsernormalize\expandafter{#2}}%
+ \skvaftergroupdef#2\endgroup
+}
+% This is for normalizing lists like {x\\ y\\\\ z}, where \\ is
+% a control sequence. Such parsers may be commands but we don't
+% expect them to be active characters.
+%
+% Example:
+%
+% \skvsetupmacroparsernormalizer{\\}
+% \edef\x{\skvmacroparsernormalize{x\\ y\\\\ z}}
+%
+\skvrobustdef*\skvsetupmacroparsernormalizer#1{%
+ \long\def\skvmacroparsernormalize##1{%
+ \unexpanded\expandafter{\romannumeral-`\q
+ \skv@mac@spaceparser##1 #1\skv@normal@nil}%
+ }%
+ \long\def\skv@mac@spaceparser##1 #1##2\skv@normal@nil{%
+ \skvifblankTF{##2}
+ {\skv@mac@parserspace##1#1 \skv@normal@nil}
+ {\skv@mac@spaceparser##1#1##2\skv@normal@nil}%
+ }%
+ \long\def\skv@mac@parserspace##1#1 ##2\skv@normal@nil{%
+ \skvifblankTF{##2}
+ {\skv@mac@doubleparser##1#1#1\skv@normal@nil}
+ {\skv@mac@parserspace##1#1##2\skv@normal@nil}%
+ }%
+ \long\def\skv@mac@doubleparser##1#1#1##2\skv@normal@nil{%
+ \skvifblankTF{##2}{ ##1}
+ {\skv@mac@doubleparser##1#1##2\skv@normal@nil}%
+ }%
+}
+% \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
+ \def\skv@prova##1{\skvremovescape{##1}@skv@\romannumeral#3}%
+ \def\do##1{\let\noexpand##1\skvnoexpandcs{\skv@prova{##1}}}%
+ \skvifcsdefTF{\skvremovescape{#1}@skv@stack}{}{%
+ \skvcsdef{\skvremovescape{#1}@skv@stack}{}%
+ }%
+ \skvcsxdef{\skvremovescape{#1}@skv@stack}{%
+ #2{\skvexpandcsonce{\skvremovescape{#1}@skv@stack}}%
+ }%
+ \def\do##1{\let\skvnoexpandcs{\skv@prova{##1}}\noexpand##1}%
+ \skvexpanded{\endgroup#2}%
+}
+% \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}\skv@ehd
+ \fi
+ }{%
+ \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}%
+ \expandafter\skv@provb\skv@prova
+ \skvgadvanceno#2\m@ne
+}
+
+\chardef\skv@stackdepthlimit=6\relax
+% #1=stack (a macro), #2=list, #3=max depth
+\skvrobustdef*\skvbuildmacrostack#1#2#3{%
+ \begingroup
+ \escapechar92\relax
+ \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%
+ \skvnoexpandcs{\skvremovescape{##1}@skv@\romannumeral\@tempcnta}%
+ }%
+ \def\skv@loop{%
+ \advance\@tempcnta\@ne
+ % Don't use \ifnum here, because #2 may contain booleans.
+ \skvifnumTF\@tempcnta<\numexpr#3+1\relax{%
+ \edef#1{\skvexpandonce#1.\romannumeral\@tempcnta.{#2}}%
+ \skv@loop
+ }{}%
+ }%
+ \skv@loop
+ \skvaftergroupdef#1\endgroup
+}
+\skvrobustdef*\skvpushstate#1#2{\skv@pushorpopstate{#1}{#2}{+}}
+\skvrobustdef*\skvpopstate#1#2{\skv@pushorpopstate{#1}{#2}{-}}
+% #1: stack (a macro) as built by \skvbuildmacrostack
+% #2: depth counter (macro-defined)
+% #3: stack direction (+/-)
+\skvrobustdef*\skv@pushorpopstate#1#2#3{%
+ \if+#3\relax
+ \skvgadvanceno#2\@ne
+ \def\skv@elt##1##2{\let##2=##1}%
+ \else
+ \ifnum#2<\@ne
+ \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}\skv@ehd
+ \fi
+ \def\skv@prova##1{%
+ \def\skv@prova####1.##1.####2####3\skv@nil{####2}%
+ \expandafter\skv@prova#1\skv@nil
+ }%
+ \expandafter\skv@prova\expandafter{\romannumeral#2}%
+ \let\skv@elt\relax
+ \if-#3\skvgadvanceno#2\m@ne\fi
+}
+
+\skvrobustdef*\skvnewbools{\skv@testopt\skv@newbools{}}
+\skvrobustdef*\skv@newbools[#1]#2{%
+ \begingroup
+ \toks@{}%
+ \def\skv@prova{#2}%
+ \skvcsvnormalize\skv@prova
+ \def\do##1,{%
+ \ifx\do##1\else
+ \skvifcsdefTF{if#1##1}{%
+ \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}%
+ }%
+ \expandafter\do
+ \fi
+ }%
+ \expandafter\do\skv@prova,\do,%
+ \expandafter\endgroup\the\toks@
+}
+
+% 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@]{%
+ inclass,inset,viarootofsetkeys,processvalueaslist,st,cl,pl,kf,inpox,inopt,%
+ inprepo,tracingkeys,tempsw,swa,verbose,intry,insa,success,inoptionsec,%
+ inreservedhandler,ignorepointers,addslots@appending%
+}
+
+\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
+ \toks@{}%
+ \def\skv@prova{#2}%
+ \skvcsvnormalize\skv@prova
+ \def\do##1,{%
+ \ifx\do##1\else
+ \skvifcsdefTF{#1##1}{%
+ \skv@err{Counter '\skvnoexpandcs{#1##1}' already exists}\skv@ehd
+ }{%
+ \toks@\expandafter{\the\expandafter\toks@
+ \csname newcount\expandafter\endcsname\csname#1##1\endcsname}%
+ }%
+ \expandafter\do
+ \fi
+ }%
+ \expandafter\do\skv@prova,\do,%
+ \expandafter\endgroup\the\toks@
+}
+\skvnewcounts[skv@]{tempcnt,cnta}
+% \skvnewnumbers[<optional prefix>]{<name list>}
+\skvrobustdef*\skvnewnumbers{\skv@testopt\skv@newnumbers{}}
+\skvrobustdef*\skv@newnumbers[#1]#2{%
+ \begingroup
+ \toks@{}%
+ \def\skv@prova{#2}%
+ \skvcsvnormalize\skv@prova
+ \def\do##1,{%
+ \ifx\do##1\else
+ \skvifcsdefTF{#1##1}{%
+ \skv@err{Number '\skvnoexpandcs{#1##1}' already exists}\skv@ehd
+ }{%
+ \toks@\expandafter{\the\expandafter\toks@
+ \expandafter\def\csname#1##1\endcsname{0}}%
+ }%
+ \expandafter\do
+ \fi
+ }%
+ \expandafter\do\skv@prova,\do,%
+ \expandafter\endgroup\the\toks@
+}
+\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}
+
+% A fast key parsing scheme originally designed for \newforeach loop.
+%
+% \skvquickkeys.define{<family>}[<hp>]{<list>}
+% \skvquickkeys.set{<family>}[<na>]{<kvlist>}
+%
+% 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:
+%
+% {<keya-1,...,keya-n>}/{<default>}/{<callback>}/{<choice list>}/{<arg>}
+% ;...;
+% {<keyb-1,...,keyb-n>}/{<default>}/{<callback>}/{<choice list>}/{<arg>}
+%
+% Here, keys key1 and key2 will have the same default value, callback,
+% choice list and argument pattern.
+%
+% 5. The special keys '.exec' and '.exec code' will simply execute the
+% code <default>, without defining anything.
+% 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:
+% \skvquickkeys.define{fam}[mp@]{%
+% keya/true/\def\x##1{#1*##1}/true,false;
+% keyb;
+% keyc,keyd/aaa+bbb/\def\x##1{#1*##1*#2}/.na/#1+#2;
+% }
+%
+\skvnewdef*\skv@ifstrrejorempty#1{%
+ \skvifstrcmpTF{#1}{^skv^}{%
+ \@firstoftwo
+ }{%
+ \skvifblankTF{#1}%
+ }%
+}
+\skvnewdef*\skv@ifstrrejordotna#1{%
+ \skvifstrcmpTF{#1}{^skv^}{%
+ \@firstoftwo
+ }{%
+ \skvifstrcmpTF{#1}{.na}%
+ }%
+}
+\skvnewdef*\skv@ifstrnut#1{%
+ \skvifstrcmpTF{#1}{^skv^}{%
+ \@firstoftwo
+ }{%
+ \skvifstrcmpTF{#1}{.na}{%
+ \@firstoftwo
+ }{%
+ \skvifblankTF{#1}%
+ }%
+ }%
+}
+\skvnewdef*\skv@ifcmdrejorempty#1{%
+ \skvifxTF#1\skv@rej{%
+ \@firstoftwo
+ }{%
+ \skvifemptyTF#1%
+ }%
+}
+\skvnewdef*\skv@ifcmdrejordotna#1{%
+ \skvifxTF#1\skv@rej{%
+ \@firstoftwo
+ }{%
+ \skvifxTF#1\skv@dotna
+ }%
+}
+\skvnewdef*\skv@ifcmdnut#1{%
+ \skvifxTF#1\skv@rej{%
+ \@firstoftwo
+ }{%
+ \skvifxTF#1\skv@dotna{%
+ \@firstoftwo
+ }{%
+ \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*\skvquickkeys#1#{%
+ \edef\skv@tempa{\skvtrimspace{#1}}%
+ \skvxifstrcmpTF{\skvexpandonce\skv@tempa}{.define}{%
+ \begingroup\endlinechar\m@ne
+ \skv@defquickkeys
+ }{%
+ \skvxifstrcmpTF{\skvexpandonce\skv@tempa}{.set}{%
+ \skv@setquickkeys
+ }{%
+ \skvxifstrcmpTF{\skvexpandonce\skv@tempa}{.preset}{%
+ \skv@presetquickkeys
+ }{%
+ \skv@err{Unknown task for \string\skvquickkeys}\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}}%
+ \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}}%
+ }%
+ }%
+ }%
+ }%
+ }%
+}
+
+% \skvquickkeys.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}
+
+% \skvquickkeys.set{<family>}[<na>]{<kvlist>}
+
+\skvrobustdef*\skv@setquickkeys#1{\skv@testopt{\skv@setquickkeys@a{#1}}{}}
+\skvrobustdef*\skv@setquickkeys@a#1[#2]#3{%
+ \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@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{\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 '\skv@qkeysfam/##1'}\skv@ehd
+ }%
+ }{%
+ \skvcsedef{\skv@qkeysfam/##1/qkeys.val}{\unexpanded{##2}}%
+ }%
+ \skvletcs\skv@tempval{\skv@qkeysfam/##1/qkeys.val}%
+ \skvletcs\reserved@a{\skv@qkeysfam/##1/qkeys.chc}%
+ \skvifdefTF\reserved@a{%
+ \skvxifinTF{,\skvoxdetok\skv@tempval,}{,\skvoxdetok\reserved@a,}{}{%
+ \skv@err{Value '\skvoxdetok\skv@tempval' for key '##1'
+ \MessageBreak is not in prescribed list
+ \MessageBreak '\skvoxdetok\reserved@a'}\skv@ehd
+ }%
+ }{}%
+ \skvifcsdefTF{\skv@qkeysfam/##1/qkeys.arg}{%
+ \skvletcs\skv@argpattern{\skv@qkeysfam/##1/qkeys.arg}%
+ }{%
+ \let\skv@argpattern\skv@simplearg
+ }%
+ \skvletcs\skv@callback{\skv@qkeysfam/##1/qkeys.cbk}%
+ \expandafter\expandafter\expandafter\def\expandafter\expandafter
+ \expandafter\reserved@a\expandafter\skv@argpattern\expandafter
+ \quickkeyseov\expandafter{\skv@callback}%
+ \expandafter\reserved@a\skv@tempval\quickkeyseov
+ }%
+ \def\skv@setqkeys@b##1=##2=##3\skv@setqkeys@nil{%
+ \skvxifinTF{,\detokenize{##1},}{,\skvoxdetok\skv@qkeysna,}{}{%
+ \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
+ }%
+ }%
+ \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\skvquickkeys.set' can't be nested in a preset
+ \MessageBreak key's callback: this will cause a cyclic call
+ \MessageBreak to '\string\skvquickkeys.set'}\skv@ehd
+}
+
+% \skvinitializequickkeys{<fam>}[<na>]{<kvlist>}
+\skvrobustdef*\skvinitializequickkeys#1{%
+ \skv@testopt{\skv@initializequickkeys@a{#1}}{}%
+}
+\skvrobustdef*\skv@initializequickkeys@a#1[#2]#3{%
+ \skvindeftrue
+ \skv@setquickkeys{#1}[#2]{#3}%
+ \skvindeffalse
+}
+
+\input skeyval-for
+
+% \skvifcase<comparator>{<teststr>}
+% {<cases>}
+% \elsedo
+% {<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}
+% {a}{do a}
+% {b}{do b}
+% {c}{do c}
+% \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}%
+ }%
+}
+\skvnewdef\skv@ifcase@a#1#2#3{\skv@ifcase{#1}{#2}}
+\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.
+%
+% Example:
+%
+% \skvifexprTF{%
+% not ( expr { \skvifdefTF\xa } and expr { \skvifemptyTF\xa } )
+% or ( expr { \skvifboolTF{@tempswa} } or expr { \skvifxTF\xa\xb } )
+% }{%
+% \def\x{T}
+% }{%
+% \def\x{F}
+% }
+\skvnewnumbers[skv@]{exprcnt}
+\skvrobustdef*\skvifexprTF#1{%
+ \begingroup
+ \def\skv@expr@neg{01}%
+ \skvsetno\skv@exprcnt\skvz@
+ \skv@expr@beg
+ \skv@expr@bgroup#1(\skv@expr@nil
+ \skv@expr@end
+ \skv@expr@end@end
+}
+\skvrobustdef*\skv@expr@beg{%
+ \begingroup
+ \def\skv@expr@neg{01}%
+ \skv@exprcnt\skvz@
+}
+\skvrobustdef*\skv@expr@end{%
+ \skv@expr@end@end\skv@expr@true\skv@expr@false
+}
+\skvrobustdef*\skv@expr@end@end{%
+ \expandafter\endgroup\csname @\ifnum\skv@exprcnt<\skvz@
+ second\else first\fi oftwo\endcsname
+}
+\skvrobustdef*\skv@expr@true{%
+ \skvadvanceno\skv@exprcnt{\if\skv@expr@neg\m@ne\else\skvz@\fi}%
+ \def\skv@expr@neg{01}%
+}
+\skvrobustdef*\skv@expr@false{%
+ \skvadvanceno\skv@exprcnt{\if\skv@expr@neg\skvz@\else\m@ne\fi}%
+ \def\skv@expr@neg{01}%
+}
+\skvrobustdef\skv@expr@bgroup#1(#2\skv@expr@nil{%
+ \skv@expr@egroup#1)\skv@expr@nil
+ \skvifblankTF{#2}{}{%
+ \skv@expr@beg
+ \skv@expr@bgroup#2\skv@expr@nil
+ }%
+}
+\skvrobustdef\skv@expr@egroup#1)#2\skv@expr@nil{%
+ \skv@expr@and#1and\skv@expr@nil
+ \skvifblankTF{#2}{}{%
+ \skv@expr@end
+ \skv@expr@egroup#2\skv@expr@nil
+ }%
+}
+\skvrobustdef\skv@expr@and#1and#2\skv@expr@nil{%
+ \skv@expr@or#1or\skv@expr@nil
+ \skvifblankTF{#2}{}{%
+ \skv@exprcnt\ifnum\skv@exprcnt<\skvz@\m@ne\else\skvz@\fi
+ \skv@expr@and#2\skv@expr@nil
+ }%
+}
+\skvrobustdef\skv@expr@or#1or#2\skv@expr@nil{%
+ \skv@expr@not#1not\skv@expr@nil
+ \skvifblankTF{#2}{}{%
+ \skv@exprcnt\ifnum\skv@exprcnt<\skvz@\skvz@\else\@ne\fi
+ \skv@expr@or#2\skv@expr@nil
+ }%
+}
+\skvrobustdef\skv@expr@not#1not#2\skv@expr@nil{%
+ \skv@expr@do#1expr\skv@expr@nil
+ \skvifblankTF{#2}{}{%
+ \def\skv@expr@neg{00}%
+ \skv@expr@not#2\skv@expr@nil
+ }%
+}
+\skvrobustdef\skv@expr@do#1expr#2\skv@expr@nil{%
+ \skvifblankTF{#1}{}{%
+ \skv@err{Invalid \noexpand\skvifexprTF test expression}
+ {The handicapped test part is: '\detokenize{#1}'}%
+ }%
+ \skvifblankTF{#2}{}{\skv@expr@do@a#2\skv@expr@nil}%
+}
+\skvrobustdef\skv@expr@do@a#1#2\skv@expr@nil{%
+ \ignorespaces#1\skv@expr@true\skv@expr@false
+ \skv@expr@do#2\skv@expr@nil
+}
+
+\skvnewdef\skvwhileexpr#1\do#2{%
+ \skvifcondTF{#1}\fi{#2\skvwhileexpr{#1}\do{#2}}{}%
+}
+
+\skvbuildmacrostack\skv@keystate{%
+ \do\skvcurrentprefix\do\skv@fams\do\skvcurrentfamily
+ \do\skvcurrentkey\do\skv@header\do\skvcurrentpath\do\skv@na
+ \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@inprepo\do\skv@pathdo\do\skv@rmkeys
+ \do\ifskv@viarootofsetkeys\do\skv@currpref\do\skv@currfam
+}\skv@stackdepthlimit
+
+\skvbuildmacrostack\skv@dirkeys@state{%
+ \do\dirkeys@pathlist\do\dirkeys@holderprefixtoks\do\dirkeys@parser
+ \do\dirkeys@unknownkeysmacro\do\ifdirkeys@saveunknownkeys
+ \do\ifindirectkeys\do\ifskvdfk@initialize\do\ifskvdfk@saveinitialvalues
+}\skv@stackdepthlimit
+
+\skvrobustdef\skvappto#1#2{\edef#1{\skvexpandonce{#1}\unexpanded{#2}}}
+\skvrobustdef\skvxappto#1#2{\edef#1{\skvexpandonce{#1}#2}}
+\skvrobustdef\skvgappto#1#2{\xdef#1{\skvexpandonce{#1}\unexpanded{#2}}}
+\skvrobustdef\skvxgappto#1#2{\xdef#1{\skvexpandonce{#1}#2}}
+\skvrobustdef\skvappendtomacro{\skv@testst{\skv@appendtomacro{app}{e}}}
+\skvrobustdef\skvgappendtomacro{\skv@testst{\skv@appendtomacro{app}{x}}}
+\skvrobustdef\skvprependtomacro{\skv@testst{\skv@appendtomacro{pre}{e}}}
+\skvrobustdef\skvgprependtomacro{\skv@testst{\skv@appendtomacro{pre}{x}}}
+\skvrobustdef\skv@appendtomacro#1#2#3#4{%
+ \skvifescapedTF{#3}{%
+ \@nameuse{#2def}#3{%
+ \skvifstrcmpTF{#1}{app}{%
+ \skvifdefTF#3{\skvexpandonce#3}{}%
+ \skvifdefboolTF{skv@tempst}\skvexpandonce\unexpanded{#4}%
+ }{%
+ \skvifdefboolTF{skv@tempst}\skvexpandonce\unexpanded{#4}%
+ \skvifdefTF#3{\skvexpandonce#3}{}%
+ }%
+ }%
+ }{%
+ \skv@err{Token '\detokenize{#3}' is not escaped}\skv@ehd
+ }%
+}
+
+% \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{\skvaddlist#1#2#3}}
+% \skvaddtolist[<parser>]{<listcmd>}{<newitem>}
+\skvrobustdef*\skvaddtolist{\skv@teststopt{\skv@addtolist{}},}
+\skvrobustdef*\skvgaddtolist{\skv@teststopt{\skv@addtolist{\global}},}
+\skvrobustdef\skv@addtolist#1[#2]#3#4{%
+ #1\edef#3{%
+ \skvifdefTF#3{%
+ \skvifemptyTF#3{}{\skvexpandonce#3#2}%
+ }{}%
+ \skvifdefboolTF{skv@tempst}\skvexpandonce\unexpanded{#4}%
+ }%
+}
+% \skv@declarefilter{<filter.type>}
+\skvrobustdef*\skv@declarefilter#1{%
+ \edef\skv@filter##1##2{%
+ \skvifblankTF{#1}{\let##2=##1}{%
+ \skvifxTF#1\relax{\let##2=##1}{%
+ \skvifstrcmpTF{#1}\nofilter{\let##2=##1}{%
+ \unexpanded{#1}{##1}{##2}%
+ }%
+ }%
+ }%
+ }%
+}
+
+% \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{#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#3%
+ \let#3\@empty
+ \skvdolist*{#1}\skv@mergc\skv@mergc{%
+ \skv@filter\skv@mergc\skv@mergd
+ \ifx\skv@mergb\skv@mergd
+ \@tempswafalse
+ \edef#3{\skvaddlist#1#3#2{\skv@merga}}%
+ \else
+ \edef#3{\skvaddlist#1#3#2{\skv@mergc}}%
+ \fi
+ }%
+ \if@tempswa
+ \edef#3{\skvaddlist#1#3#2{\skv@merga}}%
+ \fi
+ }%
+ \skvaftergroupdef#3\endgroup
+ \ifskv@cl\global\let#3#3\fi
+}
+% \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#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#3\endgroup
+ \ifskv@cl\global\let#3#3\fi
+}
+
+% \skvfilterremoveelements!<cmd>{<sublist>}<filter>
+% The exclamation mark (!) implies that the outcome is globalized.
+% When there is no filter to be applied, \skvremoveelements is faster
+% than \skvfilterremoveelements.
+% \if@tempswa can be used to test if, at the end, anything was
+% removed from #1.
+\skvrobustdef*\skvfilterremoveelements{%
+ \skv@testcl\skv@filterremoveelements
+}
+\skvrobustdef*\skv@filterremoveelements#1#2#3{%
+ \begingroup
+ \let\skv@origlist#1%
+ \skv@declarefilter{#3}%
+ \skvifdefTF#1{\skvkvnormalize#1}{\def#1{}}%
+ \skvcommaparse{#2}\skv@rema\skv@rema{%
+ \skv@filter\skv@rema\skv@remb
+ \let\skv@remc#1\let#1\@empty
+ \skvcommaloop*\skv@remc\skv@remc{%
+ \skv@filter\skv@remc\skv@remd
+ \ifx\skv@remb\skv@remd\else
+ \edef#1{\skvaddlist,#1\skvexpandonce\skv@remc}%
+ \fi
+ }%
+ }%
+ \skvexpanded{\endgroup
+ \skvcmdexit#1%
+ \ifx#1\@empty
+ \noexpand\@tempswatrue
+ \else
+ \ifx#1\skv@origlist\noexpand\@tempswafalse\else
+ \noexpand\@tempswatrue\fi
+ \fi
+ }%
+ \ifskv@cl\global\let#1#1\fi
+}
+% \skvremoveelements!<cmd>{<sublist>}
+% The exclamation mark (!) implies that the outcome is globalized.
+% \if@tempswa can be used to test if, at the end, anything was
+% removed from #1.
+\skvrobustdef*\skvremoveelements{\skv@testcl\skv@removeelements}
+\skvrobustdef\skv@removeelements#1#2{%
+ \begingroup
+ \let\skv@origlist#1%
+ \skvifdefTF#1{}{\def#1{}}%
+ \edef\skv@rema{\unexpanded{#2}}%
+ \skvcsvnormalize\skv@rema
+ \let\skv@remb#1\let#1\@empty
+ \skvcommaparse*\skv@remb\skv@tempa{%
+ \skvxifinTF{,\skvoxdetok\skv@tempa,}{,\skvoxdetok\skv@rema,}{}{%
+ \edef#1{\skvaddlist,#1\skvexpandonce\skv@tempa}%
+ }%
+ }%
+ \skvexpanded{\endgroup
+ \skvcmdexit#1%
+ \ifx#1\@empty
+ \noexpand\@tempswatrue
+ \else
+ \ifx#1\skv@origlist\noexpand\@tempswafalse\else
+ \noexpand\@tempswatrue\fi
+ \fi
+ }%
+ \ifskv@cl\global\let#1#1\fi
+}
+
+% \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
+}
+\skvrobustdef*\skv@filterreplaceelements#1#2#3{%
+ \begingroup
+ \skv@declarefilter{#3}%
+ \skvifdefTF#1{\skvkvnormalize#1}{\def#1{}}%
+ \def\do##1##2\skv@nil{%
+ \ifx#3\skv@getkeyname
+ \def\@do####1=####2=####3\skv@nil####4{%
+ \edef####4{\skvtrimspace{####1}=\skvtrimspace{####2}}%
+ }%
+ \@do##1==\skv@nil\skv@old
+ \@do##2==\skv@nil\skv@new
+ \else
+ \edef\skv@old{\unexpanded{##1}}%
+ \edef\skv@new{\unexpanded{##2}}%
+ \fi
+ }%
+ \skvcommaparse{#2}\skv@tempa{%
+ \expandafter\do\skv@tempa\skv@nil
+ \skv@filter\skv@old\skv@oldb
+ \let\skv@tempb#1\let#1\@empty
+ \skvcommaloop*\skv@tempb\skv@tempb{%
+ \skv@filter\skv@tempb\skv@tempc
+ \ifx\skv@tempc\skv@oldb
+ \edef#1{\skvaddlist,#1\skvexpandonce\skv@new}%
+ \else
+ \edef#1{\skvaddlist,#1\skvexpandonce\skv@tempb}%
+ \fi
+ }%
+ }%
+ \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
+}
+% \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
+ \ifx\skvcurrentprefix\@undefined
+ \let\skvcurrentprefix\skvdefaultprefix
+ \fi
+ \edef\skv@header{%
+ \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*\skv@testopta#1{%
+ \skvifstar
+ {\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}}\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}}\skvdefaultprefix
+}
+\skvrobustdef*\skv@t@stoptc#1[#2]#3{%
+ \skvxifinTF{,}{\detokenize{#2}}{%
+ \skv@err{Only one prefix is allowed here,
+ \MessageBreak but you gave '#2'}\skv@ehd
+ }{%
+ \skv@makeprefix{#2}%
+ \edef\skv@fams{#3}%
+ \skvxifinTF{,}{\detokenize{#3}}{%
+ \skvcsvnormalize\skv@fams
+ }{%
+ \skvdespacecontent\skv@fams
+ }%
+ \skv@testopt#1{}%
+ }%
+}
+% \skv@testoptd{<cmd>}{<pre-mp>}
+\skvrobustdef*\skv@testoptd#1#2{%
+ \skv@testoptb{%
+ \edef\skv@provb{#2\skv@header}%
+ \def\skv@prova{\skv@testopt{\skv@t@stoptd{#1}}}%
+ \expandafter\skv@prova\expandafter{\skv@provb}%
+ }%
+}
+% \skv@t@stoptd{<cmd>}[<mp>]{<key>}
+\skvrobustdef*\skv@t@stoptd#1[#2]#3{%
+ \skvifnextchar[{\skv@sttrue#1{#2}{#3}}{\skv@stfalse#1{#2}{#3}[]}%
+}
+\skvrobustdef*\skv@getkeyname#1#2{%
+ \expandafter\skv@g@tkeyname#1=\skv@getname@nil#2%
+}
+\skvrobustdef*\skv@g@tkeyname#1=#2\skv@getname@nil#3{%
+ \skv@strippointersfromkey{#1}%
+ \let#3=\skvcurrentkey
+}
+\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\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}
+\skvrobustdef*\skv@definedefault#1#2{%
+ \ifskv@inoptionsec\else
+ \skvxifinTF{,\skvcurrentprefix,}{,skv,SKV,}{%
+ \skvxifinTF{,\skvcurrentfamily,}{,skeyval,}{%
+ \skv@err{Prefix/family '\skvcurrentpath' are reserved}\skv@ehd
+ }{}%
+ }{}%
+ \fi
+ \ifskv@tracingkeys
+ \skvxifinTF{,#1,}{,\skv@badkeynames,}{%
+ \skv@err{Key name '#1' not allowed}\skv@ehd
+ }{}%
+ \fi
+ \skvcsedef{\skv@header#1.@defa}{%
+ \skvnoexpandcs{\skv@header#1}{\unexpanded{#2}}%
+ }%
+ \skv@recordkey{#1}{#2}%
+}
+
+% 1. Record key and its initial/default value if the key appears in the
+% 'needini' list of its family. The list 'needini' is made by the
+% command \skvsaveinitialvaluekeys.
+% 2. To 'save initial values of keys', the key names must have been
+% entered by \skvsaveinitialvaluekeys in 'needini' list.
+% 3. If a key has no default, then \skv@definedefault will not be called
+% and hence \skv@recordkey won't be invoked.
+% 4. In \skvdefinekeys, if a key has no default, it won't be entered in
+% the 'needini' list. In \skvdefinekeys, an empty default value should
+% be indicated with a slash, eg, .cmd/keya/, .ord/keyb//,
+% or .ord/keyb/.na/.
+% 5. In \skvdefinekeys, use the key/option '.save initial values' to
+% create 'needini' lists of families.
+\skvrobustdef*\skv@recordkey#1#2{%
+ \begingroup
+ \skvifcsdefFT{\skvcurrentpath.@needini}{%
+ \endgroup\skv@swafalse
+ }{%
+ \skv@swatrue
+ \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{\skvcurrentpath.@inikv}%
+ \skvifdefTF\skv@tempb{%
+ \skvxifinTF{,\skvoxdetok\skv@tempa,}{,\skvoxdetok\skv@tempb,}{}{%
+ \skvcsedef{\skvcurrentpath.@inikv}{%
+ \skvaddlist,\skv@tempb\skvexpandonce\skv@tempa
+ }%
+ }%
+ }{%
+ \skvcsedef{\skvcurrentpath.@inikv}{\skvexpandonce\skv@tempa}%
+ }%
+ }{}%
+ }%
+ \ifskv@swa
+ \expandafter\skvaftergroupdef\csname
+ \skvcurrentpath.@inikv\expandafter\endcsname
+ \expandafter\endgroup
+ \fi
+}
+
+% Key will be given in the form <pointer>{<key>}. The command
+% \skv@strippointersfromkey is called both when defining and setting keys.
+%
+% Notes:
+% 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.
+%
+% \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
+ \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@tempb{.gneed value}\skv@tempa{%
+ \skv@add{\skvcsgdef{\skv@header\skv@tempa.@ndv}{}}%
+ }{%
+ \skv@tempb{.forbid value}\skv@tempa{%
+ \skv@add{\skvcsdef{\skv@header\skv@tempa.@fbv}{}}%
+ }{%
+ \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}%
+ }%
+ }%
+}
+% \skv@strippointersfromvalue{<key value>}
+% \skv@strippointersfromvalue*{<key value cmd>}
+%
+% Strip pointers from a key's value. The pointers that may be used on
+% values of keys are
+%
+% .expand once process list -> Expand value once and process the
+% expanded value as a list.
+% .expand twice process list -> Expand value twice and process the
+% expanded value as a list.
+% .expand process list -> Fully expand value and process the
+% expanded value as a list.
+% .eprocess list -> Fully expand value and process the
+% expanded value as a list.
+% .process list -> Process the given value as a list.
+% .list -> Process the given value as a list.
+% .expand once -> Expand value once before parsing it.
+% .expand twice -> Expand value twice before parsing it.
+% .expanded -> Fully expand value before parsing it.
+% .expand -> Fully expand value before parsing it.
+%
+% Return \skvcurrentvalue.
+%
+\skvrobustdef*\skv@strippointersfromvalue{%
+ \skv@i@testst\skv@str@ppointersfromvalue
+}
+\skvrobustdef*\skv@str@ppointersfromvalue#1{%
+ \begingroup
+ \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{.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
+ }{%
+ % 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'.
+ \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@f@ndpointer#1#2{\skv@nil}\skv@pointer@nil
+}
+% \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{}%
+ \def\skv@prova##1(##2){%
+ \def\skv@provb{##2}%
+ \ifx\skv@provb\@nnil\else
+ \advance\@tempcnta\@ne
+ \edef#2{\skvexpandonce#2\skvtrimspace{##1}}%
+ \expandafter\skv@prova
+ \fi
+ }%
+ \skv@prova#1(\@nil)%
+ \ifx#2\@empty
+ \edef#2{\unexpanded{#1}}%
+ \else
+ % 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%
+ \skvcsexit{\skv@header#2.@x0arg}%
+ }%
+}
+% \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
+ \def\skvcurrentkey{}%
+ \def\skvcurrentvalue{}%
+ \def\skv@prova##1(##2){%
+ \def\skv@provb{##2}%
+ \ifx\skv@provb\@nnil\else
+ \edef\skvcurrentkey{\skvxonce\skvcurrentkey\skvtrimspace{##1}}%
+ \edef\skvcurrentvalue{\skvxonce\skvcurrentvalue{\skvtrimspace{##2}}}%
+ \expandafter\skv@prova
+ \fi
+ }%
+ \skv@prova#1(\@nil)%
+ \ifx\skvcurrentkey\@empty
+ \skv@err{No key name for a parenthesized key}\skv@ehd
+ \expandafter\@nodocument
+ \fi
+ \skvexpanded{\endgroup
+ \skvcmdexit\skvcurrentkey\skvcmdexit\skvcurrentvalue
+ }%
+}
+\skvrobustdef*\skv@replacepointers#1{%
+ \begingroup
+ \let\skvcurrentvalue\@empty
+ \let\skv@tempa\@empty
+ \skvifbracedTF{#1}{%
+ \skv@r@placepointers{#1}.use value\skv@nil
+ }{%
+ \skv@r@placepointers#1.use value\skv@nil
+ }%
+ \skvaftergroupdef\skvcurrentvalue\endgroup
+}
+% In the following scheme, if we have, eg,
+%
+% key2=\dimexpr.use value{key1}*5\relax
+%
+% \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{}{%
+ \skvifcsdefFT{\skv@header#2.@value}{%
+ \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}\skv@ehd
+ }{%
+ \edef\skv@tempa{\skvaddlist,\skv@tempa\unexpanded{#2}}%
+ \skvletcs\skv@prova{\skv@header#2.@value}%
+ \skvexpbracenext\skvifbracedTF\skv@prova\skvexpbracenext\skvexpandnext
+ \skv@r@placepointers\skv@prova
+ }%
+ }%
+ }%
+}
+
+% Assign arguments to keys:
+%
+% \skvassignargs[<prefixes>]{<families>}{<keys>}{.<expansion type>{<arg>}}
+%
+% 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
+% defined. This allows the user to define the key later, after its
+% argument has been fixed.
+% 3. Under the macros \skvdefinekeys and \directkeys, there are equally
+% efficient handlers for assigning arguments to keys.
+%
+% Example:
+%
+% \skvassignargs[KV1,KV2]{fam1,fam2}{keya,keyb}{.expanded{#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>.@xxarg.
+%
+% which will be used at setkeys to define and execute the key's callback.
+%
+\skvrobustdef*\skvassignargs{\skv@testopt\skv@assignargs\skvdefaultprefix}
+\skvrobustdef*\skv@assignargs[#1]#2#3#4{%
+ \begingroup
+ \let\skv@temparg\skv@simplearg
+ \def\skv@expandertype{x0}%
+ \edef\skv@tempa{\skvtrimspace{#4}}%
+ \def\do##1##2{%
+ \ifx\do##1\else
+ \skvxifinTF{\detokenize{##1}}{\skvoxdetok\skv@tempa}{%
+ \def\skv@prova####1##1####2####3\skv@arg@nil{%
+ \edef\skv@temparg{\unexpanded{####2}}%
+ \def\skv@expandertype{##2}%
+ }%
+ \expandafter\skv@prova\skv@tempa\skv@arg@nil
+ \def\do####1\do\do{}%
+ }{}%
+ \expandafter\do
+ \fi
+ }%
+ \do{.unexpanded}{x0}{.expand once}{x1}{.expand twice}{x2}%
+ {.expanded}{xx}{.expand}{xx}\do\do
+ \def\skv@tempc{}%
+ % Loop over prefixes:
+ \skvcommaparse{#1}\skv@tempa{%
+ \skv@makeprefix\skv@tempa
+ % Loop over families:
+ \skvcommaparse{#2}\skv@tempa{%
+ \skv@makeheader\skv@tempa
+ % Loop over keys:
+ \skvcommaparse{#3}\skv@tempa{%
+ \edef\skv@tempc{%
+ \skvexpandonce\skv@tempc
+ \skvcsedef{\skv@header\skv@tempa.@\skv@expandertype arg}{%
+ \noexpand\unexpanded{\skvexpandonce\skv@temparg}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \expandafter\endgroup\skv@tempc
+}
+% \skv@getexpander{<expander.type>}
+%
+% 1. <expander.type> is one of 'x0', 'x1', 'x2', 'xx', which had been
+% saved in a key-dependent macro.
+%
+% 2. \skv@getexpander returns macro \skvexpander, which will
+% contain one of \unexpanded, \skvexpandonce, \skvexpandtwice, \@iden.
+%
+\skvrobustdef*\skv@getexpander#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{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]#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*\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
+% automatically be told that the key is inadmissible. The author of an
+% invalid key can also use <callback> to set a message.
+%
+\skvrobustdef*\skvvoidkey{\skv@testoptb\skv@voidkey}
+\skvrobustdef*\skv@voidkey#1{%
+ \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}}%
+ \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
+ }%
+}
+
+%% Key names with parenthesized tokens.
+%
+% \skvpntkey[<pref>]{<fam>}{<key>}[<defa>]{<callback>}
+%
+% The tokens in parenthesis are removed when building the key name.
+% Each parenthesis gives rise to one argument of the key's callback.
+% When the key is set, the tokens in parenthesis are assigned to the
+% arguments. It is the user's responsibility to catch those argument
+% in the key's callback.
+%
+% Example - a key of three arguments:
+%
+% \skvpntkey[KV]{fam}{evaluate (1) as (2) using (3)}{%
+% \def\oldcmd{#1}\def\newcmd{#2}\def\formula{#3}%
+% \def\x##1{#1*##1}%
+% }
+%
+% \skvpntkey[KV]{fam}{evaluate (1) as (2) using (3)}[\x\y{\numexpr\x*2}]{%
+% \edef\x#2{#3}%
+% }
+%
+% \skvshowcs{KV/fam/evaluateasusing/.@x0arg}
+%
+% \skvsetkeys[KV]{fam}{evaluate (\x) as (\y) using (\numexpr\x*2)}
+%
+\skvrobustdef*\skvpntkey{\skv@testoptb\skv@pntkey}
+\skvrobustdef*\skv@pntkey#1{%
+ \skv@strippointersfromkey{#1}%
+ \skvexpbracenext\skv@extractpntkey@atdefkey\skvcurrentkey\skvcurrentkey
+ \skvexpanded{\skv@testopt{\skv@pntkey@a{\skvcurrentkey}}{^skv^}}%
+}
+\skvrobustdef*\skv@pntkey@a#1[#2]#3{%
+ \skvifstrcmpTF{#2}{^skv^}{}{\skv@definedefault{#1}{#2}}%
+ \skvcsedef{\skv@header#1.@cbk}{\unexpanded{#3}}%
+}
+
+%% Command keys:
+%
+% \skvcmdkey[<pref>]{<fam>}[<mp>]{<key>}[<defa>]{<callback>}
+%
+\skvrobustdef*\skvcmdkey{%
+ \def\skv@zapsw{01}%
+ \skv@testoptd\skv@cmdkey{cmd}%
+}
+% \skvzcmdkey will internally zap the spaces in the key's name, but the
+% key user will not notice that: he can still use the key's name with
+% spaces in it. The key's author could then use the zapped name internally
+% in his code.
+\skvrobustdef*\skvzcmdkey{%
+ \def\skv@zapsw{00}%
+ \skv@testoptd\skv@cmdkey{cmd}%
+}
+% When the key's value has doubled hash characters, xkeyval's definition
+% of \skv@cmdkey fails:
+\skvrobustdef*\skv@cmdkey#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@prova{#1\skvcurrentkey}%
+ \edef\skv@prova{\expandafter\skv@zapornot\expandafter
+ {\expandafter\skv@zapsw\expandafter}\expandafter{\skv@prova}}%
+ \skvcsedef{\skv@header\skvcurrentkey.@cbk}{%
+ \skvcslet{\skv@prova}\noexpand\skvcurrentvalue
+ \unexpanded{#4}%
+ }%
+}
+% \skvcmdkeys[<pref>]{<fam>}[<mp>]{<keys>}[<defa>]{<callback>}
+\skvrobustdef*\skvcmdkeys{%
+ \def\skv@zapsw{01}%
+ \skv@testoptd\skv@cmdkeys{cmd}%
+}
+\skvrobustdef*\skvzcmdkeys{%
+ \def\skv@zapsw{00}%
+ \skv@testoptd\skv@cmdkeys{cmd}%
+}
+\skvrobustdef*\skv@cmdkeys#1#2[#3]#4{%
+ \skvcommaparse{#2}\skv@tempa{%
+ \skvexpanded{\skv@cmdkey{#1}{\skv@tempa}}[#3]{#4}%
+ }%
+}
+
+%% 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.
+%
+% \skvchoicekey[<pref>]{<fam>}[<mp>]{<keys>}[<bins>]{<choices>}
+% [<default>]{<callback>}
+% \skvchoicekey+[<pref>]{<fam>}[<mp>]{<keys>}[<bins>]{<choices>}
+% [<default>]{<callback>}{<fallback>}
+% \skvchoicekey*[<pref>]{<fam>}[<mp>]{<keys>}[<bins>]{<choices>}
+% [<default>]{<callback>}
+% \skvchoicekey*+[<pref>]{<fam>}[<mp>]{<keys>}[<bins>]{<choices>}
+% [<default>]{<callback>}{<fallback>}
+%
+% \skvchoicekeys[KV]{fam}[mp@]{key1,key2}[\val\nr]{%
+% center.do=\def\vala{#1},
+% right.do=\def\valb{#1},
+% left.do=\def\valc{#1}
+% }[center]{\def\x##1{#1*##1}}
+%
+% \skv@preparenominations{00.or.01}{<altlist>}
+\skvrobustdef*\skv@preparenominations#1#2{%
+ \begingroup
+ \def\skv@altlista{}%
+ \def\skv@altlistb{}%
+ \def\skv@provc##1.do=##2.do=##3\skv@choice@nil{%
+ \if#1\lowercase{\fi
+ \edef\skv@prova{\skvtrimspace{##1}}%
+ \if#1}\fi
+ \skvstripouterbraces{2}\skv@prova
+ \edef\skv@altlista{%
+ \skvaddlist,\skv@altlista\skvxonce\skv@prova
+ }%
+ \edef\reserved@a{%
+ \skvnoexpandcs{\skvoxdetok\skv@prova @skvch}%
+ {\skvtrimspace{##2}}%
+ }%
+ \edef\skv@altlistb{\skvxonce\skv@altlistb\skvxonce\reserved@a}%
+ }%
+ \skvcommaparse{#2}\skv@prova{%
+ \expandafter\skv@provc\skv@prova.do=.do=\skv@choice@nil
+ }%
+ \ifx\skv@altlista\@empty
+ \skv@err{No nominations (state pattern) for choice key}\skv@ehd
+ \def\skv@altlistb{}%
+ \fi
+ \skvexpanded{\endgroup
+ \skvcmdexit\skv@altlista\skvcmdexit\skv@altlistb
+ }%
+}
+% \skv@executechoice{00 or 01}{<currentvalue>}{<altlist>}
+\skvrobustdef*\skv@executechoice#1#2#3{%
+ \begingroup
+ \if#1\lowercase{\fi
+ \edef\skv@prova{\skvtrimspace{#2}}%
+ \if#1}\fi
+ \skvstripouterbraces{2}\skv@prova
+ \edef\do{%
+ \expandafter\noexpand\csname\detokenize
+ \expandafter{\skv@prova}@skvch\endcsname
+ }%
+ % Hide #3 in a macro to avoid confusing any parameter
+ % characters in #3 with the parameters of \skv@prova:
+ \edef\skv@provb{\unexpanded{#3}}%
+ \edef\skv@prova{\def\noexpand\skv@prova####1\skvxonce\do####2####3}%
+ \skv@prova\skv@choice@nil{%
+ \toks@{##2}%
+ \edef\skv@prova{\unexpanded{##2}}%
+ \ifx\skv@prova\skv@nnil
+ \skv@err{No state pattern match found for key
+ \MessageBreak '\skvcurrentkey'}\skv@ehd
+ \toks@{}%
+ \fi
+ }%
+ \expandafter\expandafter\expandafter\skv@prova\expandafter
+ \skv@provb\do{\skv@nil}\skv@choice@nil
+ \expandafter\endgroup\the\toks@
+}
+\skvrobustdef*\skvchoicekey{%
+ \skv@testopta{\skv@testoptb
+ {\skv@testopt\skv@choicekey@a{choice\skv@header}}}%
+}
+\skvnewlet\skvchoicekeys\skvchoicekey
+\skvrobustdef*\skv@choicekey@a[#1]#2{%
+ \skvxifinTF{\skv@hashchar}{\detokenize{#2}}{%
+ \skv@err{Hash character '\skv@hashchar' not allowed
+ \MessageBreak in key name}\skv@ehd
+ }{%
+ \edef\skv@currlist{\unexpanded{#2}}%
+ \edef\skv@hp{\skvtrimspace{#1}}%
+ \skv@testopt\skv@choicekey@b{}%
+ }%
+}
+\skvrobustdef*\skv@choicekey@b[#1]#2{%
+ \edef\skv@bins{\unexpanded{#1}}%
+ % Check the syntax of bins. This also helps catch wrong use syntax
+ % of \skvchoicekeys: it's easy to get the syntax of \skvchoicekeys
+ % wrong. The default value may have been put in place of bins.
+ \ifx\skv@bins\@empty\else
+ \skvtfor\skv@prova:=#1\do{%
+ \skvexpbracenext\skvifescapedTF\skv@prova{}{%
+ \skv@err{Token '\skvoxdetok\skv@prova' of bin of
+ \MessageBreak choice key isn't escaped}\skv@ehd
+ }%
+ }%
+ \fi
+ \skvifblankTF{#2}{%
+ \skv@err{No nominations (state pattern) for
+ \MessageBreak choice keys '\skv@currlist'}\skv@ehd
+ }{%
+ \skvifboolTF{skv@st}{%
+ \skv@preparenominations{00}{#2}%
+ }{%
+ \skv@preparenominations{01}{#2}%
+ }%
+ }%
+ \skvifnextchar[\skv@choicekey@c{\skv@choicekey@c[^skv^]}%
+}
+\skvrobustdef*\skv@choicekey@c[#1]{%
+ \edef\skv@default{\skvtrimspace{#1}}%
+ % Choice can't have braced values, since that will make matching
+ % to the state pattern difficult or impossible:
+ \skvstripouterbraces{2}\skv@default
+ \skvifdefboolTF{skv@pl}\skv@choicekey@e\skv@choicekey@d
+}
+\skvrobustdef*\skv@choicekey@d#1{%
+ \skvexpanded{%
+ \noexpand\skv@choicekey@f{{%
+ \noexpand\skv@executechoice\ifskv@st{00}\else{01}\fi
+ {####1}{\skvxonce\skv@altlistb}%
+ \unexpanded{#1}%
+ }}%
+ }%
+}
+\skvrobustdef*\skv@choicekey@e#1#2{%
+ \skvexpanded{%
+ \noexpand\skv@choicekey@f{{%
+ \noexpand\skv@executechoice\ifskv@st{00}\else{01}\fi
+ {####1}{\skvxonce\skv@altlistb}%
+ \unexpanded{#1}%
+ }{\unexpanded{#2}}}%
+ }%
+}
+\skvrobustdef*\skv@choicekey@f#1{%
+ \edef\skv@prova##1##2{%
+ \ifskv@st\noexpand\skv@sttrue\else\noexpand\skv@stfalse\fi
+ \ifskv@pl\noexpand\skv@pltrue\else\noexpand\skv@plfalse\fi
+ \noexpand\skv@checkchoice
+ \ifx\skv@bins\@empty\else[\skvxonce\skv@bins]\fi
+ {##1}{\skvxonce\skv@altlista}##2%
+ }%
+ \skv@temptoks\expandafter{\skv@prova{##1}{#1}}%
+ % Why separate \skv@choicekey@g? It is needed by skeyval-view.sty:
+ \skv@choicekey@g
+}
+\skvrobustdef*\skv@choicekey@g{%
+ \skvcommaparse*\skv@currlist\skv@prova{%
+ \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.@cbk}{%
+ \skvcslet{\skv@hp\skvcurrentkey}\noexpand\skvcurrentvalue
+ \the\skv@temptoks
+ }%
+ }%
+}
+
+\skvrobustdef*\skv@togkey@settog#1#2#3{%
+ \edef\skv@prova{\skv@zapornot{#1}{#2}}%
+ \csname skvsettog#3\expandafter\endcsname\expandafter{\skv@prova}%
+}
+
+%% Boolean keys:
+%
+% \skvboolkey[<pref>]{<fam>}[<mp>]{<key>}[<defa>]{<callback>}
+% \skvboolkey+[<pref>]{<fam>}[<mp>]{<keys>}[<defa>]{<callback>}{<fallback>}
+%
+% Boolean keys create a store to receive the key's value and also create
+% a boolean internally.
+%
+\skvrobustdef*\skvboolkey{%
+ \def\skv@typetogkey{01}%
+ \def\skv@zapsw{01}%
+ \skv@t@stopta{\skv@testoptd\skv@boolkey{}}%
+}
+% \skvzboolkey will internally zap the spaces in the key's name and in
+% the boolean that it creates internally, but the key user will not
+% notice that: he will still be able to submit the original key's name
+% with spaces in it. The key's author could then use the zapped key
+% name and boolean in his code (internally).
+\skvrobustdef*\skvzboolkey{%
+ \def\skv@typetogkey{01}%
+ \def\skv@zapsw{00}%
+ \skv@t@stopta{\skv@testoptd\skv@boolkey{}}%
+}
+% \skv@boolkeys{<mp>}{<key>}[<default>]
+\skvrobustdef*\skv@boolkey#1#2[#3]{%
+ \skv@strippointersfromkey{#2}%
+ \skvexpanded{%
+ \ifskv@pl\skv@boolkey@b\else\skv@boolkey@a\fi
+ {\skvcurrentkey}{#1\skvcurrentkey}%
+ }{#3}%
+}
+% \skv@boolkey@a{<key>}{<mp.key>}{<default>}{<callback>}
+\skvrobustdef*\skv@boolkey@a#1#2#3#4{%
+ \def\skv@tempa{\skv@boolkey@c{#1}{#2}{#3}}%
+ \skvifknobTF{skv@typetogkey}{%
+ \expandafter\skv@tempa\expandafter{\expandafter{\expandafter
+ \skv@togkey@settog\expandafter{\skv@zapsw}{#2}\skv@value#4}}%
+ }{%
+ \expandafter\skv@tempa\expandafter{\expandafter{\expandafter
+ \csname\expandafter\skv@zapornot\expandafter{\skv@zapsw}{#2}%
+ \skv@value\endcsname#4}}%
+ }%
+}
+% \skv@boolkey@b{<key>}{<mp.key>}{<default>}{<callback>}{<fallback>}
+\skvrobustdef*\skv@boolkey@b#1#2#3#4#5{%
+ \def\skv@tempa{\skv@boolkey@c{#1}{#2}{#3}}%
+ \skvifknobTF{skv@typetogkey}{%
+ \expandafter\skv@tempa\expandafter{\expandafter{\expandafter
+ \skv@togkey@settog\expandafter{\skv@zapsw}{#2}\skv@value#4}{#5}}%
+ }{%
+ \expandafter\skv@tempa\expandafter{\expandafter{\expandafter
+ \csname\expandafter\skv@zapornot\expandafter{\skv@zapsw}{#2}%
+ \skv@value\endcsname#4}{#5}}%
+ }%
+}
+% \skv@boolkey@c{<key>}{<mp.key>}{<default>}{{<callback>}{<fallback>}}
+\skvrobustdef*\skv@boolkey@c#1#2#3#4{%
+ \if\skv@typetogkey
+ \skvdeftog{\skv@zapornot{\skv@zapsw}{#2}}%
+ \else
+ \skvcsnewif{\skv@zapornot{\skv@zapsw}{#2}}%
+ \fi
+ \skvifdefboolTF{skv@st}{\skv@definedefault{#1}{#3}}{}%
+ \edef\skv@tempa##1##2{%
+ \noexpand\skv@sttrue
+ \ifskv@pl\noexpand\skv@pltrue\else\noexpand\skv@plfalse\fi
+ \skv@checkchoice[\noexpand\skv@value]{##1}{true,false}##2%
+ }%
+ \skv@temptoks\expandafter{\skv@tempa{##1}{#4}}%
+ \skvcsedef{\skv@header#1.@cbk}{\the\skv@temptoks}%
+}
+%
+% \skvboolkeys[<pref>]{<fam>}[<mp>]{<keys>}[<defa>]{<callback>}
+% \skvboolkeys+[<pref>]{<fam>}[<mp>]{<keys>}[<defa>]{<callback>}{<fallback>}
+%
+\skvrobustdef*\skvboolkeys{%
+ \def\skv@typetogkey{01}%
+ \def\skv@zapsw{01}%
+ \skv@t@stopta{\skv@testoptd\skv@boolkeys{}}%
+}
+\skvrobustdef*\skvzboolkeys{%
+ \def\skv@typetogkey{01}%
+ \def\skv@zapsw{00}%
+ \skv@t@stopta{\skv@testoptd\skv@boolkeys{}}%
+}
+% \skv@boolkeys{<mp>}{<keys>}[<default>]
+\skvrobustdef*\skv@boolkeys#1#2[#3]{%
+ \skvifdefboolTF{skv@pl}\skv@boolkeys@b\skv@boolkeys@a{#2}{#1}{#3}%
+}
+% \skv@boolkeys@a{<keys>}{<mp>}{<default>}{<callback>}
+\skvrobustdef*\skv@boolkeys@a#1#2#3#4{\skv@boolkeys@c{#1}{#2}{#3}{#4}{^skv^}}
+% \skv@boolkeys@b{<keys>}{<mp>}{<default>}{<callback>}{<fallback>}
+\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@strippointersfromkey\skv@tempa
+ \skvexpanded{%
+ \skvifstrcmpTF{#5}{^skv^}{%
+ \skv@boolkey@a{\skvcurrentkey}%
+ {#2\skvcurrentkey}\unexpanded{{#3}{#4}}%
+ }{%
+ \skv@boolkey@b{\skvcurrentkey}%
+ {#2\skvcurrentkey}\unexpanded{{#3}{#4}{#5}}%
+ }%
+ }%
+ }%
+}
+%
+% \skvbiboolkeys[<pref>]{<fam>}[<mp>]{<key1,key2>}[<defa>]
+% {<callback.for.key1>}{<callback.for.key2>}
+% \skvbiboolkeys+[<pref>]{<fam>}[<mp>]{<key1,key2>}[<defa>]
+% {<callback.for.key1>}{<callback.for.key2>}{<fallback>}
+%
+% Example:
+%
+% \skvbiboolkeys+[KV]{fam}[mp@]{.need value{keya},keyb}[true]{%
+% \ifmp@keya\def\xa##1{##1}\fi
+% }{%
+% \ifmp@keyb\def\xb##1{##1}\fi
+% }{%
+% \skv@warn{Value '#1' is invalid}%
+% }
+%
+\skvrobustdef*\skvbiboolkeys{%
+ \def\skv@typetogkey{01}%
+ \def\skv@zapsw{01}%
+ \skv@t@stopta{\skv@testoptd\skv@biboolkeys{}}%
+}
+\skvrobustdef*\skvzbiboolkeys{%
+ \def\skv@typetogkey{01}%
+ \def\skv@zapsw{00}%
+ \skv@t@stopta{\skv@testoptd\skv@biboolkeys{}}%
+}
+\skvrobustdef*\skv@biboolkeys#1#2[#3]{%
+ \begingroup
+ \edef\skv@currlist{\unexpanded{#2}}%
+ \skvcsvnormalize\skv@currlist
+ \@tempcnta\skvz@
+ \skvcommaloop*\skv@currlist\skv@tempa{%
+ \advance\@tempcnta\@ne
+ \ifnum\@tempcnta>\tw@
+ \skvbreakloop
+ \fi
+ }%
+ \ifnum\@tempcnta=\tw@\else
+ \skv@err{Number of bi-keys isn't 2:
+ \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>}
+\skvrobustdef*\skv@biboolkeys@a#1#2#3#4#5{%
+ \skv@biboolkeys@c{#1}{#2}{#3}{#4}{#5}{^skv^}%
+}
+% \skv@bilboolkeys@a{<key1,key2>}{<mp>}{<default>}
+% {<callback1>}{<callback2>}{<fallback>}
+\skvrobustdef*\skv@biboolkeys@b#1#2#3#4#5#6{%
+ \skv@biboolkeys@c{#1}{#2}{#3}{#4}{#5}{#6}%
+}
+\skvrobustdef*\skv@biboolkeys@c#1#2#3#4#5#6{%
+ % Don't group the following: pointers will be lost outide the group.
+ % 'bicallerid' is used to indicate that the master key is the one
+ % that has instantiated the callback of the slave. This avoids
+ % infinite re-entrance of \skvsetkeys.
+ \edef\skv@default{\unexpanded{#3}}%
+ \edef\skv@tempc{\unexpanded{#4}}%
+ \edef\skv@tempd{\unexpanded{#5}}%
+ \edef\skv@tempe{\unexpanded{#6}}%
+ \toks@{}\def\skv@provd{}%
+ \let\nx\noexpand
+ \def\@do##1##2{%
+ \skvifcsname\skv@header##1.@##2\then
+ \edef\skv@provd{%
+ \skv@provd
+ \skvcsdef{\skv@header##1.@##2}{%
+ \csname\skv@header##1.@##2\endcsname
+ }%
+ }%
+ \fi
+ }%
+ \def\skv@provc##1##2##3##4{%
+ \skvsettogtrue{\skv@header bicallerid/##3}%
+ \skvxonce\@elt
+ \nx\skvifxTF\nx\skvcurrentvalue\nx\skv@truetoks{%
+ \nx\skviftogTF{\skv@header bicallerid/##4}{}{%
+ \skvsetkeys[##1]{##2}{##4=false}%
+ }%
+ }{%
+ \nx\skviftogTF{\skv@header bicallerid/##4}{}{%
+ \skvsetkeys[##1]{##2}{##4=true}%
+ }%
+ }%
+ \skvsettogfalse{\skv@header bicallerid/##3}%
+ }%
+ % \skv@provb{<KV>}{<fam>}{<primary.key>}{<secondary.key>}
+ \def\skv@provb##1##2##3##4{%
+ \@do{##3}{ndv}\@do{##3}{fbv}%
+ \skvexpanded{%
+ \toks@{\the\toks@
+ \skvdeftog{\skv@header bicallerid/##3}%
+ \skvifstrcmpTF{#6}{^skv^}{%
+ \skv@boolkey@a
+ {##3}{#2##3}{\skvxonce\skv@default}{%
+ \skv@provc{##1}{##2}{##3}{##4}%
+ }%
+ }{%
+ \skv@boolkey@b
+ {##3}{#2##3}{\skvxonce\skv@default}{%
+ \skv@provc{##1}{##2}{##3}{##4}%
+ }{\skvxonce\skv@tempe}%
+ }%
+ }%
+ }%
+ }%
+ \def\skv@prova##1,##2\skv@nil{%
+ \skv@strippointersfromkey{##1}%
+ \let\skv@tempa\skvcurrentkey
+ \skv@strippointersfromkey{##2}%
+ \let\skv@tempb\skvcurrentkey
+ \skvexpanded{%
+ \let\nx\@elt\nx\skv@tempc
+ \nx\skv@provb{\skvcurrentprefix}{\skvcurrentfamily}%
+ {\skv@tempa}{\skv@tempb}%
+ \let\nx\@elt\nx\skv@tempd
+ \nx\skv@provb{\skvcurrentprefix}{\skvcurrentfamily}%
+ {\skv@tempb}{\skv@tempa}%
+ }%
+ }%
+ \skv@prova#1\skv@nil
+ \skvexpanded{\endgroup
+ \skv@provd\the\toks@
+ }%
+}
+
+%% Toggle keys:
+%
+% \skvtogkey[<pref>]{<fam>}[<mp>]{<key>}[<defa>]{<callback>}
+% \skvtogkey+[<pref>]{<fam>}[<mp>]{<key>}[<defa>]{<callback>}{<fallback>}
+%
+\skvrobustdef*\skvtogkey{%
+ \def\skv@typetogkey{00}%
+ \def\skv@zapsw{01}%
+ \skv@t@stopta{\skv@testoptd\skv@boolkey{}}%
+}
+\skvrobustdef*\skvztogkey{%
+ \def\skv@typetogkey{00}%
+ \def\skv@zapsw{00}%
+ \skv@t@stopta{\skv@testoptd\skv@boolkey{}}%
+}
+\skvrobustdef*\skvtogkeys{%
+ \def\skv@typetogkey{00}%
+ \def\skv@zapsw{01}%
+ \skv@t@stopta{\skv@testoptd\skv@boolkeys{}}%
+}
+\skvrobustdef*\skvztogkeys{%
+ \def\skv@typetogkey{00}%
+ \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}%
+ \skv@t@stopta{\skv@testoptd\skv@biboolkeys{}}%
+}
+\skvrobustdef*\skvzbitogkeys{%
+ \def\skv@typetogkey{00}%
+ \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
+}
+
+% 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.
+%
+% Example:
+%
+% \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>}
+%
+% Example:
+%
+% \skvordkeys[KV]{fam}{keya,keyb}{\def\x##1{#1*##1}}
+% \skvappendslots[KV]{fam}{keyd,keye}{keya=.expanded{\vala},keyb=valb}
+% [def-d&e]{\def\y##1{#1*##1}}
+%
+% 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 <slots>.
+%
+% 3. Here, it helps to consider <signal.keys> as parents (or signals/
+% subjects/observables) and <slots> as children (or slots/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.
+%
+\AtEndOfPackage{%
+ \skvnewcastcommands{%
+ \skvslotkeys=\skvappendslots,\skvstylekeys=\skvappendslots,
+ \skvprependstyles=\skvprependslots,
+ \skvappendstylesexpanded=\skvappendslotsexpanded,
+ \skvprependstylesexpanded=\skvprependslotsexpanded,
+ \skvaddstyles=\skvaddslots,
+ \skvobserverkeys=\skvappendslots,
+ \skvprependobservers=\skvprependslots,
+ \skvappendobserversexpanded=\skvappendslotsexpanded,
+ \skvprependobserversexpanded=\skvprependslotsexpanded,
+ \skvaddobservers=\skvaddslots
+ }%
+}
+\skvrobustdef*\skvappendslots{%
+ \def\skv@type{app}%
+ \let\skvexpanderpointer\@iden
+ \skv@testoptb\skv@appendslots
+}
+\skvrobustdef*\skvprependslots{%
+ \def\skv@type{prep}%
+ \let\skvexpanderpointer\@iden
+ \skv@testoptb\skv@appendslots
+}
+\skvrobustdef*\skvappendslotsexpanded{%
+ \def\skv@type{app}%
+ \def\skvexpanderpointer{.expanded}%
+ \skv@testoptb\skv@appendslots
+}
+\skvrobustdef*\skvprependslotsexpanded{%
+ \def\skv@type{prep}%
+ \def\skvexpanderpointer{.expanded}%
+ \skv@testoptb\skv@appendslots
+}
+\skvrobustdef*\skv@appendslots#1#2{%
+ \skv@testopt{\skv@appendslots@a{#1}{#2}}{^skv^}%
+}
+% #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@strippointersfromkey\skv@prova
+ \skvexpanded{%
+ \skvifstrcmpTF{#3}{^skv^}{}{%
+ % If the signal aready exists, the default value will be
+ % overridden:
+ \skv@definedefault{\skvcurrentkey}{\unexpanded{#3}}%
+ }%
+ \skv@appendslots@b{\skvcurrentkey}\unexpanded{{#2}{#4}}%
+ }%
+ }%
+}
+% \skv@appendslots@b{<signal>}{<slots>}{<signal.callback>}
+\skvrobustdef*\skv@appendslots@b#1#2#3{%
+ \def\skv@slotlist{}%
+ \skvkvparse{#2}\skv@prova{%
+ \skv@okvsplit\skv@prova{%
+ \skvxifstrcmpTF{#1}{##1}{%
+ \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{Slot key '\skvcurrentpath/##1'
+ \MessageBreak is undefined}\skv@ehd
+ }%
+ }%
+ \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 using
+ % \skvaddslots:
+ \edef\elt{%
+ \skvifcsdefTF{\skv@header#1.@cbk}%
+ {\skvexpandcsonce{\skv@header#1.@cbk}}{}%
+ }%
+ \skvcsedef{\skv@header#1.@cbk}{%
+ \skvxifstrcmpTF{\skv@type}{prep}{%
+ \skvexpandonce\skv@elt\skvtrimspace{#3}\skvexpandonce\elt
+ }{%
+ \skvexpandonce\elt\skvtrimspace{#3}\skvexpandonce\skv@elt
+ }%
+ }%
+}
+%
+% \skvaddslots[<pref>]{<fam>}{<signals>}{<prepended.slots>}
+% {<appended.slots>}[<signal.default>]{<signal.callback>}
+%
+% 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}}
+% \skvaddslots[KV]{fam}{keyd,keye}{keya1=vala,keyb1=valb}
+% {keya2=vala,keyb2=.expanded{\valb}}[def-d&e]{\def\y##1{#1*##1}}
+%
+% \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@addslots#1#2#3{%
+ \skv@testopt{\skv@addslots@a{#1}{#2}{#3}}{^skv^}%
+}
+% \skv@addslots@a{<signals>}{<prepended slots>}{<appended slots>}
+% [<signal default>]{<signal callback>}
+\skvrobustdef*\skv@addslots@a#1#2#3[#4]#5{%
+ \skvexpanded{%
+ \skvprependslots[\skvcurrentprefix]{\skvcurrentfamily}%
+ \unexpanded{{#1}{#2}[#4]{#5}}%
+ % Without \ifskv@addslots@appending, when using \skvaddslots,
+ % signal keys will otherwise be added in the database twice
+ % (while treating prepended and appended slots).
+ \noexpand\skv@addslots@appendingtrue
+ \skvappendslots[\skvcurrentprefix]{\skvcurrentfamily}%
+ \unexpanded{{#1}{#3}[#4]{#5}}%
+ \noexpand\skv@addslots@appendingfalse
+ }%
+}
+
+% Checking the admissible values of keys:
+%
+\skvrobustdef*\skvcheckchoice{\skv@testopta{\skv@testopt\skv@checkchoice{}}}
+\skvrobustdef*\skv@checkchoice[#1]#2#3{%
+ \begingroup
+ \edef\skv@tempa{\skvtrimspace{#2}}%
+ \def\skv@tempb{#3}%
+ \skvcsvnormalize\skv@tempb
+ \skvexpanded{%
+ \ifskv@st\lowercase{\fi
+ \ifcat$\detokenize{#1}$%
+ \skv@checkchoice@b\skv@nil
+ {\skvexpandonce\skv@tempa}{\skvexpandonce\skv@tempb}%
+ \else
+ \skv@checkchoice@a\unexpanded{#1}\skv@nil
+ {\skvexpandonce\skv@tempa}{\skvexpandonce\skv@tempb}%
+ \fi
+ \ifskv@st}\fi
+ }%
+}
+\skvrobustdef*\skv@checkchoice@a#1#2\skv@nil#3#4{%
+ \def\skv@tempa{#2}%
+ \skvifxTF\skv@tempa\@empty{%
+ \skv@checkchoice@b#1{#3}{#4}%
+ }{%
+ \skv@checkchoice@c#1#2{#3}{#4}%
+ }%
+}
+\skvrobustdef*\skv@checkchoice@b#1#2#3{%
+ \def\skv@tempa{#1}%
+ \ifx\skv@tempa\skv@nnil
+ \def\skv@tempa{\endgroup}%
+ \else
+ \def\skv@tempa{\endgroup\def#1{#2}}%
+ \fi
+ \skvxifinTF{,\detokenize{#2},}{,\detokenize{#3},}{%
+ \ifskv@pl
+ \skvappendtomacro\skv@tempa{\@firstoftwo}%
+ \else
+ \skvappendtomacro\skv@tempa{\@firstofone}%
+ \fi
+ }{%
+ \ifskv@pl
+ \skvappendtomacro\skv@tempa{\@secondoftwo}%
+ \else
+ \skv@err{Value '\detokenize{#2}' is not allowed}\skv@ehd
+ \skvappendtomacro\skv@tempa{\@gobble}%
+ \fi
+ }%
+ \skv@tempa
+}
+\skvrobustdef*\skv@checkchoice@c#1#2#3#4{%
+ \@tempcnta\skvz@
+ \def\skv@tempa{#3}%
+ \edef\skv@tempc{\unexpanded{#4}}%
+ \skvcsvnormalize\skv@tempc
+ \def\skv@prova{\endgroup\skvexpandonce\skv@tempc\noexpand}%
+ \def\skv@tempb##1,{%
+ \def\skv@provb{##1}%
+ \ifx\skv@provb\skv@nnil
+ \def\skv@tempc{\def#1{#3}\def#2{-1}}%
+ \ifskv@pl
+ \edef\skv@tempb{\skv@prova\@secondoftwo}%
+ \else
+ \skv@err{Value '\detokenize{#3}' is not allowed}\skv@ehd
+ \edef\skv@tempb{\skv@prova\@gobble}%
+ \fi
+ \else
+ \edef\skv@tempc{\def\unexpanded{#1{##1}\def#2}{\the\@tempcnta}}%
+ \ifx\skv@provb\skv@tempa
+ \ifskv@pl
+ \edef\skv@tempb{\skv@prova\skv@checkchoice@d}%
+ \else
+ \edef\skv@tempb{\skv@prova\skv@checkchoice@e}%
+ \fi
+ \else
+ \advance\@tempcnta\@ne
+ \fi
+ \fi
+ \skv@tempb
+ }%
+ \expandafter\skv@tempb\skv@tempc,\skv@nil,%
+}
+\skvrobustdef*\skv@checkchoice@d#1\skv@nil,{\@firstoftwo}
+\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}\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}%
+ \edef\skv@fams{#3}%
+ \skvdespace{#4}\skvcurrentkey
+ \skv@kffalse
+ % Don't use \skvcurrentprefix in place of \skv@prova here.
+ % We use \skv@prova here because \skv@tempa, \skvcurrentprefix and
+ % \skvcurrentfamily might be in use already.
+ \skvcommaparse*\skv@prefs\skv@prova{%
+ \skv@makeprefix\skv@prova
+ \skv@ifk@yundef
+ % Break outer loop as needed:
+ \ifskv@kf\skvbreakloop\fi
+ }%
+ \skvexpanded{%
+ \skvifboolTF{skv@kf}{%
+ \if0#1%
+ \noexpand\@firstoftwo
+ \else
+ \noexpand\@secondoftwo
+ \fi
+ }{%
+ \if0#1%
+ \noexpand\@secondoftwo
+ \else
+ \noexpand\@firstoftwo
+ \fi
+ }%
+ }{#5}{#6}%
+ \skvpopstate\skv@keystate\skv@keydepth
+}
+\skvrobustdef*\skv@ifk@yundef{%
+ \skvcommaparse*\skv@fams\skv@prova{%
+ \skv@makeheader\skv@prova
+ \skvifcsdefFT{\skv@header\skvcurrentkey.@cbk}{}{%
+ \skv@kftrue\skvbreakloop
+ }%
+ }%
+}
+% \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.
+%
+\skvrobustdef*\skvifkeyinfamiliesTF{%
+ \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}\skvdefaultprefix
+}
+\skvrobustdef*\skv@ifkeyinfamilies#1[#2]#3#4#5#6{%
+ \skvpushstate\skv@keystate\skv@keydepth
+ \edef\skv@prefs{#2}%
+ \edef\skv@fams{#3}%
+ \skvdespace{#4}\skvcurrentkey
+ \skvcommaparse*\skv@prefs\skv@prova{%
+ \skv@makeprefix\skv@prova
+ \skv@ifk@yinfamilies{#1}{#5}{#6}%
+ }%
+}
+\skvrobustdef*\skv@ifk@yinfamilies#1#2#3{%
+ \skvcommaparse*\skv@fams\skv@prova{%
+ \skv@makeheader\skv@prova
+ \skvexpanded{%
+ \skvifcsdefTF{\skv@header\skvcurrentkey.@cbk}{%
+ \if0#1%
+ \noexpand\@firstoftwo
+ \else
+ \noexpand\@secondoftwo
+ \fi
+ }{%
+ \if0#1%
+ \noexpand\@secondoftwo
+ \else
+ \noexpand\@firstoftwo
+ \fi
+ }%
+ }{#2}{#3}%
+ }%
+ \skvpopstate\skv@keystate\skv@keydepth
+}
+% \skvifkeyinfamilyTF{<prefix>/<family>}{<key>}
+\skvnewdef*\skvifkeyinfamilyTF#1#2{%
+ \skvifcsdefTF{\skvtrimspace{#1}/\skvtrimspace{#2}.@cbk}%
+}
+% \skvifkeyincurrentfamilyTF{<key>}
+\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}}.
+%
+\skvnewdef*\skvifonekeyinfamilyTF#1#2{%
+ \ifnum\numexpr0\skv@ifonekeydef{#1}#2,\@nnil,>\skvz@
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+\skvnewdef*\skv@ifonekeydef#1#2,{%
+ \ifx\@nnil#2%
+ \expandafter\@gobble
+ \else
+ \skvifcsdefTF{\skvtrimspace{#1}/\skvtrimspace{#2}.@cbk}{+1}{+0}%
+ \expandafter\skv@ifonekeydef
+ \fi
+ {#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 'default KV' for <pref>.
+% \skvprintvalue[<pref>]{<family>}{<key>}
+\skvrobustdef*\skvprintvalue{\skv@testoptb\skv@printvalue}
+\skvrobustdef*\skv@printvalue#1{\skvcsuse{\skv@header#1.@value}}
+
+% \skvgetvalue{<pref>}{<family>}{<key>}<cmd>
+\skvrobustdef*\skvgetvalue#1#2#3#4{\skvletcs#4{#1/#2/#3.@value}}
+
+% \skvconveyvalue[<pref>]{<family>}{<key>}<cmd>
+\skvrobustdef*\skvconveyvalue{\skv@testoptb\skv@conveyvalue}
+\skvrobustdef*\skv@conveyvalue#1#2{\skvletcs#2{\skv@header#1.@value}}
+
+% \skvgetinikv{<pref>}{<family>}<cmd>
+\skvrobustdef*\skvgetinikv#1#2#3{\skvletcs#3{#1/#2.@inikv}}
+
+% \skvconveyinikv[<pref>]{<family>}<cmd>
+\skvrobustdef*\skvconveyinikv{\skv@testoptb\skv@conveyinikv}
+\skvrobustdef*\skv@conveyinikv#1{\skvletcs#1{\skvcurrentpath.@inikv}}
+
+% \skvkeyslet[<pref>]{<family>}{<list>}
+%
+% <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\skvkeyinherit\skvkeyslet
+\skvrobustdef*\skv@keyslet#1{%
+ \skvletcs\skv@inikv{\skvcurrentpath.@inikv}%
+ \skvifdefFT\skv@inikv{}{%
+ \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@keyslet@do@b##1##2{%
+ \skvifnamedefFT{\skv@header##2.@cbk}{%
+ \skv@err{Key '\skvcurrentpath/##2'\MessageBreak is undefined}\skv@ehd
+ }{%
+ \skvifnamedefTF{\skv@header##1.@cbk}{%
+ \skv@err{Key '\skvcurrentpath/##1' is already defined}\skv@ehd
+ }{}%
+ }%
+ \skvcommaloop{cbk,ndv,gnv,fbv,gfv}\skv@prova{%
+ \skvcsletcs{\skv@header##1.@\skv@prova}{\skv@header##2.@\skv@prova}%
+ }%
+ \skvifnamedefTF{\skv@header##2.@defa}{%
+ \edef\skvcurrentkey{##2}%
+ \skv@getdefault\skvcurrentprefix\skvcurrentfamily\skvcurrentkey
+ \skvcurrentvalue
+ \skvcsedef{\skv@header##1.@defa}{%
+ \skvnoexpandcs{\skv@header##1}{\skvexpandonce\skvcurrentvalue}%
+ }%
+ \skv@swatrue
+ }{%
+ \skv@swafalse
+ }%
+ \skvifdefFT\skv@inikv{}{%
+ \skvxifinFT{,\detokenize{##2},}{,\skvoxdetok\skv@inikeys,}{}{%
+ \skvcsedef{\skvcurrentpath.@inikv}{%
+ \skvcsaddlist,{\skvcurrentpath.@inikv}%
+ ##1\ifskv@swa=\skvexpandonce\skvcurrentvalue\fi
+ }%
+ }%
+ }%
+ \skvcommaloop{ignoredkeys,needini}\skv@prova{%
+ \skvletcs\skv@tempa{\skvcurrentpath.@\skv@prova}%
+ \skvifdefFT\skv@tempa{}{%
+ \skvxifinFT{,\detokenize{##2},}{,\skvoxdetok\skv@tempa,}{}{%
+ \skvcsedef{\skvcurrentpath.@\skv@prova}{%
+ \skvaddlist,\skv@tempa##1%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \skvkvparse{#1}\skv@prova{%
+ \expandafter\skv@keyslet@do@a\skv@prova==\skv@nil
+ }%
+ \let\do\skvundef
+ \do\skv@keyslet@do\do\skv@inikv\do\skv@inikeys
+}
+
+\skvrobustdef*\skv@disabledkeywarning#1{%
+ \skv@warn{Key '\skvcurrentpath/#1' has been disabled
+ \MessageBreak You can't set or reset key '#1' at this
+ \MessageBreak late stage. Perhaps you should have set it
+ \MessageBreak earlier \ifskv@latex in \noexpand\documentclass or
+ \string\usepackage\fi}%
+}
+\skvrobustdef*\skv@disabledkeyerror#1{%
+ \skv@err{Key '\skvcurrentpath/#1' has been disabled}%
+ {You can't set or reset key '#1' at this
+ \MessageBreak late stage. Perhaps you should have set it
+ \MessageBreak earlier \ifskv@latex in \noexpand\documentclass or
+ \string\usepackage\fi}%
+}
+% 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@disabledkeymsg\skv@disabledkeywarning
+ \or
+ \let\skv@disabledkeymsg\skv@disabledkeywarning
+ \or
+ \let\skv@disabledkeymsg\skv@disabledkeyerror
+ \or
+ \let\skv@disabledkeymsg\@gobble
+ \else
+ \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{%
+ \def\skv@disable@temp{\skv@ordkey@a{e}}%
+ \skv@testoptb\skv@disablekeys
+}
+\skvrobustdef*\skvgdisablekeys{%
+ \def\skv@disable@temp{\skv@ordkey@a{x}}%
+ \skv@testoptb\skv@disablekeys
+}
+\skvrobustdef*\skv@disablekeys#1{%
+ \skvcommaparse{#1}\skv@prova{%
+ \skvifnamedefTF{\skv@header\skv@prova.@cbk}{%
+ \skvifnamedefTF{\skv@header\skv@prova.@defa}{%
+ \edef\skv@provb{\noexpand\skv@disable@temp{\skv@prova}[]}%
+ }{%
+ \edef\skv@provb{\noexpand\skv@disable@temp{\skv@prova}[^skv^]}%
+ }%
+ \expandafter\skv@provb\expandafter{\expandafter
+ \skv@disabledkeymsg\expandafter{\skv@prova}}%
+ }{%
+ \skv@err{Key '\skv@prova' is undefined:
+ \MessageBreak couldn't be disabled}\skv@ehd
+ }%
+ }%
+ \skvundef\skv@disable@temp
+}
+
+% We split xkeyval's \presetkeys (which has both head and tail) into
+% \skvpresetkeys (head only) and \skvpostsetkeys (tail only).
+% We strengthen \presetkeys as \skvpreposetkeys.
+%
+% \skvpresetkeys[<pref>]{<fam>}{<keys>}
+% \skvgpresetkeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvpresetkeys{\skv@testopt\skv@presetkeys\skvdefaultprefix}
+\skvrobustdef*\skv@presetkeys[#1]#2#3{\skvpreposetkeys[#1]{#2}{#3}{}}
+\skvrobustdef*\skvgpresetkeys{\skv@testopt\skv@gpresetkeys\skvdefaultprefix}
+\skvrobustdef*\skv@gpresetkeys[#1]#2#3{\skvgpreposetkeys[#1]{#2}{#3}{}}
+\skvrobustdef*\skvpostsetkeys{\skv@testopt\skv@postsetkeys\skvdefaultprefix}
+\skvrobustdef*\skv@postsetkeys[#1]#2#3{\skvpreposetkeys[#1]{#2}{}{#3}}
+\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}
+\skvrobustdef*\skv@preposetkeys#1#2{%
+ \skvifblankTF{#1}{}{\skv@pr@posetkeys{#1}{preset}}%
+ \skvifblankTF{#2}{}{\skv@pr@posetkeys{#2}{postset}}%
+}
+\skvrobustdef*\skv@pr@posetkeys#1#2{%
+ \skvifcsdefFT{\skvcurrentpath.@#2}{%
+ \skvnormalize{csv}{,}{#1}\skv@tempa
+ \ifskv@cl\expandafter\global\fi
+ \expandafter\def\csname\skvcurrentpath.@#2\expandafter
+ \endcsname\expandafter{\skv@tempa}%
+ }{%
+ % Don't change \skv@filtermergelist to \skvfiltermergelist:
+ \expandafter\skv@filtermergelist\csname\skv@header
+ .@#2\endcsname{#1}\skv@getkeyname
+ }%
+}
+% \skvremovepresetkeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvremovepresetkeys{%
+ \skv@clfalse\skv@testoptb\skv@removepresetkeys
+}
+% \skvgremovepresetkeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvgremovepresetkeys{%
+ \skv@cltrue\skv@testoptb\skv@removepresetkeys
+}
+\skvrobustdef*\skv@removepresetkeys#1{%
+ \skvifcsdefTF{\skvcurrentpath.@preset}{%
+ \expandafter\skv@filterremoveelements\csname\skv@header
+ .@preset\endcsname{#1}\skv@getkeyname
+ }{%
+ \skv@err{No preset keys defined for '\skvcurrentpath'}\skv@ehd
+ }%
+}
+% \skvundefpresetkeys[<pref>]{<fam>}
+\skvrobustdef*\skvundefpresetkeys{%
+ \skv@clfalse\skv@testoptb\skv@undefpresetkeys
+}
+\skvrobustdef*\skvgundefpresetkeys{%
+ \skv@cltrue\skv@testoptb\skv@undefpresetkeys
+}
+\skvrobustdef*\skv@undefpresetkeys{%
+ \skvifcsdefFT{\skvcurrentpath.@preset}{%
+ \skv@err{No preset keys defined for '\skvcurrentpath'}\skv@ehd
+ }{%
+ \ifskv@cl\expandafter\global\fi
+ \skvcsundef{\skvcurrentpath.@preset}%
+ }%
+}
+
+% \skvremovepostsetkeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvremovepostsetkeys{%
+ \skv@clfalse\skv@testoptb\skv@removepostsetkeys
+}
+% \skvgremovepostsetkeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvgremovepostsetkeys{%
+ \skv@cltrue\skv@testoptb\skv@removepostsetkeys
+}
+\skvrobustdef*\skv@removepostsetkeys#1{%
+ \skvifcsdefTF{\skvcurrentpath.@postset}{%
+ \expandafter\skv@filterremoveelements\csname\skv@header
+ .@postset\endcsname{#1}\skv@getkeyname
+ }{%
+ \skv@err{No postset keys defined for '\skvcurrentpath'}\skv@ehd
+ }%
+}
+% \skvundefpostsetkeys[<pref>]{<fam>}
+\skvrobustdef*\skvundefpostsetkeys{%
+ \skv@clfalse\skv@testoptb\skv@undefpostsetkeys
+}
+\skvrobustdef*\skvgundefpostsetkeys{%
+ \skv@cltrue\skv@testoptb\skv@undefpostsetkeys
+}
+\skvrobustdef*\skv@undefpostsetkeys{%
+ \skvifcsdefFT{\skvcurrentpath.@postset}{%
+ \skv@err{No postset keys defined for '\skvcurrentpath'}\skv@ehd
+ }{%
+ \ifskv@cl\expandafter\global\fi
+ \skvcsundef{\skvcurrentpath.@postset}%
+ }%
+}
+
+% \skvremovepreposetkeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvremovepreposetkeys{%
+ \skv@clfalse\skv@testoptb\skv@removepreposetkeys
+}
+% \skvgremovepreposetkeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvgremovepreposetkeys{%
+ \skv@cltrue\skv@testoptb\skv@removepreposetkeys
+}
+\skvrobustdef*\skv@removepreposetkeys#1#2{%
+ \skv@r@movepreposetkeys{#1}{preset}%
+ \skv@r@movepreposetkeys{#2}{postset}%
+}
+\skvrobustdef*\skv@r@movepreposetkeys#1#2{%
+ \skvifcsdefTF{\skvcurrentpath.@#2}{%
+ \expandafter\skv@filterremoveelements\csname\skv@header
+ .@#2\endcsname{#1}\skv@getkeyname
+ }{%
+ \skv@err{No preset keys defined for '\skvcurrentpath'}\skv@ehd
+ }%
+}
+% \skvundefpreposetkeys[<pref>]{<fam>}
+\skvrobustdef*\skvundefpreposetkeys{%
+ \skv@clfalse\skv@testoptb\skv@undefpreposetkeys
+}
+\skvrobustdef*\skvgundefpreposetkeys{%
+ \skv@cltrue\skv@testoptb\skv@undefpreposetkeys
+}
+\skvrobustdef*\skv@undefpreposetkeys{%
+ \skvifcsdefFT{\skvcurrentpath.@preset}{%
+ \skv@err{No preset keys defined for '\skvcurrentpath'}\skv@ehd
+ }{%
+ \ifskv@cl\expandafter\global\fi
+ \skvcsundef{\skvcurrentpath.@preset}%
+ \ifskv@cl\expandafter\global\fi
+ \skvcsundef{\skvcurrentpath.@postset}%
+ }%
+}
+
+%% 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
+% on the macro that has inherited the key's value via these commands.
+
+% \skvneedvaluekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvneedvaluekeys{%
+ \skv@clfalse\skv@testoptb\skv@needvaluekeys
+}
+\skvrobustdef*\skvgneedvaluekeys{%
+ \skv@cltrue\skv@testoptb\skv@needvaluekeys
+}
+\skvrobustdef*\skv@needvaluekeys#1{%
+ \skvcommaparse{#1}\skv@prova{%
+ \ifskv@cl\expandafter\global\fi
+ \skvcsdef{\skv@header\skv@prova.@ndv}{}%
+ }%
+}
+% \skvremoveneedvaluekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvremoveneedvaluekeys{%
+ \skv@clfalse\skv@testoptb\skv@removeneedvaluekeys
+}
+\skvrobustdef*\skvgremoveneedvaluekeys{%
+ \skv@cltrue\skv@testoptb\skv@removeneedvaluekeys
+}
+\skvrobustdef*\skv@removeneedvaluekeys#1{%
+ \skvcommaparse{#1}\skv@prova{%
+ \ifskv@cl\expandafter\global\fi
+ \skvcsundef{\skv@header\skv@prova.@ndv}%
+ }%
+}
+
+% \skvforbidvaluekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvforbidvaluekeys{%
+ \skv@clfalse\skv@testoptb\skv@forbidvaluekeys
+}
+\skvrobustdef*\skvgforbidvaluekeys{%
+ \skv@cltrue\skv@testoptb\skv@forbidvaluekeys
+}
+\skvrobustdef*\skv@forbidvaluekeys#1{%
+ \skvcommaparse{#1}\skv@prova{%
+ \ifskv@cl\expandafter\global\fi
+ \skvcsdef{\skv@header\skv@prova.@fbv}{}%
+ }%
+}
+% \skvremoveforbidvaluekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvremoveforbidvaluekeys{%
+ \skv@clfalse\skv@testoptb\skv@removeforbidvaluekeys
+}
+\skvrobustdef*\skvgremoveforbidvaluekeys{%
+ \skv@cltrue\skv@testoptb\skv@removeforbidvaluekeys
+}
+\skvrobustdef*\skv@removeforbidvaluekeys#1{%
+ \skvcommaparse{#1}\skv@prova{%
+ \ifskv@cl\expandafter\global\fi
+ \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{%
+ \skv@clfalse\skv@testoptb\skv@saveinitialvaluekeys
+}
+% \skvgsaveinitialvaluekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvgsaveinitialvaluekeys{%
+ \skv@cltrue\skv@testoptb\skv@saveinitialvaluekeys
+}
+\skvrobustdef*\skv@saveinitialvaluekeys#1{%
+ \skvifcsdefFT{\skvcurrentpath.@needini}{%
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \skvcsvnormalize\skv@tempa
+ \ifskv@cl\expandafter\global\fi
+ \skvcsedef{\skvcurrentpath.@needini}{\skvexpandonce\skv@tempa}%
+ }{%
+ \expandafter\skv@filtermergelist\csname
+ \skvcurrentpath.@needini\endcsname{#1}\skv@getkeyname
+ }%
+}
+% \skvremovesaveinitialvaluekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvremovesaveinitialvaluekeys{%
+ \skv@clfalse\skv@testoptb\skv@removesaveinitialvaluekeys
+}
+% \skvgremovesaveinitialvaluekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvgremovesaveinitialvaluekeys{%
+ \skv@cltrue\skv@testoptb\skv@removesaveinitialvaluekeys
+}
+\skvrobustdef*\skv@removesaveinitialvaluekeys#1{%
+ \skvifcsdefFT{\skvcurrentpath.@needini}{%
+ \skv@err{No save-initial keys defined for '\skvcurrentpath'}\skv@ehd
+ }{%
+ \expandafter\skv@filterremoveelements\csname
+ \skvcurrentpath.@needini\endcsname{#1}\skv@getkeyname
+ }%
+}
+% \skvundefsaveinitialvaluekeys[<pref>]{<fam>}
+\skvrobustdef*\skvundefsaveinitialvaluekeys{%
+ \skv@clfalse\skv@testoptb\skv@undefsaveinitialvaluekeys
+}
+% \skvgundefsaveinitialvaluekeys[<pref>]{<fam>}
+\skvrobustdef*\skvgundefsaveinitialvaluekeys{%
+ \skv@cltrue\skv@testoptb\skv@undefsaveinitialvaluekeys
+}
+\skvrobustdef*\skv@undefsaveinitialvaluekeys{%
+ \skvifcsdefFT{\skvcurrentpath.@needini}{%
+ \skv@err{No save-initial keys defined for '\skvcurrentpath'}\skv@ehd
+ }{%
+ \csname skv\ifskv@cl g\fi csundef\endcsname{\skvcurrentpath.@needini}%
+ }%
+}
+
+% While setting keys, ignore the listed keys.
+% \skvignorekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvignorekeys{\skv@clfalse\skv@testoptb\skv@ignorekeys}
+\skvrobustdef*\skvgignorekeys{\skv@cltrue\skv@testoptb\skv@ignorekeys}
+\skvrobustdef*\skv@ignorekeys#1{%
+ \skvifcsdefTF{\skvcurrentpath.@ignoredkeys}{%
+ \expandafter\skv@filtermergelist\csname
+ \skvcurrentpath.@ignoredkeys\endcsname{#1}\skv@getkeyname
+ }{%
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \skvcsvnormalize[,]\skv@tempa
+ \ifskv@cl\expandafter\global\fi
+ \skvcsedef{\skvcurrentpath.@ignoredkeys}{\skvexpandonce\skv@tempa}%
+ }%
+}
+% \skvremoveignorekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvremoveignorekeys{%
+ \skv@clfalse\skv@testoptb\skv@removeignorekeys
+}
+% \skvgremoveignorekeys[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\skvgremoveignorekeys{%
+ \skv@cltrue\skv@testoptb\skv@removeignorekeys
+}
+\skvrobustdef*\skv@removeignorekeys#1{%
+ \skvifcsdefFT{\skvcurrentpath.@ignoredkeys}{%
+ \skv@err{No ignore keys defined for '\skvcurrentpath'}\skv@ehd
+ }{%
+ \expandafter\skv@filterremoveelements\csname
+ \skvcurrentpath.@ignoredkeys\endcsname{#1}\skv@getkeyname
+ }%
+}
+% \skvundefignorekeys[<pref>]{<fam>}
+\skvrobustdef*\skvundefignorekeys{%
+ \skv@clfalse\skv@testoptb\skv@undefignorekeys
+}
+% \skvgundefignorekeys[<pref>]{<fam>}
+\skvrobustdef*\skvgundefignorekeys{%
+ \skv@cltrue\skv@testoptb\skv@undefignorekeys
+}
+\skvrobustdef*\skv@undefignorekeys{%
+ \skvifcsdefFT{\skvcurrentpath.@ignoredkeys}{%
+ \skv@err{No ignore keys defined for '\skvcurrentpath'}\skv@ehd
+ }{%
+ \csname skv\ifskv@cl g\fi csundef\endcsname
+ {\skvcurrentpath.@ignoredkeys}%
+ }%
+}
+%
+% 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{%
+ \skv@prependkeycode{prep}{#1}{#2}%
+ \skv@prependkeycode{app}{#1}{#3}%
+}
+\skvnewlet\skvaddtocallback\skvaddkeycode
+% \skvprependkeycode[<pref>]{<fam>}{<key>}{<code>}
+\skvrobustdef*\skvprependkeycode{\skv@testoptb{\skv@prependkeycode{prep}}}
+\skvrobustdef*\skvappendkeycode{\skv@testoptb{\skv@prependkeycode{app}}}
+\skvnewlet\skvprependtocallback\skvprependkeycode
+\skvnewlet\skvapendtocallback\skvappendkeycode
+\skvrobustdef*\skv@prependkeycode#1#2#3{%
+ \edef\skvcurrentkey{\skvtrimspace{#2}}%
+ \skvifcsdefTF{\skv@header\skvcurrentkey.@cbk}{%
+ \skvcsedef{\skv@header\skvcurrentkey.@cbk}{%
+ \skvifstrcmpTF{#1}{prep}{%
+ \skvtrimspace{#3}%
+ \skvexpandcsonce{\skv@header\skvcurrentkey.@cbk}%
+ }{%
+ \skvexpandcsonce{\skv@header\skvcurrentkey.@cbk}%
+ \skvtrimspace{#3}%
+ }%
+ }%
+ }{%
+ \skvcsedef{\skv@header\skvcurrentkey.@cbk}{\skvtrimspace{#3}}%
+ }%
+}
+\skvrobustdef*\skvsetkeys{%
+ \skv@viarootofsetkeystrue
+ \skv@testopta{\skv@testoptc\skv@setkeys@a}%
+}
+\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.
+ \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 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@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
+ \skvletcs\reserved@a{\skvcurrentpath.@#2}%
+ \skvifdefFT\reserved@a{}{%
+ \skvexpandtwoargs\skv@setkeys@b{\skvexpandonce\reserved@a}%
+ {\skvaddlist,\skv@currentnames\unexpanded{#1}}%
+ }%
+ }%
+ \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.
+%
+\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
+ \ifnum\skv@setkeysdepth>\skv@stackdepthlimit\relax
+ \skv@err{\noexpand\skvsetkeys is nested too deeply.
+ \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}%
+ \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}%
+ \ifx\skvcurrentvalue\@empty
+ \skvnovaluetrue
+ \else
+ \skvnovaluefalse
+ \fi
+ \else
+ \skv@err{A parenthesized key can't have pointers}\skv@ehd
+ \fi
+ }{%
+ \skv@err{Key value has '(' but no ')'}
+ {The value of a parenthesized key must have both opening
+ \MessageBreak parenthesis '(' and closing ')'.}%
+ }%
+ }{%
+ \def\skv@ispntkey{01}%
+ \skv@g@tkeyname#1=\skv@getname@nil\skvcurrentkey
+ }%
+ % ##1=value:
+ \def\skv@prova##1=##2\skv@setkeys@nil{%
+ \skvifknobTF{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}\skv@ehd
+ \fi
+ \fi
+ \skvifdefboolTF{skv@processvalueaslist}{%
+ % You can use the pointer '.process list', etc, 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=\skvxonce\skvcurrentvalue\fi
+ }%
+ \skv@setkeys@d
+ }%
+ }%
+ \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
+ }%
+ }%
+ \skvpopstate\skv@keystate\skv@keydepth
+}
+\skvrobustdef*\skv@setkeys@d{%
+ \begingroup
+ \skv@swatrue
+ \skvxifinTF{,\skvcurrentkey,}{,\skv@na,}{\skv@swafalse}{}%
+ \skvletcs\skv@tempa{\skvcurrentpath.@ignoredkeys}%
+ \skvifdefTF\skv@tempa{%
+ \skvxifinTF{,\skvcurrentkey,}{,\skv@tempa,}{\skv@swafalse}{}%
+ }{}%
+ \skvaftergroupifboolFT skv@swa\endgroup{}{%
+ \skv@kffalse
+ \skvifdefboolTF{skv@inprepo}{%
+ \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
+ }%
+ }{%
+ % 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}{%
+ \ifskv@inclass\skvafterfi
+ \expandafter\skv@removeoption\expandafter{\CurrentOption}%
+ \fi
+ }{}%
+ }{%
+ \skvifdefboolTF{skv@inpox}{%
+ \skvifcsdefTF{\skvcurrentpath.@famhandler}{%
+ \begingroup
+ \let\elt\skvexpandonce
+ \skvexpanded{\endgroup
+ \skvnoexpandcs{\skvcurrentpath.@famhandler}%
+ {\elt\skvcurrentprefix}{\elt\skvcurrentfamily}%
+ {\elt\skvcurrentkey}{\elt\skvcurrentvalue}%
+ }%
+ }{%
+ \skvifcsdefTF{skv@dox@\@currname.\@currext}{%
+ \skvcsuse{skv@dox@\@currname.\@currext}%
+ }{%
+ \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@st}{%
+ \skv@setkeys@f
+ }{%
+ \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
+ \skv@err{Key '\skvcurrentfullkey'
+ \MessageBreak is undefined}\skv@ehd
+ \fi
+ }%
+ }%
+ }%
+ }%
+ }%
+}
+\skvrobustdef*\skv@setkeys@e{%
+ \skvifcsdefFT{\skv@header\skvcurrentkey.@cbk}{%
+ \ifskv@intry\skv@successfalse\fi
+ }{%
+ \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'
+ \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
+ % Check if the default value is braced:
+ \skvexpbracenext\skvifbracedFT\skvcurrentvalue{}{%
+ \skvvaluebracedtrue
+ }%
+ }{%
+ \skv@err{No value specified for key
+ \MessageBreak'\skvcurrenttriple'
+ \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.}\skv@ehd
+ }{}%
+ \fi
+ \skvifemptyTF\skvcurrentvalue{}{%
+ \expandafter\skv@replacepointers\expandafter{\skvcurrentvalue}%
+ }%
+ \skvletcs\skv@callback{\skv@header\skvcurrentkey.@cbk}%
+ \skv@getargpattern
+ \edef\skv@callback{%
+ \let\noexpand\this\noexpand\skvcurrentkey
+ \skvexpandonce\skv@callback
+ }%
+ % 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 may be more complex:
+ \ifx\skv@argpattern\skv@simplearg\else
+ \ifcsname\skv@header\skvcurrentkey.@listkey\endcsname
+ \skv@err{A listkey must have only a one-parameter argument}\skv@ehd
+ \else
+ \skvstripouterbraces{2}\skvcurrentvalue
+ \skvvaluebracedfalse
+ \fi
+ \fi
+ \skvcslet{\skv@header\skvcurrentkey.@value}\skvcurrentvalue
+ \skvpushstate\skv@keystate\skv@keydepth
+ \expandafter\expandafter\expandafter\def\expandafter\expandafter
+ \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{%
+ \skvexpanded{%
+ \skvmergelist\noexpand\skv@rmkeys{\skvexpandonce\CurrentOption}%
+ % The boolean \ifdirkeys@saveunknownkeys is, by default, false.
+ % The default value of \dirkeys@unknownkeysmacro is \skvfaillist.
+ \ifindirectkeys
+ \ifdirkeys@saveunknownkeys
+ \skvmergelist\skvexpandonce\dirkeys@unknownkeysmacro
+ {{\skvcurrentprefix}/{\skvcurrentfamily}/%
+ {\skvexpandonce\CurrentOption}}%
+ \fi
+ \fi
+ }%
+}
+% \skv@getdefault{<pref>}{<fam>}{<key>}{<return.macro>}
+\skvrobustdef*\skv@getdefault#1#2#3#4{%
+ \begingroup
+ \let\elt\relax
+ \edef\skv@prova{\elt{#1}/\elt{#2}/\elt{#3}}%
+ \let\elt\skvtrimspace
+ \edef\skv@prova{\skv@prova}%
+ \def\skv@g@tdefault##1##2\skv@nil{%
+ \edef\skv@provb{\skvremovescape{##1}}%
+ \@onelevel@sanitize\skv@prova
+ \ifx\skv@prova\skv@provb
+ \skvcsdef{\skv@prova}####1{\edef#4{\unexpanded{####1}}}%
+ \csname\skv@prova.@defa\endcsname
+ \else
+ \skv@err{The default value syntax of key
+ \MessageBreak '\skv@prova' doesn't conform to
+ \MessageBreak skeyval format. Maybe another package
+ \MessageBreak has abused the format}
+ {I can't extract the default value of key '\skv@prova'.}%
+ \fi
+ }%
+ % <default.macro><key.macro>
+ \expandafter\expandafter\expandafter\skv@g@tdefault
+ \csname\skv@prova.@defa\endcsname\skv@nil
+ \skvaftergroupdef#4\endgroup
+}
+% Set keys using their default values:
+% \skvinitializekeys[<pref>]{<fams>}[<ignored.keys>]
+\skvrobustdef*\skvinitializekeys{\skv@testoptc\skv@initializekeys}
+% #1: ignored keys
+\skvrobustdef*\skv@initializekeys[#1]{%
+ \begingroup
+ \def\skv@tempe{}%
+ % \skv@testoptc has created \skvcurrentprefix and \skv@fams.
+ \skvcommaloop*\skv@fams\skv@tempa{%
+ \skv@makeheader\skv@tempa
+ \skvletcs\skv@tempa{\skvcurrentpath.@inikv}%
+ \skvifdefFT\skv@tempa{%
+ \skv@err{No 'save initial value' keys defined in family
+ \MessageBreak'\skvcurrentpath'}\skv@ehd
+ }{%
+ % '\skvcurrentpath.@poxkeys' is the list of keys that have been
+ % instantiated as current pacakge options.
+ \skvletcs\skv@tempc{\skvcurrentpath.@poxkeys}%
+ \skvifdefFT\skv@tempc{%
+ \edef\skv@tempe{%
+ \skvexpandonce\skv@tempe
+ \skvsetkeys[\skvcurrentprefix]{\skvcurrentfamily}%
+ [#1]{\skvexpandonce\skv@tempa}%
+ }%
+ }{%
+ % Filter pox (instantiated package/article options) list members.
+ % Pox keys can't be initialized.
+ \def\skv@tempd{}%
+ \skvcommaloop*\skv@tempa\skv@tempa{%
+ \expandafter\skv@g@tkeyname\skv@tempa=\skv@getname@nil\skv@tempb
+ \skvxifinTF{,\skvoxdetok\skv@tempb,}{,\skvoxdetok\skv@tempc,}{}{%
+ \edef\skv@tempd{%
+ \skvaddlist,\skv@tempd\skvexpandonce\skv@tempa
+ }%
+ }%
+ }%
+ \edef\skv@tempe{%
+ \skvexpandonce\skv@tempe
+ \skvsetkeys[\skvcurrentprefix]{\skv@fams}[#1]%
+ {\skvexpandonce\skv@tempd}%
+ }%
+ }%
+ }%
+ }%
+ \expandafter\endgroup\skv@tempe
+}
+
+%+++++++++++++++++++++ Compactly define keys +++++++++++++++++++++++++%
+%
+% \skvdefinekeys*+[<pref>]{<fams>}[<hp>]{<list>}
+% * -> define only new keys.
+% + -> define in all the given families.
+%
+% The only difference between \skvedefinekeys and \skvdefinekeys is the
+% value of \endlinechar.
+%
+% Examples:
+%
+% \skvdefinekeys*+[KVA]{fam1,fam2}[thp@]{%
+% .initialize keys after define=true,
+% .save initial values,
+% .prepend to every key name=X@,
+% .ord/{keya,keyb}/{default-a},
+% .cmd/{keyc,keyd}/,
+% .zcmd/key e/\def\cmde##1{##1}/
+% \edef\y{\detokenize\expandafter{\thp@keye}}\def\x##1{#1*key e*##1},
+% .choice/keyf/center/{center.do=\def\x##1{#1*##1},left,right}/
+% \def\f##1{#1*##1}/\@@warning{Invalid value for keyf},
+% .zbool/show center/true/\edef\cmd{\ifthp@showcenter Yes\else No\fi}/
+% \@@warning{Invalid value for show center},
+% .arg/{key1,key2}/{#1/#2},
+% .arg/key3/{#1+#2},
+% .exec/\def\x##1{##1},
+% .exec code=\def\y##1{##1},
+% }
+% \skvshowcs{KVA/fam1/keyb.@defa}
+% \def\keybval{xx}
+% \skvsetkeys[KVA]{fam1}{keyb=.expand once{\keybval}}
+%
+\skvnewbools[skvdfk@]{saveinitialvalues,initialize}
+% '.initialize' means set the keys with their default values after
+% 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
+ }%
+}
+\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}
+
+% Set aliases for handlers used in \skvdefinekeys:
+\skvrobustdef*\skvtypecastfordefinekeys#1{%
+ \begingroup
+ \def\skv@tempa{}%
+ \skvkvparse{#1}\skv@prova{%
+ \skv@okvsplit\skv@prova{%
+ \def\skv@keytypecast####1{%
+ \skvifcsdefTF{skvdfk@typealias@####1}{%
+ \skv@err{Key type alias '####1' already defined}\skv@ehd
+ }{%
+ \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
+}
+\skvtypecastfordefinekeys{%
+ {.singleton,.state pattern}=.choice,
+ .exec code=.exec,
+ {.arg,.args}=.argx0,
+ .arg expand once=.argx1,
+ .arg expand twice=.argx2,
+ .arg expanded=.argxx,
+ {.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
+}
+\skvrobustdef*\skvdfk@testopta#1{%
+ \skvifstar{%
+ \skv@sttrue
+ \skvifplus
+ {\skv@pltrue\skvdfk@testoptb#1}
+ {\skv@plfalse\skvdfk@testoptb#1}%
+ }{%
+ \skv@stfalse
+ \skvifplus
+ {\skv@pltrue\skvdfk@testoptb#1}
+ {\skv@plfalse\skvdfk@testoptb#1}%
+ }%
+}
+\skvrobustdef*\skvdfk@testoptb#1{%
+ \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'}\skv@ehd
+ }{%
+ % The prefix and families here deserve separate names, to avoid
+ % confusing them with those required for setting the keys of the
+ % macro \skvdefinekeys.
+ \edef\skv@checkkeyexist{\ifskv@st00\else01\fi}%
+ \edef\skvdfk@pref{#2}%
+ \skvxifinTF{,}{\detokenize{#3}}{%
+ \edef\skvdfk@fams{#3}%
+ \skvcsvnormalize\skvdfk@fams
+ }{%
+ \edef\skvdfk@fams{#3}%
+ \skvdespacecontent\skvdfk@fams
+ }%
+ \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{%
+ \begingroup
+ \endlinechar\m@ne
+ \skvdfk@testopta\skv@definekeys@a
+}
+\skvrobustdef*\skvdefinekeys{%
+ \begingroup
+ \skvdfk@testopta\skv@definekeys@a
+}
+\skvrobustdef*\skv@definekeys@a[#1]#2{%
+ \skvindeftrue
+ \def\skv@validtypes{%
+ .ord,.cmd,.zcmd,.bool,.zbool,.tog,.ztog,.choice,.choice*,%
+ .exec,.afterdef,.initialize,.saveini,.argx0,.argx1,.argx2,.argxx,%
+ .preptokey,.apptokey,.preptocode,.apptocode%
+ }%
+ \def\iftypeis##1\then{%
+ \ifnum\skv@strcmp{\skvoxdetok\skv@type}{\detokenize{##1}}=\skvz@
+ }%
+ \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
+ \skv@makeprefix\skvdfk@pref
+ \edef\skvdfk@currlist{\skvkeepdoubleslashnormalize{#2}}%
+ \def\skv@definekeys@b##1{%
+ \skv@makeheader{##1}%
+ \def\skv@accumulateonkeys{}%
+ \def\skvdfk@keys{}%
+ \def\skvdfk@keyvals{}%
+ \skvexpbracenext\skv@definekeys@c\skvdfk@currlist
+ }%
+ % If the plus variant is not specified, just take and use the first
+ % family.
+ \skvifdefboolTF{skv@pl}{%
+ \skvcommaloop*\skvdfk@fams\skv@tempa{%
+ \skvexpbracenext\skv@definekeys@b\skv@tempa
+ }%
+ }{%
+ \def\skv@prova##1,##2\skv@nil{%
+ \skv@definekeys@b{##1}%
+ }%
+ \expandafter\skv@prova\skvdfk@fams,\skv@nil
+ }%
+ \edef\skv@accumulateonfams{%
+ \skvxonce\skv@accumulateonfams
+ \skvxonce\skvdfk@afterdefine@hook\relax
+ }%
+ \expandafter\endgroup\skv@accumulateonfams
+ \skvindeffalse
+ % 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: \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\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}\skv@ehd
+ }{%
+ % In case we have, eg, .exec=\def\x{?} instead of .exec/\def\x{?}:
+ \skvxifinTF{=}{\detokenize{##1}}{%
+ \skv@kvsplit{##1}{%
+ \edef\skv@type{\skvtrimspace{####1}}%
+ \edef\skv@itemtwo{\skvtrimspace{####2}}%
+ }%
+ }{%
+ \edef\skv@type{\unexpanded{##1}}%
+ \edef\skv@itemtwo{\unexpanded{##2}}%
+ }%
+ }%
+ \skvifcsname skvdfk@typealias@\skv@type\then
+ \edef\skv@type{\@nameuse{skvdfk@typealias@\skv@type}}%
+ \fi
+ \edef\skv@default{\skvexpandonce{\@gobble##3}}%
+ % To avoid mixing parameter characters in \skv@prova:
+ \edef\skv@rest{\unexpanded{{##4}/{##5}/{##6}/{##7}/{##8}/{##9}}}%
+ \skvexpbracenext\skv@definekeys@d\skv@type
+ }%
+ \def\skv@splitc##1/##2/##3/##4/##5/##6/##7/##8/##9\skv@split@nil{%
+ \edef\skv@itemfour{\unexpanded{##4}}%
+ \edef\skv@itemfive{\unexpanded{##5}}%
+ \edef\skv@itemsix{\unexpanded{##6}}%
+ \skvifknobTF{skv@isarg}{%
+ \skvdfk@definearg{##1}{##2}{##3}%
+ }{%
+ \if\skv@checkkeyexist
+ \skvifcsname\skv@header##2.@cbk\then
+ \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'}\skv@ehd
+ }{}%
+ \fi
+ \edef\skvdfk@keys{\skvaddlist,\skvdfk@keys##2}%
+ \skvxifboolvalTF{\skvexpandonce\skv@default}\in@true\in@false
+ \edef\skvdfk@keyvals{%
+ \skvaddlist,\skvdfk@keyvals
+ \skv@ifcmdrejordotna\skv@default{}{%
+ ##2=\skvifdefboolTF{in@}{false}{\skvexpandonce\skv@default}%
+ }%
+ }%
+ \if\skv@isboolorchoice
+ \if\skv@ischoice
+ \let\skv@altact\skv@itemsix
+ \else
+ % bool or tog:
+ \let\skv@altact\skv@itemfive
+ \fi
+ \skv@ifcmdnut\skv@altact{\let\skv@altact\skvkeyvalueerror}{}%
+ \fi
+ \iftypeis.choice*\then
+ \def\skv@prova####1*{\def\skv@typeb{####1}}%
+ \expandafter\skv@prova\skv@type
+ \else
+ \let\skv@typeb\skv@type
+ \fi
+ % Remove leading dot (.):
+ \edef\skv@typeb{\expandafter\@gobble\skv@typeb}%
+ \edef\skv@accumulateonkeys{%
+ \skvexpandonce\skv@accumulateonkeys
+ \skvnoexpandcs{skv\skv@typeb key}%
+ \iftypeis.choice*\then*\fi
+ \if\skv@isboolorchoice+\fi
+ [\skvcurrentprefix]{\skvcurrentfamily}%
+ \if\skv@needhp[\skv@hp]\fi
+ {##2}%
+ \if\skv@ischoice
+ [\unexpanded{\skvuserinput\skvorder}]{\skvxonce\skv@itemfour}%
+ \fi
+ % default:
+ \skv@ifcmdrejordotna\skv@default{}{[{\skvxonce\skv@default}]}%
+ {% Key callback:
+ \skvxonce\skv@prependtoeverycallback
+ % If choice key, then the callback is item 5, otherwise
+ % it's item 4:
+ \if\skv@ischoice
+ \skv@ifcmdnut\skv@itemfive{}{\skvxonce\skv@itemfive}%
+ \else
+ \skv@ifcmdnut\skv@itemfour{}{\skvxonce\skv@itemfour}%
+ \fi
+ \skvxonce\skv@appendtoeverycallback
+ }%
+ % Second branch of callback for '+' variants, now used for all
+ % boolean and choice keys:
+ \if\skv@isboolorchoice{\skvexpandonce\skv@altact}\fi
+ }%
+ }%
+ }%
+ \skvexpanded{\skvparselist{\skvdfk@parser}}{#1}\skv@prova{%
+ \expandafter\skv@splita\skv@prova
+ /^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^/^skv^\skv@split@nil
+ }%
+ % 1. \skv@accumulateonfams is a two-layer stack: there're loops on
+ % families and keys.
+ % 2. To save initial values of keys, the key names should be
+ % entered by \skvsaveinitialvaluekeys in 'needini' list. This is
+ % the case even when the boolean '.initialize' is true. See below.
+ % 3. The boolean '.save initial values' is the one that will invoke
+ % \skvsaveinitialvaluekeys below.
+ \def\@elt{%
+ [\skvcurrentprefix]{\skvcurrentfamily}{\skvxonce\skvdfk@keyvals}%
+ }%
+ \edef\skv@accumulateonfams{%
+ \skvexpandonce\skv@accumulateonfams
+ \ifskvdfk@saveinitialvalues
+ \noexpand\skvsaveinitialvaluekeys\@elt
+ \fi
+ \skvexpandonce\skv@accumulateonkeys
+ \ifskvdfk@initialize
+ \noexpand\skvsetkeys\@elt
+ \fi
+ }%
+}
+\skvrobustdef*\skv@definekeys@d#1{%
+ \skvxifinFT{,#1,}{,\skv@validtypes,}{%
+ \skv@err{Invalid key type '#1' in \string\skvdefinekeys}\skv@ehd
+ }{%
+ \@tempswatrue
+ \iftypeis.exec\then
+ \@tempswafalse
+ \edef\skv@accumulateonkeys{%
+ \skvexpandonce\skv@accumulateonkeys\skvexpandonce\skv@itemtwo
+ }%
+ \else
+ \iftypeis.initialize\then
+ \@tempswafalse
+ \skv@ifcmdnut\skv@itemtwo{%
+ \edef\skv@itemtwo{true}%
+ }{%
+ \skvexpbracenext\skvifboolvalT\skv@itemtwo\relax
+ }%
+ \csname skvdfk@initialize\skv@itemtwo\endcsname
+ \edef\skv@accumulateonfams{%
+ \skvexpandonce\skv@accumulateonfams
+ \noexpand\csname skvdfk@initialize\skv@itemtwo\endcsname
+ }%
+ \else
+ \iftypeis.saveini\then
+ \@tempswafalse
+ \skv@ifcmdnut\skv@itemtwo{%
+ \edef\skv@itemtwo{true}%
+ }{%
+ \skvexpbracenext\skvifboolvalT\skv@itemtwo\relax
+ }%
+ \csname skvdfk@saveinitialvalues\skv@itemtwo\endcsname
+ \edef\skv@accumulateonfams{%
+ \skvexpandonce\skv@accumulateonfams
+ \noexpand\csname skvdfk@saveinitialvalues\skv@itemtwo
+ \endcsname
+ }%
+ \else
+ \iftypeis.preptokey\then
+ \@tempswafalse
+ \let\skv@prependtoeverykeyname\skv@itemtwo
+ \else
+ \iftypeis.apptokey\then
+ \@tempswafalse
+ \let\skv@appendtoeverykeyname\skv@itemtwo
+ \else
+ \iftypeis.preptocode\then
+ \@tempswafalse
+ \let\skv@prependtoeverycallback\skv@itemtwo
+ \else
+ \iftypeis.apptocode\then
+ \@tempswafalse
+ \let\skv@appendtoeverycallback\skv@itemtwo
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \skvifdefboolTF{@tempswa}{%
+ % Leave these tests here, so that they aren't repeated for each
+ % key in the next loop:
+ \def\do##1{\def##1{01}}%
+ \do\skv@isboolorchoice\do\skv@ischoice\do\skv@needhp\do\skv@isarg
+ \skvifinTF{,#1,}{,.choice,.choice*,}{%
+ \skvstripouterbraces{2}\skv@default
+ \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}%
+ \def\skv@needhp{00}%
+ }{%
+ \skvifinTF{,#1,}{,.cmd,.zcmd,}{%
+ \def\skv@needhp{00}%
+ }{%
+ \skvifinTF{,#1,}{,.argx0,.argx1,.argx2,.argxx,}{%
+ \def\skv@isarg{00}%
+ }{}%
+ }%
+ }%
+ }%
+ \skvcommaloop*\skv@itemtwo\skv@tempa{%
+ \skv@strippointersfromkey*\skv@tempa
+ \edef\skvcurrentkey{%
+ \skv@prependtoeverykeyname\skvcurrentkey
+ \skv@appendtoeverykeyname
+ }%
+ \let\do\skvoxdetok
+ \skvxifinTF{,\do\skvcurrentkey,}{,\do\skv@igkeys,}{}{%
+ \edef\do{%
+ \noexpand\skv@splitc#1/\skvcurrentkey/%
+ {\skvexpandonce\skv@default}/\skvexpandonce\skv@rest
+ }%
+ \do\skv@split@nil
+ }%
+ }%
+ }{%
+ \skvifinFT{,#1,}{,.preptokey,.apptokey,.preptocode,.apptocode,}{}{%
+ \let\skv@tempa\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}\skv@ehd
+ \fi
+ }%
+ }%
+ }%
+}
+%
+% Assigning arguments within \skvdefinekeys:
+%
+% Eg, using the type .arg:
+%
+% .arg/{key1,key2}/{#1/#2}
+%
+\skvrobustdef*\skvdfk@definearg#1#2#3{%
+ \begingroup
+ \def\skv@prova.arg##1\skv@nil{%
+ \edef\skv@prova{\skvtrimspace{##1}}%
+ }%
+ \skv@prova#1\skv@nil
+ \edef\skv@accumulateonkeys{%
+ \skvexpandonce\skv@accumulateonkeys
+ \skvcsedef{\skv@header#2.@\skv@prova arg}{%
+ \noexpand\unexpanded{\unexpanded{#3}}%
+ }%
+ }%
+ \skvaftergroupdef\skv@accumulateonkeys\endgroup
+}
+
+%+++++++++++++++++++++++ Keys for \skvmakekeys +++++++++++++++++++++++%
+% Example:
+% \skvmakekeys[
+% .prefix=KVA, .families={fam1,fam2}, .hp=thp@, .all new,
+% .define in all families, .initialize=true, .endlinechar=-1
+% ]{%
+% .ord/{keya,keyb}/{default-a},
+% .cmd/{keyc,keyd}/,
+% .zcmd/key e/\def\cmde##1{##1}/
+% \edef\y{\detokenize\expandafter{\thp@keye}}\def\x##1{#1*key e*##1},
+% .choice/keyf/center/{center.do=\def\x##1{#1*##1},left,right},
+% .zbool/show center/true/\edef\cmd{\ifthp@showcenter Yes\else No\fi}
+% }
+% \skvshowcs{KVA/fam1/keyb.@defa}
+% \def\keybval{xx}
+% \skvsetkeys[KVA]{fam1}{keyb=.expand once{\keybval}}
+
+\skvedefinekeys*[SKV]{makekeys}[skvmk@]{%
+ .ord/{.new,.all new,.all are new}/true/
+ \edef\skvmk@allnew{0\skvifstrcmpTF{#1}{true}{0}{1}}
+ ,
+ .ord/{.initialize,.initialize after define,.initialize keys after define}
+ /true/
+ \skvifboolvalT{#1}{%
+ \csname skvdfk@initialize#1\endcsname
+ }%
+ ,
+ .ord/.save initial values,.save initial values of keys/true/
+ \skvifboolvalT{#1}{%
+ \csname skvdfk@saveinitialvalues#1\endcsname
+ }%
+ ,
+ .ord/{.endlinechar,.endline character}/13/
+ \def\skvmk@endlinechar{#1},
+ .ord/{.define in all families,.in all families}/true/
+ \edef\skvmk@inallfams{0\skvifstrcmpTF{#1}{true}{0}{1}}
+ ,
+ .ord/.prefix/\skvdefaultprefix/
+ \skviflacus#1\then
+ \let\skvmk@pref\skvdefaultprefix
+ \else
+ \edef\skvmk@pref{#1}%
+ \skvstripouterbraces{2}\skvmk@pref
+ \fi
+ ,
+ .ord/{.family,.families}/\skv@nil/
+ \skviflacus#1\then
+ \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
+% inefficient here, since many of the keys have complements. It will be
+% necessary to include all the complements in the preset list, but doing
+% this will be inefficient.
+\skvsetkeys[SKV]{makekeys}{%
+ .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{%
+ \do\skvmk@pref\do\skvmk@fams\do\skvmk@allnew\do\skvmk@hp
+ \do\skvmk@endlinechar\do\skvmk@inallfams\do\ifskvdfk@initialize
+ \do\ifskvdfk@saveinitialvalues
+ }\skv@makekeysdepth
+ \skvsetkeys[SKV]{makekeys}{#1}%
+ \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
+ \skvexpanded{%
+ \endlinechar=\skvmk@endlinechar\relax
+ \skvdfk@testopta\skv@definekeys@a
+ \if\skvmk@allnew*\fi\if\skvmk@inallfams+\fi
+ [\skvmk@pref]{\skvmk@fams}%
+ [\ifx\skvmk@hp\@empty userhp@\else\skvmk@hp\fi]%
+ }%
+ {#2}%
+ \skvpopfunctions\skvmakekeys\skv@makekeysdepth
+}
+
+\skvrobustdef*\skvkeyvalueerror{%
+ \skv@getinnoval\CurrentOption
+ \skv@err{Erroneous value '\skv@ival' for key or option
+ \MessageBreak'\skvcurrentkey'}{Invalid key value encountered.}%
+}
+
+\skvrobustdef*\skv@getinnoval#1{%
+ \begingroup
+ \skv@okvsplit{#1}{%
+ \edef\skv@provb{\detokenize{##2}}%
+ \skvifxTF\skv@provb\@empty{%
+ \def\skv@ival{???}%
+ }{%
+ \skv@getshortformofcontent{30}\skv@provb\skv@ival
+ }%
+ }%
+ \skvaftergroupdef\skv@ival\endgroup
+}
+% \skv@getshortformofcontent{<nr>}{<toks.cmd>}{<result.cmd>}
+\skvrobustdef*\skv@getshortformofcontent#1#2#3{%
+ \begingroup
+ \edef\skv@prova{\detokenize\expandafter{#2}}%
+ \def#3{}\@tempcnta\skvz@
+ \def\do##1{%
+ \def\skv@prova{##1}%
+ \skvifxTF\skv@prova\skv@nnil{}{%
+ \advance\@tempcnta\@ne
+ \ifnum\@tempcnta<#1\relax
+ \edef#3{#3\ifx\next\@sptoken\@space\fi##1}%
+ \else
+ \def\@do####1\skv@nil{}%
+ \fi
+ \@do
+ }%
+ }%
+ \def\@do{\futurelet\next\do}%
+ \expandafter\@do\skv@prova\skv@nil
+ \skvaftergroupdef#3\endgroup
+}
+
+% +++++++++++ User-defined handlers for unknown keys. +++++++++++++%
+%
+% \skvunknownkeyhandler[<prefixes>]{<families>}{<handler>}
+%
+% Note: See skeyval.sty for \skvunknownoptionhandler.
+%
+% Eg, for keya undefined in KV/fam:
+%
+% \skvunknownkeyhandler[KV]{fam}{%
+% \skvordkey[#1]{#2}{#3}[#4]{\def\x##1{##1xx#4}}%
+% }
+% \skvsetkeys[KV]{fam}{unknownkey=val}
+%
+\skvrobustdef*\skvunknownkeyhandler{%
+ \skv@testopt\skv@unknownkeyhandler\skvdefaultprefix
+}
+% For each prefix and family, this will define the functions
+% \<prefix>/<family>/.@famhandler of 4 parameters (prefix, family,
+% key name, current value).
+\skvrobustdef*\skv@unknownkeyhandler[#1]#2#3{%
+ \skvcommaloop{#1}\skv@tempa{%
+ \skv@makeprefix\skv@tempa
+ \skvcommaloop{#2}\skv@tempb{%
+ \skv@makeheader\skv@tempb
+ \skvcsdef{\skvcurrentpath.@famhandler}##1##2##3##4{#3}%
+ }%
+ }%
+}
+
+%%++++++++++++++++++++++ Keys for \skvusekeys: +++++++++++++++++++++++%%
+% Example:
+% \skvusekeys[
+% .prefix=KVA,.families={fam1,fam2},.set in all families,
+% .save rm keys
+% ]{%
+% key1=value1, key2=value2
+% }
+\skvmakekeys[
+ .prefix=SKV,.family=usekeys,.hp=skvuk@,.endlinechar=-1
+]{%
+ .ord/{.save rm,.save rm keys,.save unknown keys}/true/
+ \edef\skvuk@saverm{\skvifstrcmpTF{#1}{true}{00}{01}}
+ ,
+ .ord/{.set in all families,.in all families}/true/
+ \edef\skvuk@inallfams{\skvifstrcmpTF{#1}{true}{00}{01}}
+ ,
+ .ord/.prefix/\skvdefaultprefix/
+ \skviflacus#1\then
+ \let\skvuk@pref\skvdefaultprefix
+ \else
+ \edef\skvuk@pref{#1}%
+ \skvstripouterbraces{2}\skvuk@pref
+ \fi
+ ,
+ .ord/{.family,.families}/\skv@nil/
+ \skviflacus#1\then
+ \skv@err{Key family is empty\on@line}\skv@ehd
+ \else
+ \edef\skvuk@fams{#1}%
+ \skvstripouterbraces{2}\skvuk@fams
+ \fi
+ ,
+ .ord/{.path,paths}/\skv@nil/
+ \skvifblankTF{#1}{%
+ \skv@err{Key family is empty\on@line}\skv@ehd
+ }{%
+ \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,.set in all families=false,.save rm=false%
+}
+
+\skvrobustdef*\skvusekeys{\skv@testopt\skv@usekeys{}}
+\skvrobustdef*\skv@usekeys[#1]#2{%
+ \skvpushfunctions\skvusekeys{%
+ \do\skvuk@fams\do\skvuk@pref\do\skvuk@inallfams\do\skvuk@saverm
+ }\skv@usekeysdepth
+ \skvsetkeys[SKV]{usekeys}{#1}%
+ \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
+ [\skvuk@pref]{\skvuk@fams}{\unexpanded{#2}}%
+ }%
+ \skvpopfunctions\skvusekeys\skv@usekeysdepth
+}
+
+%++++++++++ Utilities for handlers of the macro \directkeys +++++++++++%
+
+\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>'.
+\skvundef\dirkeys@handler@
+
+\skvrobustdef*\skvsetdirectkeysparser{\def\dirkeys@parser}
+\skvsetdirectkeysparser{,}
+\skvrobustdef*\directkeys{\skv@testst\skv@dirkeys@parse@a}
+\skvrobustdef*\skv@dirkeys@parse@a{%
+ \begingroup
+ \ifskv@tempst\endlinechar\m@ne\fi
+ \skv@dirkeys@parse@b
+}
+\skvrobustdef*\skv@dirkeys@parse@b#1{%
+ \endgroup
+ \skvpushstate\skv@dirkeys@state\dirkeys@depth
+ \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 \directkeys. If it is, then
+ % we have a nested \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}\skv@ehd
+ }%
+ }{%
+ \skv@ensurehandlerdot{##1}%
+ \skvifcsdefTF{dirkeys@handler@##1}{%
+ \csname dirkeys@handler@##1\expandafter\endcsname
+ \skv@tempa\skvhandlereov
+ }{%
+ \skv@err{Unknown handler '\detokenize{##1}'
+ \MessageBreak in command \string\directkeys, or no '=' sign
+ \MessageBreak after handler name}\skv@ehd
+ }%
+ }%
+ }%
+ % Normalize with respect to \dirkeys@parser:
+ \skvexpanded{\skvparselist*{\dirkeys@parser}}\skv@tempa\skv@tempa{%
+ \expandafter\skv@dirkeys@split\skv@tempa==\dirkeys@nil
+ }%
+ \indirectkeysfalse
+ \skvpopstate\skv@dirkeys@state\dirkeys@depth
+}
+\skvrobustdef*\dirkeys@setdefaultpath{%
+ \ifx\dirkeys@pathlist\@empty
+ \ifskv@inopt
+ \edef\dirkeys@pathlist{%
+ \noexpand\skv@pathdo{KV}{\@currname.\@currext}%
+ }%
+ \else
+ \skv@err{No key can have empty or nil path/family}\skv@ehd
+ \fi
+ \fi
+ \ifx\dirkeys@holderprefixtoks\@empty
+ \def\dirkeys@holderprefixtoks{user@}%
+ \fi
+}
+\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@dodefinekeys#1#2{%
+ \begingroup
+ % #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{}%
+ \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
+}
+% \dirkeys@definetypekeys{<type>}{<star.or.empty>}{<keylist>}
+\skvrobustdef*\dirkeys@definetypekeys#1#2#3{%
+ \begingroup
+ \def\skv@tempa{}%
+ \skvexpanded{\skvparselist{\skvdfk@parser}}{#3}\skv@prova{%
+ \edef\skv@tempa{%
+ \skvexpandonce\skv@tempa
+ \ifx\skv@tempa\@empty\else\skvdfk@parser\fi
+ .#1/\skvexpandonce\skv@prova
+ }%
+ }%
+ \skvexpanded{\endgroup
+ \dirkeys@dodefinekeys{#2}{\skvexpandonce\skv@tempa}%
+ }%
+}
+\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{#4}}%
+ \def\skv@tempa{}%
+ \def\skv@pathdo##1##2{%
+ \edef\skv@tempa{%
+ \skvexpandonce\skv@tempa
+ #3\ifdirkeys@saveunknownkeys*\else#1\fi
+ [##1]{##2}[\skvcsuse{##1/##2/.@ignoredkeys}]%
+ \skvifstrcmpTF{#2}{rm}{}{{\skvexpandonce\skv@tempb}}%
+ }%
+ }%
+ \dirkeys@pathlist
+ \expandafter\endgroup\skv@tempa
+}
+
+% This is used by prepostsetkeys, etc.
+% \dirkeys@dolistedkeys@a{<key.list>}{<callback>}
+\skvrobustdef*\dirkeys@dolistedkeys@a#1#2{%
+ \begingroup
+ \def\skv@tempd{}%
+ % ##1=prefix, ##2=family
+ \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{\skvaddlist,\skv@tempb\skvexpandonce\skv@tempa}%
+ }%
+ }%
+ \edef\skv@tempd{%
+ \skvexpandonce\skv@tempd
+ \skvifemptyTF\skv@tempb{}{%
+ \noexpand#2[##1]{##2}{\skvexpandonce\skv@tempb}%
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+ \expandafter\endgroup\skv@tempd
+}
+
+% \dirkeys@dolistedkeys@b{<callback>}
+\skvrobustdef*\dirkeys@dolistedkeys@b#1{%
+ \begingroup
+ \def\skv@tempa{}%
+ % ##1=prefix, ##2=family
+ \def\skv@pathdo##1##2{%
+ \edef\skv@tempa{%
+ \skvexpandonce\skv@tempa
+ \unexpanded{\skv@makeprefix{##1}\skv@makeheader{##2}#1}%
+ }%
+ }%
+ \dirkeys@pathlist
+ \expandafter\endgroup\skv@tempa
+}
+\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}'}\skv@ehd
+ \fi
+ \edef\skvcurrentsub{\unexpanded{##2}}%
+ \ifx\skvcurrentsub\skv@novaluetoks
+ \def\skvcurrentsub{}%
+ \else\skvafterfi
+ \skvdespacecontent\skvcurrentsub
+ \skvstripouterbraces{2}\skvcurrentsub
+ \fi
+ }%
+ \skv@prova#1#2\skv@novalue#2\skv@nil
+}
+
+% Pushing and popping path or holder prefix.
+%
+\skvnewnumbers[dirkeys@meta]{pathdepth,hpdepth}
+\skvrobustdef*\dirkeys@pushmeta#1{%
+ \skvifcasse{#1}
+ case{path}{\def\@elt{pathlist}}
+ case{hp}{\def\@elt{holderprefixtoks}}
+ \elsedo
+ \skv@err{Unknown meta type '#1'}\skv@ehd
+ \endif
+ \skvaftercs\skvgadvanceno{dirkeys@meta#1depth}\@ne
+ \edef\skv@elt{\skvrom\csname dirkeys@meta#1depth\endcsname}%
+ \skvcsletcs{dirkeys@\@elt @meta@\skv@elt}{dirkeys@\@elt}%
+}
+\skvrobustdef*\dirkeys@popmeta#1{%
+ \skvifcase\skvifstrcmpTF{#1}%
+ {path}{\def\@elt{pathlist}}%
+ {hp}{\def\@elt{holderprefixtoks}}%
+ \elsedo
+ \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}%
+ \skvaftercs\skvgadvanceno{dirkeys@meta#1depth}\m@ne
+}
+
+% Assigning admissible values to keys. The handlers here are:
+%
+% .state pattern, .state pattern expanded, .state pattern expand once,
+% .state pattern expand twice.
+%
+% \dirkeys@savechoice{<list>}{<expander.type>}
+%
+% 1. <list> has the form
+%
+% {<key1,...,keyn>}/{<ch1>.do={<act1>},...,<ch-n>.do={<act-n>}}
+% ,...,
+% <keyx-n>/{<ch1>.do={<act1>},...,<ch-n>.do={<act-n>}}
+%
+% 2. If it didn't exist, the main key (eg, the above <key1>) will be
+% defined with an empty default value and an empty callback.
+%
+\skvrobustdef*\dirkeys@savechoice#1#2{%
+ \begingroup
+ \def\skv@tempd{}%
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \skvcsvnormalize[/]\skv@tempa
+ \skvcommaparse*\skv@tempa\skv@tempa{%
+ \skvexpbracenext\dirkeys@s@vechoice\skv@tempa{#2}%
+ }%
+ \expandafter\endgroup\skv@tempd
+}
+\skvrobustdef*\dirkeys@s@vechoice#1#2{%
+ \skv@getmaintoks{#1}{/}%
+ \skvkvnormalize\skvcurrentsub
+ \def\skv@pathdo##1##2{%
+ \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}%
+ \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}%
+ \skvcommaparse*\skvcurrentmaintoks\skv@tempb{%
+ \skvxifinTF{,\skv@tempb,}{,\skv@igkeys,}{}{%
+ \skvifcsdefTF{##1/##2/\skv@tempb.@cbk}{}{%
+ \edef\skv@tempd{%
+ \skvexpandonce\skv@tempd
+ \skvordkey[##1]{##2}{\skv@tempb}[]{}%
+ }%
+ }%
+ \def\skv@choicelist{}%
+ \skvcommaloop*\skvcurrentsub\skv@tempa{%
+ \def\skv@prova####1.do=####2.do=####3\skv@nil{%
+ \edef\skv@choicelist{%
+ \skvexpandonce\skv@choicelist
+ {\skvtrimspace{####1}}{\skvtrimspace{####2}}%
+ }%
+ }%
+ \expandafter\skv@prova\skv@tempa.do=.do=\skv@nil
+ }%
+ }%
+ \edef\skv@tempd{%
+ \skvexpandonce\skv@tempd
+ \skvappendkeycode[##1]{##2}{\skv@tempb}%
+ {\dirkeys@executechoice{#2}{########1}%
+ {\skvexpandonce\skv@choicelist}}%
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+}
+% \dirkeys@executechoice{<expansion.type>}{<curr.value>}{<choices.and.cbks>}
+\skvrobustdef*\dirkeys@executechoice#1#2#3{%
+ \skv@getexpander{#1}%
+ \edef\skv@prova{\skvexpander{#2}}%
+ \skvdespacecontent\skv@prova
+ \def\do##1##2##3\skv@nil{%
+ \edef\skv@provb{\unexpanded{##1}}%
+ \skvifxTF\skv@provb\skv@prova{%
+ ##2%
+ }{%
+ \skvifblankTF{##3}{%
+ \skv@err{No choice match found for key '\skvcurrentkey'}\skv@ehd
+ }{%
+ \do##3\skv@nil
+ }%
+ }%
+ }%
+ \do#3\skv@nil
+}
+
+% Slot/style keys represent a limited signal-slot (or subject-observer)
+% concept from Java.
+%
+% The handlers here are:
+%
+% .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@saveslots{<list>}{<append.or.prepend>}{<expander.type>}
+%
+% 1. <list> has the form
+%
+% {<signal key1>,...,<signal key-n>}/{<slot1=val1>,...,<slot-n=val-n>}
+% ,...,
+% {<signal key1>,...,<signal key-n>/{<slot1=val1>,...,<slot-n=val-n>}
+%
+% 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 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 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 slot value expanded={keye,keyf}/{keyc=#1,keyd=#1}
+%
+\skvrobustdef*\dirkeys@saveslots#1#2#3{%
+ \begingroup
+ \skv@getexpander{#3}%
+ \def\skv@tempd{}%
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \skvcsvnormalize[/]\skv@tempa
+ \skvcommaparse*\skv@tempa\skv@tempa{%
+ \skvexpbracenext\dirkeys@s@veslots\skv@tempa{#2}%
+ }%
+ \expandafter\endgroup\skv@tempd
+}
+\skvrobustdef*\dirkeys@s@veslots#1#2{%
+ \skv@getmaintoks{#1}{/}%
+ \skvcsvnormalize\skvcurrentmaintoks
+ \skvkvnormalize\skvcurrentsub
+ \def\skv@pathdo##1##2{%
+ \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}%
+ \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}%
+ \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@signalkey}}{}%
+ }%
+ }%
+ % Insert expanders in the sub list:
+ \def\skv@slotlist{}%
+ \skvcommaloop*\skvcurrentsub\skv@tempa{%
+ \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{Slot key '####1' is undefined}\skv@ehd
+ }%
+ }%
+ \skvxifinTF{,####1,}{,\skv@igkeys,}{}{%
+ \edef\skv@slotlist{%
+ \skvaddlist,\skv@slotlist\unexpanded{####1}=%
+ \skvexpandonce\skvexpander{\unexpanded{####2}}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \edef\skv@tempd{%
+ \skvexpandonce\skv@tempd
+ % 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@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}}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+}
+
+%% +++++++++++++++ Linking keys:
+%
+% The handlers here are:
+%
+% .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@savelinks{<list>}{<append.or.prepend>}{<expander.type>}
+%
+% 1. <list> has the form
+%
+% {<linkkey-1>,..,<linkkey-n>}/{<parentkey-1>,...,<parentkey-n>}
+%
+% 2. The parent key will be set (with the value of link key) whenever the
+% link key is set.
+% 3. If the link key didn't exist, it will be defined as an ordinary key
+% with the default value of the parent key. In this way, setting a
+% link key without value won't give rise to a 'no value and no default
+% error'.
+% 4. Example: Link keyb and keyc to existing keya:
+%
+% .link={keyb,keyc}/keya
+%
+% This is equivalent to:
+%
+% .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@savelinks#1#2#3{%
+ \begingroup
+ \def\skv@tempe{}%
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \skvcsvnormalize[/]\skv@tempa
+ \skvcommaparse*\skv@tempa\skv@tempa{%
+ \skvexpbracenext\skv@getmaintoks\skv@tempa{/}%
+ \skvcsvnormalize\skvcurrentmaintoks
+ \def\skv@tempd{}%
+ \skvcommaparse*\skvcurrentsub\skv@tempb{%
+ \edef\skv@tempd{%
+ \skvaddlist,\skv@tempd\skvexpandonce\skv@tempb=####1%
+ }%
+ }%
+ \edef\skv@tempe{%
+ \skvaddlist,\skv@tempe
+ {\skvexpandonce\skvcurrentmaintoks}/{\skvexpandonce\skv@tempd}%
+ }%
+ }%
+ \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{#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@pathdo because it contains parameter
+ % characters:
+ \edef\skv@tempd{\unexpanded{#1}}%
+ \def\skv@tempe{}%
+ \skvkvnormalize\skv@tempd
+ \def\skv@pathdo##1##2{%
+ \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}%
+ \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}%
+ \skvcommaloop*\skv@tempd\skv@tempa{%
+ \skv@okvsplit\skv@tempa{%
+ \skvxifinTF{,####1,}{,\skv@igkeys,}{}{%
+ \skvifcsdefTF{##1/##2/####1.@cbk}{%
+ \skvifblankTF{####2}{}{%
+ \edef\skv@tempe{%
+ \skvexpandonce\skv@tempe\unexpanded{%
+ \skvcsedef{##1/##2/####1.@#2arg}{\unexpanded{####2}}%
+ }%
+ }%
+ }%
+ }{%
+ \skv@err{Key '####1' is undefined
+ \MessageBreak in family '##1/##2'}\skv@ehd
+ }%
+ }%
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+ \expandafter\endgroup\skv@tempe
+}
+
+% Use the default values of <keys> to set the keys.
+% \dirkeys@setwithdefaults[<pref>]{<fam>}{<keys>}
+\skvrobustdef*\dirkeys@setwithdefaults[#1]#2#3{%
+ \begingroup
+ \def\skv@defaultlist{}%
+ \skvcommaparse{#3}\skvcurrentkey{%
+ \skvletcs\skv@prova{#1/#2/\skvcurrentkey.@defa}%
+ \skvifdefTF\skv@prova{%
+ \skv@getdefault{#1}{#2}\skvcurrentkey\skvcurrentvalue
+ \edef\skv@defaultlist{%
+ \skvaddlist,\skv@defaultlist
+ \skvcurrentkey=\skvexpandonce\skvcurrentvalue
+ }%
+ }{%
+ \skv@err{No default value for key '\skvcurrentkey'
+ \MessageBreak in family '#1/#2'}\skv@ehd
+ }%
+ }%
+ \skvexpanded{\endgroup
+ \skvsetkeys*+[#1]{#2}{\skvexpandonce\skv@defaultlist}%
+ }%
+}
+\skvrobustdef*\dirkeys@setunknownkeyhandler#1{%
+ \begingroup
+ \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
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+ \expandafter\endgroup\skv@tempb
+}
+
+%%++++++++++++++++++++++++++ Try setting keys +++++++++++++++++++++++%%
+%
+% \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
+% <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
+% keys. When many families are given by the user, the success list is likely
+% to be smaller than failed list.
+%
+% Raise an error if the number of successful families is less than
+% the minimum threshold <min success>. The default value of <min success>
+% is 1. The options <min success> and <lower goal> are synonymous.
+%
+% \skvtrysetkeys is similar to \skvsetkeys*+ (ie, \skvsetkeys with the
+% options *+), but in this case we have <try> (ie, the maximum total number
+% of attempts - families to search for a given key) before backing off,
+% and <upper goal> (the maximum number of successful families in which a key
+% should be set).
+%
+% \skvtrysetkeys too will set existing preset and postset keys in the
+% given families.
+%
+% The options of \skvtrysetkeys are:
+%
+% .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 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
+% SFs may be more than <upper goal>, but the key may not need to be
+% executed in all of them. The default value of <upper goal> is 1.
+% .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. 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:
+% The boolean that directs that known/found keys should be saved
+% 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
+% inspect this macro to see the found keys. The default macro is
+% \skvsuccesslist.
+% .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.
+
+\skvedefinekeys[SKV]{skvtryset}[skvtry@]{%
+ .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}%
+ \ifnum\skvtry@maxattempts<\@ne
+ \skv@err{The max. number of attempts ('try')
+ \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}%
+ \ifnum\skvtry@maxsuccess<\@ne
+ \skv@err{The max. number of successful attempts
+ \MessageBreak ('upper goal') can't be less than 1}\skv@ehd
+ \fi
+ ,
+ .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}%
+ \ifnum\skvtry@minsuccess<\skvz@
+ \skv@err{The min. number of successful attempts
+ \MessageBreak ('lower goal') can't be less than 0}\skv@ehd
+ \fi
+ ,
+ % #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
+ \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
+ \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/.prefixes//
+ \ifskvindef\else
+ \skv@err{Key '.prefixes' not defined; try '.paths'}\skv@ehd
+ \fi
+ ,
+ .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/{.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/
+ \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
+ ,
+}
+
+% \skvtrysetkeys[<options>]{<kvlist>}
+\skvrobustdef*\skvtrysetkeys{\skv@testopt\skv@trysetkeys{}}
+\skvrobustdef*\skv@trysetkeys[#1]#2{%
+ \skvpushfunctions\skvtrysetkeys{%
+ \do\skvtry@maxattempts\do\skvtry@hitsexception\do\skvtry@pathexception
+ \do\skvtry@minsuccess\do\skvtry@maxsuccess\do\skvtry@igkeys
+ \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@pathlist\@empty
+ \skv@err{No families in which to 'try' to set keys}\skv@ehd
+ \fi
+ % 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@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\skv@attempts
+ \do\skv@hits\do\skv@failedattempts\do\ifskv@success\do\skvtry@pathdo
+ }\skv@trysetkeysidepth
+ \skv@successfalse
+ \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
+ }%
+ \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
+ \else
+ \let\skvtry@pathdo\@gobbletwo
+ \fi
+ }%
+ \skvtry@pathlist
+ \ifnum\skv@hits<\skvtry@minsuccess\relax
+ \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@trysetkeysidepth
+ }%
+ }%
+ \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@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 +++++++++++++++++++%%
+%
+% \skvsasetkeys[<options>]{<keyvals>}
+% .sa set keys={<options>}
+%
+% When using '.sa set keys', the key '.key values' must be part of
+% <options>.
+%
+% 1. The only difference between \skvsasetkeys and \skvtrysetkeys is that,
+% 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.
+
+\skvnewlet\skvsasetkeys\skvtrysetkeys
+\skvrobustdef*\dirkeys@sasetkeys#1{%
+ \skv@insatrue
+ \dirkeys@trysetkeys{#1}%
+}
+% \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}%
+ }%
+ }%
+ }%
+ \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}%
+ }%
+ }%
+ }%
+ \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
+ \def\skv@tempa{%
+ \skvxifinFT{\skvrelax/}{\skvrelax#1}{}{%
+ \def\do/##1\skv@nil{\def#1{##1}}%
+ \expandafter\do#1\skv@nil
+ \skv@tempa
+ }%
+ }%
+ \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.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 \skv@pathdo:
+ \edef\skv@tempa{\unexpanded{#3}}%
+ \def\skv@tempb{}%
+ % ##1=prefix, ##2=family
+ \def\skv@pathdo##1##2{%
+ \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}%
+ \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}%
+ \skvkvparse*\skv@tempa\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
+ \MessageBreak '##1/##2'}\skv@ehd
+ }{%
+ \skvcsedef{##1/##2/####1.@#2}{%
+ \skvifstrcmpTF{#1}{pre}{%
+ \skvtrimspace{####2}\skvexpandonce\skv@prova
+ }{%
+ \skvexpandonce\skv@prova\skvtrimspace{####2}%
+ }%
+ }%
+ % To take the new macros outside the group:
+ \edef\skv@tempb{%
+ \skvexpandonce\skv@tempb
+ \noexpand\skvcsexit{##1/##2/####1.@#2}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+ \skvexpanded{\endgroup\skv@tempb}%
+}
+
+% \dirkeys@assigndefault{<kvlist>}
+\skvrobustdef*\dirkeys@assigndefault#1{%
+ \begingroup
+ % Hid the list from the parameters of \do:
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \def\skv@tempb{}%
+ % ##1=prefix, ##2=family
+ \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}{%
+ \skvxifinTF{,\detokenize{####1},}{,\skvoxdetok\skv@igkeys,}{}{%
+ \skvifcsdefTF{##1/##2/####1.@cbk}{%
+ \skvcsedef{##1/##2/####1.@defa}{%
+ \skvnoexpandcs{##1/##2/####1}{\skvtrimspace{####2}}%
+ }%
+ % To take the new defaults outside the group:
+ \edef\skv@tempb{%
+ \skvexpandonce\skv@tempb
+ \noexpand\skvcsexit{##1/##2/####1.@defa}%
+ }%
+ }{%
+ \skv@err{Key '####1' is not in family '##1/##2'}\skv@ehd
+ }%
+ }%
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+ \skvexpanded{\endgroup\skv@tempb}%
+}
+
+% \dirkeys@assignvalue{<kvlist>}
+\skvrobustdef*\dirkeys@assignvalue#1{%
+ \begingroup
+ % Hid the list from the parameters of \do:
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \def\skv@tempb{}%
+ % ##1=prefix, ##2=family
+ \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}{%
+ \skvxifinTF{,\detokenize{####1},}{,\skvoxdetok\skv@igkeys,}{}{%
+ \skvifcsdefTF{##1/##2/####1.@cbk}{%
+ \skvcsedef{##1/##2/####1.@value}{\skvtrimspace{####2}}%
+ \edef\skv@tempb{%
+ \skvexpandonce\skv@tempb
+ \noexpand\skvcsexit{##1/##2/####1.@value}%
+ }%
+ }{%
+ \skv@err{Key '####1' isn't in family '##1/##2'}\skv@ehd
+ }%
+ }%
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+ \skvexpanded{\endgroup\skv@tempb}%
+}
+
+% \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\skv@pathdo##1##2{%
+ \skvletcs\skv@igkeys{##1/##2/.@ignoredkeys}%
+ \skvifdefTF\skv@igkeys{}{\def\skv@igkeys{}}%
+ \skvkvparse*\skv@tempa\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
+ \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'}\skv@ehd
+ \fi
+ }%
+ }%
+ }%
+ }%
+ \dirkeys@pathlist
+ \expandafter\endgroup\skv@tempb
+}
+
+% \dirkeys@setbooleanhandler{<handler>}{<boolean>}{<bool.value>}
+\skvrobustdef*\dirkeys@setbooleanhandler#1#2#3{%
+ \skvifcsdefTF{if#2}{%
+ \skvifblankTF{#3}{%
+ \csname#2true\endcsname
+ }{%
+ \skvifboolvalTF{#3}{%
+ \csname#2#3\endcsname
+ }{%
+ \skv@err{Invalid value '\detokenize{#3}' for handler '#1':
+ \MessageBreak its expects either 'true' or 'false'}\skv@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'}\skv@ehd
+ \fi
+}
+\skvrobustdef*\dirkeys@handlerloop#1{%
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \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>}{<kvlist>}
+%
+% <flag> indicates if we're in <new> (01) or <define> (00) handler.
+%
+% <kvlist> -> {<handlers-1>}={<defn>},...,{<handlers-n>}={<defn>}
+%
+\skvrobustdef*\dirkeys@defhandlers#1#2{%
+ \begingroup
+ \def\skv@collection{}%
+ \def\skv@param{####1\skvhandlereov}%
+ \def\skv@defhandlers@do##1{%
+ \skv@ensurehandlerdot{##1}%
+ \skvifknobTF{#1}{%
+ \dirkeys@defhandlers@aux{##1}%
+ }{%
+ \skvifcsdefTF{dirkeys@handler@##1}{%
+ \skv@err{Handler '##1' arealdy exists}\skv@ehd
+ }{%
+ \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
+ }%
+}
+\skvnewlet\dirkeysdefhandlers\dirkeys@defhandlers
+% \dirkeys@defnarghandlers{<flag>}{<list>}
+%
+% Define handlers of more than one argument. This is slightly more
+% expensive than '.new handlers':
+%
+% <flag> indicates whether we're in <new> (01) or <define> (00) handler.
+%
+\skvrobustdef*\dirkeys@defnarghandlers#1#2{%
+ \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}}%
+ \skvifknobTF{#1}{%
+ \dirkeys@defhandlers@aux{##1}%
+ }{%
+ \skvifcsdefTF{dirkeys@handler@##1}{%
+ \skv@err{Handler '##1' arealdy exists}\skv@ehd
+ }{%
+ \dirkeys@defhandlers@aux{##1}%
+ }%
+ }%
+ }%
+ \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
+ }%
+}
+\skvnewlet\dirkeysdefnarghandlers\dirkeys@defnarghandlers
+
+% \dirkeys@handlerlet{<flag>}{<kvlist>}
+%
+% 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{%
+ \begingroup
+ \def\skv@collection{}%
+ \def\skv@handlerlet@do##1##2{%
+ \skvifblankTF{##1}{}{%
+ \skvxifinTF{,##1,}{,\dirkeys@reservedhandlers,}{%
+ \skv@reservedhandlererr
+ }{%
+ \ifskv@inreservedhandler
+ \edef\dirkeys@reservedhandlers{%
+ \dirkeys@reservedhandlers
+ \ifx\dirkeys@reservedhandlers\@empty\else,\fi##1%
+ }%
+ \fi
+ \skvifknobTF{#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}%
+ \skvifnamedefTF{dirkeys@handler@#1}{%
+ \csname dirkeys@handler@#1\endcsname#2\skvhandlereov
+ }{%
+ \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 \directkeys:
+\skvnewdef*\dirkeys@unknownkeysmacro{\skvfaillist}
+
+% Notes:
+% 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 \directkeys).
+%
+\skvrobustcsdef*{dirkeys@handler@.new reserved handlers}#1\skvhandlereov{%
+ \skv@inreservedhandlertrue
+ \dirkeys@defhandlers{01}{#1}%
+ \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},
+ % 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}
+ },
+ % 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@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 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}\skv@ehd
+ }
+ }
+ },
+ {.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}
+ },
+ {.initialize keys after define,.initialize after define}={
+ \dirkeys@setbooleanhandler
+ {.initialize keys after define}{skvdfk@initialize}{#1}
+ },
+ {.save initial values of keys,.save initial values}={
+ \dirkeys@setbooleanhandler
+ {.save initial values of keys}{skvdfk@saveinitialvalues}{#1}
+ },
+ {.set keys,.setkeys,.set}={
+ \dirkeys@setkeys{}{}\skvsetkeys{#1}
+ },
+ {.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'}\skv@ehd
+ }
+ },
+ {.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 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}
+ },
+ % 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,.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,.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:
+ {.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,.unknown option handler}={
+ \dirkeys@setunknownkeyhandler{#1}
+ },
+ % Redefine the default value macros of keys.
+ % .default values={keya=vala,...,keyn=valn}
+ {.default value,.default values,.default,.defaults}={
+ \dirkeys@assigndefault{#1}
+ },
+ % Change the current values of keys.
+ % .assign values={keya=vala,...,keyn=valn}
+ {.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 value,.inherit values}={
+ \dirkeys@inheritproperty{value}{#1}
+ },
+ {.inherit callback,.inherit callbacks,.inherit code}={
+ \dirkeys@inheritproperty{cbk}{#1}
+ },
+ {.inherit default,.inherit defaults}={
+ \dirkeys@inheritproperty{defa}{#1}
+ },
+ % .prepend values={key1=val1,...,keyn=valn}
+ {.prepend value,.prepend values}={
+ \dirkeys@addtocodeorvalue{pre}{value}{#1}
+ },
+ {.append value,.append values}={
+ \dirkeys@addtocodeorvalue{app}{value}{#1}
+ },
+ % .prepend code={key1=code1,...,keyn=coden}
+ {.prepend code,.prepend codes}={
+ \dirkeys@addtocodeorvalue{pre}{cbk}{#1}
+ },
+ {.append code,.append codes}={
+ \dirkeys@addtocodeorvalue{app}{cbk}{#1}
+ },
+ },
+ .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'}\skv@ehd
+ }
+ },
+ .add slot={2}{
+ \skvusehandler{.prepend slot}{#1}
+ \skvusehandler{.append slot}{#2}
+ },
+ .add code={2}{
+ \skvusehandler{.prepend code}{#1}
+ \skvusehandler{.append code}{#2}
+ },
+ .add value={2}{
+ \skvusehandler{.prepend value}{#1}
+ \skvusehandler{.append value}{#2}
+ },
+ % .get value={<pref>}{<fam>}{<key>}<cmd>
+ .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'}\skv@ehd
+ }
+ },
+ % .set boolean handler={<handler>}{<boolean>}{<boolean.value>}
+ % See example use above.
+ .set boolean handler={3}{
+ \dirkeys@setbooleanhandler{#1}{#2}{#3}
+ },
+ },
+ .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
+ \skv@testopt\skv@patchcmd{####1}%
+}
+\skvrobustdef*\skv@patchcmd[#1]#2#3#4{%
+ \ifskv@tracingkeys
+ \typeout{^^J** Debugging patches: command '\string#2'}%
+ \fi
+ \skv@p@tchcmd{#1}{#2}{#3}{#4}%
+}
+\skvrobustdef*\skv@p@tchcmd#1#2#3#4{%
+ \skvifpatchableTF{#2}{#3}{#4}{%
+ \skv@patchdebug{++}{Command is patchable}%
+ \skv@patchdebug{==}{Patching has begun}%
+ \begingroup
+ \edef\skv@tempa##1##2{%
+ \def##1####1\detokenize{macro:}####2->####3\skvrelax{%
+ #1\def\string#2####2{##2####3\skvrelax}%
+ }%
+ \def##2####1\detokenize{#3}####2\skvrelax{####1\detokenize{#4}####2}%
+ \edef##1{##1\meaning#2\skvrelax}%
+ }%
+ \skv@tempa\skv@tempa\skv@tempb
+ \skv@scantoksd\endgroup\skv@tempa
+ \skv@patchdebug{==}{Patching completed successfully}%
+ \@firstoftwo
+ }{%
+ \skv@patchdebug{--}{Patching couldn't be completed}%
+ \@secondoftwo
+ }%
+}
+\skvrobustdef*\skv@patchdebug#1#2{%
+ \ifskv@tracingkeys\typeout{[debug] #1 #2.}\fi
+}
+\skvrobustdef*\skvifpatchableTF#1#2#3{%
+ \endgroup
+ \skvifdefFT{#1}{%
+ \skv@patchdebug{--}{Command not defined}%
+ \@secondoftwo
+ }{%
+ \skv@patchdebug{++}{Command is defined}%
+ \skvifmacroTF{#1}{%
+ \skv@patchdebug{++}{Command is a macro}%
+ \skvifscannableTF{#1}{%
+ \skv@patchdebug{++}{Macro can be retokenized safely after patching}%
+ \skvifpatternTF{#2}{#1}{%
+ \skv@patchdebug{++}{Requested search pattern found}%
+ \@firstoftwo
+ }{%
+ \skv@patchdebug{--}{Requested search pattern not found}%
+ \@secondoftwo
+ }%
+ }{%
+ \skv@patchdebug{--}{Nested commands or parameters}%
+ \@secondoftwo
+ }%
+ }{%
+ \skv@patchdebug{--}{Macro can't be retokenized safely after patching}%
+ \@secondoftwo
+ }%
+ }%
+}
+\skvrobustdef*\skveveryscan{%
+ \everyeof{\noexpand}%
+ \endlinechar\m@ne
+ \makeatletter
+ \catcode`\ =10
+ \catcode`\\=0
+ \catcode`\{\@ne
+ \catcode`\}\tw@
+}
+\skvrobustdef*\skv@scantoksd#1#2{%
+ \skvexpandsecond{#1\skveveryscan\scantokens}{%
+ {#2}\everyeof{\the\everyeof}%
+ \noexpand\endlinechar\the\endlinechar\relax
+ \catcode`\noexpand\@=\the\catcode`\@\relax
+ \catcode`\noexpand\ =\the\catcode`\ \relax
+ \catcode`\noexpand\\=\the\catcode`\\\relax
+ \catcode`\noexpand\{=\the\catcode`\{\relax
+ \catcode`\noexpand\}=\the\catcode`\}\relax
+ }%
+}
+\skvrobustdef*\skvifscannableTF#1{%
+ % Fails if the content of #1 is already detokenized.
+ \begingroup
+ \edef\skv@tempa##1{%
+ \def##1####1\detokenize{macro}:####2->####3\skvrelax{%
+ ####1\def\string\skv@tempa####2{####3}%
+ }%
+ \edef##1{##1\meaning#1\skvrelax}%
+ }%
+ \skv@tempa\skv@tempa
+ \makeatletter\everyeof{\noexpand}\endlinechar\m@ne
+ \scantokens\expandafter{\skv@tempa}\relax
+ \expandafter\endgroup
+ \ifx#1\skv@tempa
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+\skvrobustdef\skvifpatternTF#1#2{%
+ \begingroup
+ \edef\skv@tempa##1{\def##1####1\detokenize{#1}####2\skvrelax}%
+ \skv@tempa\skv@tempa{%
+ \expandafter\endgroup\ifx\\##2\\%
+ \expandafter\@secondoftwo
+ \else
+ \expandafter\@firstoftwo
+ \fi
+ }%
+ \edef\skv@tempb##1{##1\detokenize{#1}\skvrelax}%
+ \skv@tempb{\expandafter\skv@tempa\meaning#2}%
+}
+\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}%
+}
+
+\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
+ }
+
+\skvpatchcmd\end
+ {\csname end#1\endcsname}
+ {\skvcsuse{lps@atend@#1@hook}\csname end#1\endcsname}
+ {}
+ {\skv@err{Patching '\string\end' failed!\MessageBreak
+ '\string\skvAtEndEnvironment' will not work\@gobble}\@ehd
+ }
+
+\skv@core@restorecodes
+
+\endinput
+
+%% End of file 'skeyval-core.tex'.
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-for.tex b/macros/latex/contrib/skeyval/tex/skeyval-for.tex
new file mode 100644
index 0000000000..205c019dc6
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-for.tex
@@ -0,0 +1,2862 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-for.tex', version 1.3, 2013/05/15. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup%
+\let\e\endlinechar\edef\p{\the\e}\e13\edef\n{\the\catcode\e}%
+\xdef\skv@for@restorecatcodes{%
+ \let\noexpand\skv@for@restorecatcodes\relax%
+ \endlinechar=\p\relax\catcode\number\e=\n\relax%
+ \catcode\string`\noexpand`\string=\the\catcode\string``\relax%
+ \catcode\string`\noexpand=\string=\the\catcode\string`=\relax%
+}%
+\endgroup%
+\endlinechar\string=13\relax%
+\catcode13\string=5\relax%
+\catcode\string``\string=12\relax
+\catcode\string`=\string=12\relax
+\def\skvgobble#1{}
+\def\do#1{\catcode`\expandafter\skvgobble\string#1=\the\catcode`#1\relax}
+\edef\skv@for@restorecatcodes{%
+ \unexpanded\expandafter{\skv@for@restorecatcodes}%
+ \do\ \do\%\do\@\do\(\do\)\do\[\do\]\do\|\do\:\do\;\do\,\do\.%
+ \do\>\do\<\do\!\do\*\do\+\do\-\do\^\do\_\do\&\do\$\do\~\do\'%
+ \do\"\do\
+}
+\catcode`\ =10\relax
+\catcode`\@=11 \catcode`\(=12 \catcode`\)=12 \catcode`\[=12
+\catcode`\]=12 \catcode`\|=12 \catcode`\:=12 \catcode`\;=12
+\catcode`\,=12 \catcode`\*=12 \catcode`\+=12 \catcode`\-=12
+\catcode`\<=12 \catcode`\>=12 \catcode`\!=12 \catcode`\.=12
+\catcode`\^=07 \catcode`\_=08 \catcode`\&=04 \catcode`\$=03
+\catcode`\~=13 \catcode`\%=14 \catcode`\'=12 \catcode`\"=12
+
+\csname skeyval-for-loaded\endcsname
+\expandafter\let\csname skeyval-for-loaded\endcsname\endinput
+
+\ifx\ProvidesFile\@undefined
+ \message{File 'skeyval-for.tex' 2013/05/15 v1.3
+ Loops for skeyval package (AM)}
+\else
+ \ProvidesFile{skeyval-for.tex}
+ [2013/05/15 v1.3 Loops for skeyval package (AM)]
+ \@addtofilelist{skeyval-for.tex}
+\fi
+
+\skvrobustdef*\skv@nostackerr{%
+ \skv@err{You've called an empty stack}\skv@ehd
+}
+% \skvsavestate<base-fn>{<fn-list>}<counter-number>
+%
+% See file skeyval-core.tex for \skvpushfunctions and \skvpopfunctions.
+%
+\skvrobustdef*\skvsavestate#1#2#3{%
+ \skvgadvanceno#3\@ne
+ \begingroup
+ \let\s\string\escapechar\m@ne
+ \def\skv@prova##1{\s##1@skv@\romannumeral#3}%
+ \def\do##1{\let\noexpand##1\skvnoexpandcs{\skv@prova{##1}}}%
+ \skvifcsdefTF{\s#1@skv@stack}{}{\skvcsdef{\s#1@skv@stack}{\nostack}}%
+ \skvcsxdef{\s#1@skv@stack}{#2{\skvexpandcsonce{\s#1@skv@stack}}}%
+ \def\do##1{\let\skvnoexpandcs{\skv@prova{##1}}\noexpand##1}%
+ \edef\reserved@a{\endgroup#2}\reserved@a
+}
+% \skvrestorestate<base-fn><counter-number>
+\skvrobustdef*\skvrestorestate#1#2{%
+ \begingroup
+ \let\nostack\skv@nostackerr
+ \edef\skv@elt{\skvnoexpandcs{\skvremovescape#1@skv@stack}}%
+ \expandafter\ifx\skv@elt\relax
+ \skv@err{Stack of '\noexpand#1' is undefined}\skv@ehd
+ \fi
+ \edef\skv@prova{\skvexpandtwice\skv@elt}%
+ \edef\skv@provb##1##{\endgroup##1\gdef\skvexpandonce\skv@elt}%
+ \expandafter\skv@provb\skv@prova
+ \skvgadvanceno#2\m@ne
+}
+\skvnewregisters\bool{%
+ \ifbreakallforeachloops,\ifskvbreakloop,\ifforeachlastitem,
+ \ifskvprocessempty,\ifskv@foreach@swa,\ifskv@foreach@swb,
+ \ifskv@foreach@parenthesis,\ifskv@useemptylist,\ifskv@inforeach,
+}
+\skvnewlet\skvbreakloop\skvbreaklooptrue
+\skvnewlet\breaknewforeach\skvbreaklooptrue
+% \breakallforeachloops will break all current loops (inner and outer):
+\skvnewdef*\breakallforeachloops{%
+ \skvbreaklooptrue\breakallforeachloopstrue
+}
+
+\skvnewnumbers[skv@]{csvdepth,dolistdepth}
+%
+% \skvdolist{<parser>}{<list>}<holdercmd>{<callback>}
+% \skvdolist*{<parser>}{<listcmd>}<holdercmd>{<callback>}
+% \skvparselist{<parser>}{<list>}<holdercmd>{<callback>}
+% \skvparselist*{<parser>}{<listcmd>}<holdercmd>{<callback>}
+% \skvprocesslist{<parser>}{<list>}<holdercmd>{<callback>}
+% \skvprocesslist*{<parser>}{<listcmd>}<holdercmd>{<callback>}
+%
+% 1. These macros can process both csv and tsv/nsv lists. Use empty
+% <parser> for tsv lists.
+% 2. These macros can be nested to any depth, with different parsers
+% on each level.
+% 3. \skvdolist and \skvparselist will not process an empty list, but
+% \skvprocesslist will do so.
+% 4. For comma lists, \skvcommaloop and \skvcommaparse are faster.
+% See later.
+% 5. For processing kv lists, use \skvparsekvlist.
+% 6. The preservation of outer braces isn't a priority in this loop.
+%
+\skvrobustdef*\skvdolist{\skv@useemptylistfalse\skv@testst\skv@dolist}
+\skvrobustdef*\skv@dolist#1#2#3#4{%
+ \skv@usetempst{#2}#3%
+ % \skvlistcount is used by listkeys.
+ \skvsavestate\skvdolist{%
+ \do\skv@dolist@callback
+ \do\skv@dolist@a\do\skvlistcount\do\ifskv@useemptylist
+ }\skv@dolistdepth
+ \edef\skv@dolist@callback{\unexpanded{#4}}%
+ \def\skvlistcount{0}%
+ \def\skv@dolist@a##1##2#1{%
+ \skvifstrcmpTF{##2}{\skv@dolist@nil}{%
+ % To allow nesting of loop:
+ \skvbreakloopfalse
+ }{%
+ \edef##1{\unexpanded{##2}}%
+ \edef\skvlistcount{\the\numexpr\skvlistcount+1}%
+ \skv@dolist@callback\relax
+ \ifskvbreakloop
+ \skvbreakloopfalse
+ \begingroup
+ \def\skv@dolist@a####1####2\skv@dolist@nil#1{%
+ \endgroup
+ \edef\skvremainder{\unexpanded{####2}}%
+ }%
+ \fi
+ \skv@dolist@a{##1}%
+ }%
+ }%
+ \ifskv@useemptylist
+ \def\reserved@a##1##2##3{##3}%
+ \else
+ \let\reserved@a\skvifemptyTF
+ \fi
+ \reserved@a#3{}{%
+ \expandafter\skv@dolist@a\expandafter#3#3#1\skv@dolist@nil#1%
+ }%
+ \skvrestorestate\skvdolist\skv@dolistdepth
+}
+% First normalize the list before parsing.
+\skvrobustdef*\skvparselist{\skv@useemptylistfalse\skv@testst\skv@parselist}
+\skvrobustdef*\skvprocesslist{\skv@useemptylisttrue\skv@testst\skv@parselist}
+\skvrobustdef*\skv@parselist#1#2#3{%
+ \skv@usetempst{#2}#3%
+ \skvcsvnormalize[#1]#3%
+ \skv@tempsttrue
+ \skv@dolist{#1}#3#3%
+}
+
+\skvnewlet\foreachlistbreaker\relax
+\skvnewlet\foreachlistpauser\relax
+\skvnewdef*\skv@listbreakertoks{\foreachlistbreaker}
+\skvnewdef*\skv@listpausertoks{\foreachlistpauser}
+\skvnewlet\skvprocessempty\skvprocessemptytrue
+
+% Reversing tokens:
+\skvnewdef*\skvreverse#1{\skv@reverse#1\skv@reverse@stop}
+\skvnewdef*\skv@reverse#1#2\skv@reverse@stop{%
+ \if\relax\detokenize{#2}\relax\skv@reverse@stop\fi
+ \skv@reverse#2\skv@reverse@stop\skvreversedo{#1}%
+}
+\skvnewdef*\skv@reverse@stop#1\skv@reverse@stop{\fi}
+\let\skvreversedo\@iden
+
+\skvrobustdef*\skv@removetrailingparser#1#2{%
+ \skvxifinTF{\detokenize{#1}\relax}{\skvoxdetok#2\relax}{%
+ \def\skv@prova##1#1\skv@trim@nil{\unexpanded{##1}}%
+ \edef#2{\expandafter\skv@prova#2\skv@trim@nil}%
+ }{}%
+}
+
+% \skvrecurse<body>\while<\if...>\fi
+%
+% On entry, the condition is checked before the body is executed.
+%
+% \@tempcnta\z@
+% \skvrecurse{
+% \advance\@tempcnta\@ne
+% \@tempcntb\z@
+% \skvrecurse
+% \advance\@tempcntb\@ne
+% \typeout{Doing \the\@tempcnta,\the\@tempcntb}
+% \while
+% \ifnum\@tempcntb<3
+% \fi
+% }
+% \while
+% \ifnum\@tempcnta<4
+% \fi
+%
+\skvnewcounts{skv@recurse@cnt}
+\skvrobustdef\skvrecurse#1\while#2\fi{%
+ \skv@recurse@cnt\skvz@
+ \@expandtwoargs\skv@dobody{\skvtrimspace{#2}}{\skvtrimspace{#1}}%
+}
+\skvrobustdef\skv@dobody#1#2{%
+ \advance\skv@recurse@cnt\@ne
+ \ifnum\skv@recurse@cnt>10000\relax
+ \@latex@error{Possibly an infinite loop in \string\skvrecurse}
+ {Maybe you didn't increment some counter or
+ \MessageBreak the termination condition was never satisfied.}%
+ \fi
+ #1\relax\expandafter\@iden\else\expandafter\@gobble\fi
+ {#2\relax\skv@dobody{#1}{#2}}%
+}
+
+% A version of LaTeX's \@tfor that can parse undoubled parameter
+% characters and terminate the loop by using \skvbreakloop.
+%
+% \skvtfor<holder.cmd>:={<list>}\do{<callback>}
+% \skvtfor*<holder.cmd>:={<listcmd>}\do{<callback>}
+%
+% Example:
+%
+% \skvnewregister\count{\nr}
+% \skvtfor\x:=a \ifx {\def\x#1{#1}} \fi\do{%
+% \nr\z@
+% \skvtfor\y:=12345\do{%
+% \typeout{Doing: \detokenize\expandafter{\x}--\y}%
+% \advance\nr\@ne
+% \ifnum\nr>\tw@\skvbreakloop\fi
+% }
+% }
+%
+\skvnewdef*\skv@tfor@nil{\skv@tfor@nil}
+\skvrobustdef*\skvtfor{\skv@testst\skv@tfor}
+\skvrobustdef*\skv@tfor#1:={\skv@tf@r#1 }
+\skvrobustdef\skv@tf@r#1#2\do#3{%
+ \edef#1{\skvtrimspace{#2}}%
+ \edef#1{\skvifdefboolTF{skv@tempst}\skvexpandtwice\skvexpandonce{#1}}%
+ \skvifemptyTF#1{}{%
+ \skvbreakloopfalse
+ \expandafter\skv@tforloop#1\skv@tfor@nil\skv@tfor#1{#3}%
+ }%
+}
+\skvrobustdef\skv@tforloop#1#2\skv@tfor#3#4{%
+ \edef#3{\unexpanded{#1}}%
+ \skvifxTF#3\skv@tfor@nil{%
+ \skvbreakloopfalse
+ }{%
+ #4\relax
+ \ifskvbreakloop
+ \skvbreakloopfalse
+ \begingroup
+ \def\skv@tforloop##1\skv@tfor@nil\skv@tfor##2##3{%
+ \endgroup
+ \edef\skvremainder{\unexpanded{##1}}%
+ }%
+ \fi
+ \skv@tforloop#2\skv@tfor#3{#4}%
+ }%
+}
+
+%+++++++++++++++ Non-expandable comma loops ++++++++++++++%%
+%
+% 1. These follow from \skvdolist and \skvparselist, but they are
+% specialized for comma lists and they are faster, since they don't
+% stack any state.
+% 2. There is no fear of parameter characters in <callback> being mixed
+% with those of \skv@commaloop@picknext.
+% 3. These loops can be nested to any depth.
+% 4. The preservation of outer braces isn't a priority in these loops.
+%
+% \skvcommaloop{<list>}<holder-cmd>{<callback>}
+% \skvcommaloop*{<listcmd>}<holder-cmd>{<callback>}
+%
+% Example:
+%
+% \skvcommaloop{x#1,y#1}\tempa{\edef\xx#1{#1\tempa}}
+%
+\skvrobustdef*\skvcommaloop{\skv@testst\skv@commaloop}
+\skvrobustdef\skv@commaloop#1#2#3{%
+ \skv@usetempst{#1}#2%
+ % Don't put \skvcsvnormalize#2 here. Use \skvcommaparse instead.
+ % Some callers of \skvcommaloop already have their lists normalized.
+ \skvifxTF#2\@empty{}{%
+ \skvbreakloopfalse
+ \skvexpandnext{\skv@commaloop@picknext#2{#3}}#2,\skv@commaloop@nil,%
+ }%
+}
+\skvrobustdef\skv@commaloop@picknext#1#2#3,{%
+ \skvifstrcmpTF{#3}{\skv@commaloop@nil}{%
+ \skvbreakloopfalse
+ }{%
+ \edef#1{\unexpanded{#3}}%
+ #2\relax
+ \ifskvbreakloop
+ \skvbreakloopfalse
+ \begingroup
+ \long\def\skv@commaloop@picknext##1##2##3\skv@commaloop@nil,{%
+ \endgroup
+ \edef\skvremainder{\unexpanded{##3}}%
+ }%
+ \fi
+ \skv@commaloop@picknext#1{#2}%
+ }%
+}
+%
+% \skvecommaloop{<list>}<cmd>{<callback>}
+% \skvecommaloop*{<listcmd>}<cmd>{<callback>}
+%
+% \skvecommaloop is as \skvcommaloop but will execute <callback>
+% once when <list> is empty. This is needed for processing empty
+% families.
+%
+\skvrobustdef\skvecommaloop{\skv@testst\skv@ecommaloop}
+\skvrobustdef\skv@ecommaloop#1#2#3{%
+ \edef#2{\unexpanded{\skv@commaloop@picknext#2{#3}}}%
+ \ifskv@tempst\expandafter\expandafter\fi#2#1,\skv@commaloop@nil,%
+}
+%
+% \skvcommaparse{<list>}<cmd>{<callback>}
+% \skvcommaparse*{<listcmd>}<cmd>{<callback>}
+%
+% \skvcommaparse is as \skvcommaloop but will first normalize <list>
+% using \skvcsvnormalize.
+%
+\skvrobustdef*\skvcommaparse{\skv@testst\skv@commaparse}
+\skvrobustdef\skv@commaparse#1#2#3{%
+ \skv@usetempst{#1}#2%
+ \skvcsvnormalize#2%
+ \skvcommaloop*#2#2{#3}%
+}
+% \skvkvparse{<list>}<cmd>{<callback>}
+% \skvkvparse*{<listcmd>}<cmd>{<callback>}
+%
+% 1. \skvkvparse is as \skvcommaloop but will first normalize <list> using
+% \skvkvnormalize.
+% 2. It is meant for processing key-value lists.
+%
+\skvrobustdef*\skvkvparse{\skv@testst\skv@kvparse}
+\skvnewlet\skvparsekvlist\skvkvparse
+\skvrobustdef\skv@kvparse#1#2#3{%
+ \skv@usetempst{#1}#2%
+ \skvkvnormalize#2%
+ \skvcommaloop*#2#2{#3}%
+}
+% \skvcountelements[<parser>]{<list>}{<return.cmd>}
+% \skvcountelements*[<parser>]{<listcmd>}{<return.cmd>}
+\skvrobustdef*\skvcountelements{\skv@teststopt\skv@countelements,}
+\skvrobustdef*\skv@countelements[#1]#2#3{%
+ \begingroup
+ \skv@usetempst{#2}\skv@tempa
+ \@tempcnta\skvz@
+ \skvdolist*{#1}\skv@tempa\skv@prova{%
+ \advance\@tempcnta\@ne
+ }%
+ \edef#3{\the\@tempcnta}%
+ \skvaftergroupdef#3\endgroup
+}
+% If the number of elements in a list is equal or greater than <nr>.
+% \skvifelementcount[<parser>]{<list>}{<nr>}{<true>}{<false>}
+% \skvifelementcount*[<parser>]{<listcmd>}{<nr>}{<true>}{<false>}
+\skvrobustdef*\skvifelementcount{\skv@teststopt\skv@ifelementcount,}
+\skvrobustdef*\skv@ifelementcount[#1]#2#3{%
+ \begingroup
+ \skv@usetempst{#2}\skv@tempa
+ \@tempcnta\skvz@
+ \skv@swafalse
+ \skvdolist*{#1}\skv@tempa\skv@prova{%
+ \advance\@tempcnta\@ne
+ \ifnum\@tempcnta=#3\relax
+ \skv@swatrue\skvbreakloop
+ \fi
+ }%
+ \expandafter\endgroup\ifskv@swa
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+
+% \skv@foreach@normalize[<parser>]<listcmd>
+\skvrobustdef*\skv@foreach@normalize{\skv@testopt\skv@foreach@norm@lize,}
+\skvrobustdef*\skv@foreach@norm@lize[#1]#2{%
+ \skvxifntypeTF{\detokenize{#1}}\skvcsvnormalize\skvmacnormalize[#1]#2%
+}
+
+% \newforeach[<options>] <holders> {<list>} {<callback>}
+% \newforeach*[<options>] <holders> {<listcmd>} {<callback>}
+% \newforeach[<options>] <holders> in {<list>} do {<callback>}
+% \newforeach*[<options>] <holders> in {<listcmd>} do {<callback>}
+% \newforeach[<options>] <holders> in {<list>} <callback> ;
+% \newforeach*[<options>] <holders> in {<listcmd>} <callback> ;
+%
+% 1. <callback> is the code that will be executed for each element
+% of the list. It will refer to the holder macros <holders>.
+%
+% 3. Elements of the form (a,b) and [a,b] are grabbed together.
+%
+% 4. Use \breaknewforeach to break out of the loop prematurely.
+%
+% 5. \newforeach can be nested.
+%
+% 6. The star (*) variant of \newforeach is equivalent to using the
+% key 'list is a macro' (or *) in <options>.
+%
+% \skv@foreach@holderdepth must be different from \foreachnestdepth,
+% to avoid confusing two different stacks.
+\skvnewnumbers{foreachnestdepth,skv@foreach@holderdepth,%
+ skv@foreach@nra,skv@warnsubparser}
+% \newforeach will not accept \skvifstreq or \skvifstrcmpTF because
+% they don't start with '\if'. So we introduce \ifforeachstrcmp:
+\skvnewlet\ifforeachstrcmp\skvifstreq
+\skvnewdef*\skv@foreach@onlyinitially{}
+\skvrobustdef*\skvforeachonlyinitially#1{%
+ \edef\skv@foreach@onlyinitially{%
+ \skvexpandonce\skv@foreach@onlyinitially
+ \unexpanded{#1}%
+ }%
+}
+% \skv@foreach@addtocallback{<pre.or.post>}{<code.to.add>}
+\skvrobustdef*\skv@foreach@addtocallback#1#2{%
+ \skvcsedef{skv@foreach@#1callback}{%
+ \skvifcsdefFT{skv@foreach@#1callback}{}{%
+ \skvexpandcsonce{skv@foreach@#1callback}%
+ }%
+ % No \unexpanded for #2 here, since #2 is to be expanded:
+ #2%
+ }%
+}
+
+\skvnewlet\skv@foreach@codemark\relax
+\skvrobustdef*\skv@foreach@addtohook#1#2#3{%
+ \begingroup
+ \skvifdefTF#2{}{\def#2{}}%
+ \edef\x{\detokenize{\skv@foreach@codemark#3\skv@foreach@codemark}}%
+ \skvxifinTF\x{\skvoxdetok#2}{}{%
+ \edef#2{%
+ \skvifstrcmpTF{#1}{pre}{%
+ \skv@foreach@codemark\unexpanded{#3}\skv@foreach@codemark
+ \skvexpandonce{#2}%
+ }{%
+ \skvexpandonce{#2}%
+ \skv@foreach@codemark\unexpanded{#3}\skv@foreach@codemark
+ }%
+ }%
+ }%
+ \skvaftergroupdef#2\endgroup
+}
+
+% \prependtobeginforeach[<depths>]{<code>}
+\skvrobustdef*\prependtobeginforeach{%
+ \skv@testopt{\skv@atbeginforeach{pre}}{}%
+}
+% \appendtobeginforeach[<depths>]{<code>}
+\skvrobustdef*\appendtobeginforeach{%
+ \skv@testopt{\skv@atbeginforeach{app}}{}%
+}
+\skvnewlet\atbeginforeach\appendtobeginforeach
+\skvrobustdef*\skv@atbeginforeach#1[#2]#3{%
+ \skvifblankTF{#2}{%
+ \skvaftercsname{\skv@foreach@addtohook{#1}}%
+ {skv@foreach@atbeginhook@\skvrom\@ne}{#3}%
+ }{%
+ \skvcommaloop{#2}\skv@tempa{%
+ \skvaftercsname{\skv@foreach@addtohook{#1}}%
+ {skv@foreach@atbeginhook@\skvrom\number\skv@tempa}{#3}%
+ }%
+ }%
+}
+% \prependtoendforeach[<depths>]{<code>}
+\skvrobustdef*\prependtoendforeach{%
+ \skv@testopt{\skv@atendforeach{pre}}{}%
+}
+% \appendtoendforeach[<depths>]{<code>}
+\skvrobustdef*\appendtoendforeach{%
+ \skv@testopt{\skv@atendforeach{app}}{}%
+}
+\skvnewlet\atendforeach\appendtoendforeach
+\skvrobustdef*\skv@atendforeach#1[#2]#3{%
+ \skvifblankTF{#2}{%
+ \skvaftercsname{\skv@foreach@addtohook{#1}}%
+ {skv@foreach@atendhook@\skvrom\@ne}{#3}%
+ }{%
+ \skvcommaloop{#2}\skv@tempa{%
+ \skvaftercsname{\skv@foreach@addtohook{#1}}%
+ {skv@foreach@atendhook@\skvrom\number\skv@tempa}{#3}%
+ }%
+ }%
+}
+% \atbeginforeachondepth{<depths>}{<code>}
+\skvrobustdef*\atbeginforeachondepth#1#2{%
+ \appendtobeginforeach[#1]{#2}%
+}
+% \atendforeachondepth{<depths>}{<code>}
+\skvrobustdef*\atendforeachondepth#1#2{%
+ \appendtoendforeach[#1]{#2}%
+}
+
+% \skv@foreach@fi@toks must use \detokenize. Don't change to \string!
+\skvnewedef*\skv@foreach@fi@toks{\detokenize{\fi}}
+\skvnewedef*\skv@foreach@if@toks{\string\if}
+
+% \skv@foreach@ifacceptkv and \skv@foreach@maketester must come
+% before the initialization of keys:
+\skvrobustdef*\skv@foreach@ifacceptkv#1#2{%
+ \def\next{}%
+ \ifskvindef\else
+ \edef\skv@prova{\unexpanded{#1}}%
+ \ifnum0>\numexpr0\ifx\skv@prova\@empty-1\else
+ \ifx\skv@prova\@nnil-1\else+0\fi\fi\relax\relax
+ \skv@err{Invalid syntax '\detokenize{#1}'}\skv@ehd
+ \else
+ \edef\next{\unexpanded{#2}}%
+ \fi
+ \fi
+ \next
+}
+\skvrobustdef*\skv@foreach@ifholderisonecmd#1#2#3{%
+ \skvifntypeTF{#2}{%
+ \skvifescapedTF{#2}{%
+ #3%
+ }{%
+ \skv@err{Value of key '#1' must
+ \MessageBreak be escaped: the holder macro
+ \MessageBreak to be evaluated}\skv@ehd
+ }%
+ }{%
+ \skv@err{Value of key '#1' must
+ \MessageBreak be only one token: the holder
+ \MessageBreak macro to be evaluated}\skv@ehd
+ }%
+}
+% \skv@foreach@maketester{<cond>}<cond.tester.cmd>{<flag>}
+%
+% 1. Only balanced conditionals beginning with \if... and ending with \fi
+% are allowed. Restricting the type of allowed conditionals is
+% necessary for auto syntax checking.
+% 2. <flag> is either 0 or 1, signifying whether or not the condition
+% should be entered in postcallback. This is because
+% \skv@foreach@maketester is called (by key 'loop stopper') for
+% formating the premature exit condition and (in
+% \skv@foreach@parsecountin and \skv@foreachfox@parsecountin) for the
+% condition for counting an item of the list. In the latter case,
+% there is no need to enter the formated
+% condition in the postcallback, since it it is entered in the
+% 'afterprecallback' or (in the case of \foreachfox) in 'precallback'.
+%
+% Examples: \ifnum\x>10\fi, \ifx\x\cmd\fi.
+%
+\skvrobustdef*\skv@foreach@maketester#1#2#3{%
+ % Make '#1' innocent in a macro, in case it contains parameter
+ % characters. \skv@prova will appear only in the error message.
+ \begingroup
+ \edef\skv@prova{\detokenize{#1}}%
+ \skvifblankTF{#1}{%
+ \skv@err{A blank conditional has been given in
+ \MessageBreak\string\newforeach or a similar command}\skv@ehd
+ }{%
+ \skvxifinTF{\skv@foreach@fi@toks\relax}{\detokenize{#1}\relax}{%
+ \skvxifinTF{\relax\skv@foreach@if@toks}{\relax\detokenize{#1}}{%
+ \edef#2{\noexpand\skvifconditionTF\unexpanded{#1}}%
+ \ifnum#3=\@ne
+ \skv@foreach@addtocallback{post}{%
+ \unexpanded{\skvifconditionTF#1}{\noexpand\skvbreakloop}{}%
+ }%
+ \fi
+ }{%
+ \skv@err{Invalid conditional '\skv@prova'}
+ {Invalid, possibly unbalanced, conditional '\skv@prova'}%
+ }%
+ }{%
+ \skv@err{Invalid conditional '\skv@prova'}\skv@ehd
+ }%
+ }%
+ \skvexpanded{\endgroup
+ \skvcmdexit#2%
+ \ifnum#3=\@ne
+ \skvcmdexit\skv@foreach@postcallback
+ \fi
+ }%
+}
+\skvquickkeys.define{skeyval/foreach}{%
+ .exec/
+ \def\skv@foreach@parser{,}
+ \def\skv@foreach@subparser{/}
+ ;
+ parser/{,}/
+ \edef\skv@foreach@parser{\unexpanded{#1}}
+ \skvstripouterbraces{2}\skv@foreach@parser
+ \skvxifntypeTF{\detokenize{#1}}{%
+ \begingroup
+ % It is assumed that every n-type parser and subparser
+ % must have catcode 12:
+ \skvexpandnext{\catcode`}\skv@foreach@parser=12\relax
+ \skvrescan\skv@foreach@parser
+ \skvaftergroupdef\skv@foreach@parser\endgroup
+ }{}
+ ;
+ subparser/{/}/
+ \edef\skv@foreach@subparser{\unexpanded{#1}}
+ \skvstripouterbraces{2}\skv@foreach@subparser
+ \skvxifntypeTF{\detokenize{#1}}{
+ \begingroup
+ \skvexpandnext{\catcode`}\skv@foreach@subparser=12\relax
+ \skvrescan\skv@foreach@subparser
+ \skvaftergroupdef\skv@foreach@subparser\endgroup
+ }{}
+ ;
+ terminator,callback terminator/{;}/
+ \edef\skv@foreach@terminator{\unexpanded{#1}}%
+ \skvstripouterbraces{2}\skv@foreach@terminator
+ ;
+ % process up to = <nr>
+ % Maximum number of items to process:
+ process up to,process up to number//
+ \skviflacus#1\then\else
+ \skvensureinteger{process up to}{#1}%
+ \def\skv@foreach@processupto{#1}%
+ \skvstripouterbraces{2}\skv@foreach@processupto
+ \fi
+ ;
+ process empty list/true/
+ \edef\skv@foreach@processempty{0\skvifstrcmpTF{true}{#1}01}%
+ /true,false
+ ;
+ % 'break=<condition>'
+ % Break list processing when <condition> is satisfied. <condition> must
+ % be a balanced plain TeX conditional. Eg, 'exit when={\ifnum\x=20\fi}'.
+ % Notice the use of outer braces in '{\ifnum\x=20\fi}'. This avoids
+ % conflicting the two equality signs: for the key-value and for number
+ % testing.
+ .exec/\let\skv@foreach@exittester\@secondoftwo;
+ break,loop stopper,exit when/\if01\fi/
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \skvstripouterbraces{2}\skv@tempa
+ \skvexpbracenext\skv@foreach@maketester\skv@tempa
+ \skv@foreach@exittester\@ne
+ ;
+ % Java-type of continue: If the user wants to ignore the callback for
+ % some items, he can instantiate the key 'condition=<condition>'.
+ % <condition> must be a balanced plain TeX conditional. Eg,
+ % continue={\ifnum\x=20\fi}.
+ .exec/\let\skv@foreach@continuetester\@secondoftwo;
+ continue,ignore callback/\if01\fi/
+ \edef\skv@tempa{\unexpanded{#1}}%
+ \skvstripouterbraces{2}\skv@tempa
+ \skvexpbracenext\skv@foreach@maketester\skv@tempa
+ \skv@foreach@continuetester\skvz@
+ ;
+ % Eg, 'evaluate = \x as \z using \numexpr\x*2'. 'as' and 'using', and the
+ % tokens after them, can be missing, but the formula must be complete.
+ evaluate/\@nil/
+ \skv@foreach@ifacceptkv{#1}{%
+ \skv@foreach@parseevaluate{#1}%
+ }%
+ ;
+ % The evaluator \numexpr will invariably be used internally for this key.
+ % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'.
+ evaluate num,evaluate number/\@nil/
+ \skv@foreach@ifacceptkv{#1}{%
+ \skv@foreach@ifholderisonecmd{evaluate number}{#1}{%
+ \skv@foreach@parseevaluate{#1as#1using\numexpr#1}%
+ }%
+ }%
+ ;
+ % The evaluator \dimexpr will invariably be used internally for this key.
+ % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'.
+ evaluate dim,evaluate dimension/\@nil/
+ \skv@foreach@ifacceptkv{#1}{%
+ \skv@foreach@ifholderisonecmd{evaluate dimension}{#1}{%
+ \skv@foreach@parseevaluate{#1as#1using\dimexpr#1}%
+ }%
+ }%
+ ;
+ % Eg, 'expand=\x'.
+ % Fully expand holder macro. This is equivalent to, eg, edef\x{\x}.
+ % 'as' and 'using' are illegal here. This is only a shortcut for 'evaluate'.
+ expand,expanded/\@nil/
+ \skv@foreach@ifacceptkv{#1}{%
+ \skv@foreach@ifholderisonecmd{expand}{#1}{%
+ \skv@foreach@parseevaluate{#1as#1using#1}%
+ }%
+ }%
+ ;
+ % Eg, 'pgf parse = \x as \xe using \x*3'. 'as' and 'using', and the
+ % tokens after them, can be present or missing.
+ % \pgfmathparse is always used for this key.
+ pgf evaluate,pgf parse,pgfmath parse/\@nil/
+ \skv@foreach@ifacceptkv{#1}{%
+ \skv@foreach@parsepgfmathparse{#1}%
+ }%
+ ;
+ % count in = \y all \x satisfying <condition> initially <value>
+ % Eg,
+ % count in = \p all \x satisfying \ifnum\x>4\fi, or
+ % count in = \p all \x satisfying \skvifnumTF\x>4
+ % The counting is not additive, meaning that the counter is initialized
+ % to zero on each depth.
+ count in,count/\@nil/
+ \skv@foreach@ifacceptkv{#1}{%
+ \skv@foreach@parsecountin{#1}%
+ }%
+ ;
+ % Eg, 'remember=\x as \y initially A':
+ remember/\@nil/
+ \skv@foreach@ifacceptkv{#1}{%
+ \skv@foreach@parseremember{#1}%
+ }%
+ ;
+ % Eg, 'recall=\x initially A'.
+ % 'recall' is as 'remember', but will save the value of the holder macro
+ % in \<foreachlast><holder>. 'as' is invalid/illegal here, since a
+ % retainer macro is built internally:
+ retain,recall,call up/\@nil/
+ \skv@foreach@ifacceptkv{#1}{%
+ \skv@foreach@parserecall{#1}%
+ }%
+ ;
+ item counter,counter/\foreachdefaultitemcounter/
+ \skvifescapedTF{#1}{%
+ \def\skv@foreach@itemcounter{#1}%
+ }{%
+ \skv@err{Non-escaped value '\detokenize{#1}'
+ \MessageBreak for key 'item counter'}\skv@ehd
+ }%
+ ;
+ list breaker/\foreachlistbreaker/
+ \edef\skv@prova{\unexpanded{#1}}%
+ \ifx\skv@prova\@empty
+ \skv@err{Invalid empty value for key 'list breaker'}\skv@ehd
+ \else
+ \let\skv@listbreakertoks\skv@prova
+ \fi
+ ;
+ list pauser/\foreachlistpauser/
+ \edef\skv@prova{\unexpanded{#1}}%
+ \ifx\skv@prova\@empty
+ \skv@err{Invalid empty value for key 'list pauser'}\skv@ehd
+ \else
+ \let\skv@listpausertoks\skv@prova
+ \fi
+ ;
+ % Remember outside the loop the holder values. Of course, this
+ % means remembering only the latest values.
+ recover holder values,recover holder values after loop/true/
+ \edef\skv@foreach@recoverholders{0\skvifstrcmpTF{true}{#1}01}%
+ /true,false
+ ;
+ % This default value of 'link' is required by \skvautocompletelist:
+ .exec code/\def\skv@foreach@link{\@nil};
+ link/\@nil/
+ \edef\skv@prova{\unexpanded{#1}}%
+ \ifcase0%
+ \ifx\skv@prova\@empty 1\fi
+ \ifx\skv@prova\@nnil 1\fi\relax
+ \edef\skv@foreach@link{\unexpanded{#1}}%
+ \skvstripouterbraces{2}\skv@foreach@link
+ \fi
+ ;
+ grow/\@nil/
+ \edef\skv@prova{\unexpanded{#1}}%
+ \ifx\skv@prova\@nnil\else
+ \skvcsedef{skv@foreach@grow#1}{00}
+ \edef\skv@prova{\skvifstrcmpTF{#1}{left}{right}{left}}%
+ \skvcsedef{skv@foreach@grow\skv@prova}{01}%
+ \fi
+ /left,right
+ ;
+ .exec/
+ \def\skv@foreach@growleft{01}
+ \def\skv@foreach@growright{01}
+ ;
+ grow left/true/
+ \edef\skv@foreach@growleft{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ grow right/true/
+ \edef\skv@foreach@growright{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ % Keep the decimals in rounded numbers or dimensions when list is
+ % auto-completed. The value value of this key is 'true'.
+ keep decimals/true/
+ \edef\skv@foreach@keepdecimals{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ keep high decimals,keep only high decimals/true/
+ \edef\skv@foreach@keephighdecimals{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ % This key means that, eg, for \x/\y, do \let\y=\x if \y has no
+ % user value, ie, if the user gives as an item 'a' instead of
+ % 'a/b' or 'a/a'.
+ inherit,transfer macro values/true/
+ \edef\skv@foreach@inherit{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ expand before fill,expand list before fill/true/
+ \edef\skv@foreach@expandbeforefill{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ expand list once,x1,list is a macro,macro list/true/
+ \edef\skv@foreach@expandlistonce{0\skvifstrcmpTF{true}{#1}01}%
+ /true,false
+ ;
+ expand list twice,x2/true/
+ \edef\skv@foreach@expandlisttwice{0\skvifstrcmpTF{true}{#1}01}%
+ /true,false
+ ;
+ % Don't use 'expand' for this key, to avoid confusing it with
+ % the 'expand' for holder macros:
+ expand list,fully expand list,expand list fully,xx/true/
+ \edef\skv@foreach@expandlistfully{0\skvifstrcmpTF{true}{#1}01}%
+ /true,false
+ ;
+ reverse list,reverse,reflect/true/
+ \edef\skv@foreach@reverselist{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ % 'hide parameters' can be used to avoid doubling the parameter
+ % characters in the callback.
+ hide parameters/true/
+ \edef\skv@foreach@hideparameters{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+}
+
+% The following keys don't need presetting. The user must supply
+% values when they are called. In internal loops, their values will
+% have to be revised from those of the outer loop.
+%
+% link,evaluate,,evaluate num,evaluate dim,expand,count in,
+% process up to,grow
+%
+\skvquickkeys.preset{skeyval/foreach}{%
+ parser,subparser,loop stopper,callback terminator,process up to,
+ process empty list=false,item counter,list breaker,list pauser,
+ recover holder values=false,grow left=false,grow right=false,
+ keep decimals=true,keep high decimals=false,inherit=false,
+ expand before fill=false,reverse list=false,expand list once=false,
+ expand list twice=false,expand list fully=false,hide parameters=false
+}
+
+\skvnewdef*\skv@foreach@kvlist{}
+% \setupforeach{<kvlist>}
+\skvrobustdef*\setupforeach#1{%
+ \skvifblankTF{#1}{}{%
+ \skvaddtolist\skv@foreach@kvlist{#1}%
+ }%
+}
+\skvrobustdef*\skv@foreach@setkeys#1{%
+ \def\reserved@a{\skvquickkeys.set{skeyval/foreach}}%
+ \expandafter\reserved@a\expandafter{\skv@foreach@kvlist,#1}%
+}
+
+% evaluate=<holder.macro> as <child.macro> using <formula>
+%
+% 1. Evaluation is done with \edef unless \pgfmathparse is present
+% in <formula> or key 'pgf evaluate' is called.
+%
+% 2. <formula> must be a valid formula, eg,
+%
+% \pgfmathparse\x*2
+% \pgfmathparse{exp(50)*\x*2+sin(.5*pi)*60}
+% \numexpr\x*2
+% \skvexpandonce\x
+%
+% or simply
+%
+% 'evaluate \x as \x using <empty>'
+%
+% The latter is equivalent to asking for full expansion. See also
+% the keys 'evaluate num', 'evaluate dim', and 'expand'.
+%
+% 3. This allows <formula> to be generic.
+%
+\skvrobustdef*\skv@foreach@parseevaluate#1{%
+ \begingroup
+ \def\skv@tempxifin##1##2{%
+ \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}%
+ }%
+ \skv@foreach@swafalse
+ \def\skv@tempd{}%
+ \def\skv@tempa##1as##2using##3\skv@nil{%
+ \edef\skv@prova{\skvtrimspace{##1}}%
+ \edef\skv@provb{\skvtrimspace{##2}}%
+ \edef\skv@provc{\skvtrimspace{##3}}%
+ \ifx\skv@prova\@empty
+ \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd
+ \else
+ \expandafter\skvifescapedTF\expandafter{\skv@prova}{%
+ \expandafter\skvifntypeTF\expandafter{\skv@prova}{}{%
+ \skv@err{Value of key 'evaluate': more than 1
+ \MessageBreak token \skvoxdetok\skv@prova.
+ \MessageBreak I can't find holder macro}\skv@ehd
+ }%
+ }{%
+ \skv@err{Value of key 'evaluate':
+ \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd
+ }%
+ \fi
+ \ifx\skv@provb\@empty
+ \skv@err{Value of key 'evaluate' has no child macro}\skv@ehd
+ \else
+ \expandafter\skvifescapedTF\expandafter{\skv@provb}{%
+ \expandafter\skvifntypeTF\expandafter{\skv@provb}{}{%
+ \skv@err{Value of key 'evaluate': more than 1
+ \MessageBreak token \skvoxdetok\skv@provb.
+ \MessageBreak I can't find child macro}\skv@ehd
+ }%
+ }{%
+ \skv@err{Value of key 'evaluate':
+ \MessageBreak child \skvoxdetok\skv@provb not escaped}\skv@ehd
+ }%
+ \fi
+ \ifx\skv@provc\@empty
+ \skv@err{Value of key 'evaluate' has no formula or
+ \MessageBreak holder macro to be expanded}\skv@ehd
+ \fi
+ \skv@tempxifin{\pgfmathparse}{##3}{%
+ \def\skv@tempc####1\pgfmathparse####2\skv@nil{%
+ \ifx\@nnil####1\@nnil
+ \skv@foreach@swatrue
+ \else
+ \skv@err{Invalid token \detokenize{####1}
+ \MessageBreak before \string\pgfmathparse}\skv@ehd
+ \fi
+ }%
+ \skv@tempc##3\skv@nil
+ }{%
+ \skv@tempxifin{\numexpr}{##3}{%
+ \def\skv@tempd{\relax}%
+ }{%
+ \skv@tempxifin{\dimexpr}{##3}{%
+ \def\skv@tempd{\relax}%
+ }{%
+ \def\skv@tempd{}%
+ }%
+ }%
+ }%
+ }%
+ \skv@tempxifin{using}{#1}{%
+ \skv@tempxifin{as}{#1}{%
+ % 'as' and 'using' are present: maybe there is a formula.
+ \skv@foreach@swbtrue
+ \skv@tempa#1\skv@nil
+ }{%
+ \skv@err{Value of key 'evaluate':
+ \MessageBreak there is 'using', but no 'as'}\skv@ehd
+ }%
+ }{%
+ % No formula given. Maybe the key is 'expand' or still 'evaluate'
+ % but without formula.
+ \skv@foreach@swbfalse
+ \skv@tempxifin{as}{#1}{%
+ \def\skv@tempb##1as##2##3\skv@nil{%
+ \ifx\@nnil##1\@nnil
+ \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd
+ \else
+ \ifx\@nnil##2%
+ \skv@err{Value of key 'evaluate' has no child macro}\skv@ehd
+ \else
+ \skv@tempa##1as##2using##1\skv@nil
+ \fi
+ \fi
+ }%
+ \skv@tempb#1{\@nnil}\skv@nil
+ }{%
+ % No 'as' or 'using': #1 should be only the holder macro:
+ \ifx\@nnil#1\@nnil
+ \skv@err{Value of key 'evaluate' has no holder macro}\skv@ehd
+ \else
+ \skvifntypeTF{#1}{%
+ % Expand the holder macro:
+ \skv@tempa#1as#1using#1\skv@nil
+ }{%
+ \skv@err{Value of key 'evaluate': more than 1
+ \MessageBreak token '\detokenize{#1}'.
+ \MessageBreak I can't find holder macro}\skv@ehd
+ }%
+ \fi
+ }%
+ }%
+ \skv@foreach@addtocallback{afterpre}{%
+ \ifskv@foreach@swa
+ % <formula> has the syntax \pgfmathparse{\x}.
+ \skvexpandonce\skv@provc
+ \let\skvexpandonce\skv@provb\noexpand\pgfmathresult
+ \else
+ % <formula> has the syntax \numexpr\x*2 or \dimexpr\x*2.
+ % \ifskv@foreach@swb is true when a formula has been given.
+ \edef\skvexpandonce\skv@provb{%
+ \ifskv@foreach@swb\noexpand\the\fi
+ \skvexpandonce\skv@provc\skv@tempd
+ }%
+ \fi
+ }%
+ \skvaftergroupdef\skv@foreach@afterprecallback\endgroup
+}
+
+% pgfmath parse=<holder.macro> as <child.macro> using <formula>
+%
+% 1. Evaluation is always done with \pgfmathparse.
+%
+% 2. <formula> must be \pgfmathparse-able.
+%
+\skvrobustdef*\skv@foreach@parsepgfmathparse#1{%
+ \begingroup
+ \ifdefined\pgfmathparse\else
+ \skv@err{No \string\pgfmathparse; 'pgfmath' module not loaded}\skv@ehd
+ \fi
+ \def\skv@tempxifin##1##2{%
+ \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}%
+ }%
+ \skv@foreach@swafalse
+ \def\skv@tempa##1as##2using##3\skv@nil{%
+ \edef\skv@prova{\skvtrimspace{##1}}%
+ \edef\skv@provb{\skvtrimspace{##2}}%
+ \edef\skv@provc{\skvtrimspace{##3}}%
+ \ifx\skv@prova\@empty
+ \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd
+ \else
+ \expandafter\skvifescapedTF\expandafter{\skv@prova}{%
+ \expandafter\skvifntypeTF\expandafter{\skv@prova}{}{%
+ \skv@err{Value of key 'pgfmath parse': more than 1
+ \MessageBreak token \skvoxdetok\skv@prova.
+ \MessageBreak I can't find holder macro}\skv@ehd
+ }%
+ }{%
+ \skv@err{Value of key 'pgfmath parse':
+ \MessageBreak holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd
+ }%
+ \fi
+ \ifx\skv@provb\@empty
+ \skv@err{Value of key 'pgfmath parse' has no child macro}\skv@ehd
+ \else
+ \expandafter\skvifescapedTF\expandafter{\skv@provb}{%
+ \expandafter\skvifntypeTF\expandafter{\skv@provb}{}{%
+ \skv@err{Value of key 'pgfmath parse': more than 1
+ \MessageBreak token \skvoxdetok\skv@provb.
+ \MessageBreak I can't find child macro}\skv@ehd
+ }%
+ }{%
+ \skv@err{Value of key 'pgfmath parse':
+ \MessageBreak child \skvoxdetok\skv@provb not escaped}\skv@ehd
+ }%
+ \fi
+ \ifx\skv@provc\@empty
+ \skv@err{Value of key 'pgfmath parse' has no formula or
+ \MessageBreak holder macro to be expanded}\skv@ehd
+ \fi
+ \skv@tempxifin{\pgfmathparse}{##3}{%
+ \def\skv@tempc####1\pgfmathparse####2\skv@nil{%
+ \ifx\@nnil####1\@nnil
+ \skv@foreach@swatrue
+ \else
+ \skv@err{Invalid token \detokenize{####1}
+ \MessageBreak before \string\pgfmathparse}\skv@ehd
+ \fi
+ }%
+ \expandafter\skv@tempc\skv@provc\skv@nil
+ }{%
+ \skv@tempxifin{\numexpr}{##3}{%
+ \skv@err{Value of key 'pgfmath parse':
+ \MessageBreak\noexpand\numexpr not allowed}\skv@ehd
+ }{%
+ \skv@tempxifin{\dimexpr}{##3}{%
+ \skv@err{Value of key 'pgfmath parse':
+ \MessageBreak\noexpand\dimexpr not allowed}\skv@ehd
+ }{%
+ \skv@foreach@swatrue
+ \edef\skv@provc{\noexpand\pgfmathparse{\skvexpandonce\skv@provc}}%
+ }%
+ }%
+ }%
+ }%
+ \skv@tempxifin{using}{#1}{%
+ \skv@tempxifin{as}{#1}{%
+ % 'as' and 'using' are present: maybe there is a formula.
+ \skv@tempa#1\skv@nil
+ }{%
+ \skv@err{Value of key 'pgfmath parse':
+ \MessageBreak there is 'using', but no 'as'}\skv@ehd
+ }%
+ }{%
+ \skv@tempxifin{as}{#1}{%
+ \def\skv@tempb##1as##2##3\skv@nil{%
+ \ifx\@nnil##1\@nnil
+ \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd
+ \else
+ \ifx\@nnil##2%
+ \skv@err{Value of key 'pgfmath parse' has no child macro}\skv@ehd
+ \else
+ \skv@tempa##1as##2using##1\skv@nil
+ \fi
+ \fi
+ }%
+ \skv@tempb#1{\@nnil}\skv@nil
+ }{%
+ % No 'as' or 'using': #1 should be only the holder macro:
+ \ifx\@nnil#1\@nnil
+ \skv@err{Value of key 'pgfmath parse' has no holder macro}\skv@ehd
+ \else
+ \skvifntypeTF{#1}{%
+ % Evaluate the holder macro:
+ \skv@tempa#1as#1using#1\skv@nil
+ }{%
+ \skv@err{Value of key 'pgfmath parse': more than 1
+ \MessageBreak token '\detokenize{#1}'.
+ \MessageBreak I can't find holder macro}\skv@ehd
+ }%
+ \fi
+ }%
+ }%
+ \skv@foreach@addtocallback{afterpre}{%
+ \ifskv@foreach@swa
+ \skvexpandonce\skv@provc
+ \let\skvexpandonce\skv@provb\noexpand\pgfmathresult
+ \fi
+ }%
+ \skvaftergroupdef\skv@foreach@afterprecallback\endgroup
+}
+
+% count in = \y all \x satisfying <condition> initially <value>
+%
+% 1. <condition> must be a balanced and valid TeX conditional, like
+%
+% \ifnum\x>2\fi, \ifx\x\@empty\fi
+%
+% 2. The aim is to allow general conditions (not only those involving
+% numerals) to be submitted.
+%
+% 3. PGF's \foreach doesn't have this feature; it has only a general
+% counter, eg,
+%
+% '\foreach \x [count=\xi] in {a,...,e}'.
+%
+% Generic counting is available in \newforeach by default, without
+% user request. The macros \foreachcurrentitem, \foreachitemcount,
+% \foreachnextitem are always available on each nesting level. The
+% boolean \ifforeachlastitem is also always available, to indicate when
+% the last item of the list has been reached:
+%
+% \ifforeachlastitem \typeout{Processing last entry of the list} \fi
+%
+% 4. Counting is done from 1 (zero) unless <value> is given after
+% 'initially'.
+%
+\skvrobustdef*\skv@foreach@parsecountin#1{%
+ \begingroup
+ \def\skv@tempxifin##1##2{%
+ \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}%
+ }%
+ \def\skv@tempa##1\skv@nil{%
+ \skv@tempxifin{initially}{##1}{%
+ \skv@tempb##1\skv@nil
+ }{%
+ \skv@tempb##1initially\skv@nil
+ }%
+ }%
+ \def\skv@tempb##1all##2satisfying##3initially##4\skv@nil{%
+ \edef\skv@prova{\skvtrimspace{##1}}%
+ \edef\skv@provb{\skvtrimspace{##2}}%
+ \edef\skv@provc{\skvtrimspace{##3}}%
+ \edef\skv@provd{\skvtrimspace{##4}}%
+ \ifx\skv@prova\@empty
+ \skv@err{Value of key 'count' has no counter macro}\skv@ehd
+ \else
+ \expandafter\skvifescapedTF\expandafter{\skv@prova}{%
+ \expandafter\skvifntypeTF\expandafter{\skv@prova}{}{%
+ \skv@err{Value of key 'count in': more than 1
+ \MessageBreak token \skvoxdetok\skv@prova.
+ \MessageBreak I can't find counter macro}\skv@ehd
+ }%
+ }{%
+ \skv@err{Value of key 'count':\MessageBreak
+ counter macro \skvoxdetok\skv@prova not escaped}\skv@ehd
+ }%
+ \fi
+ \ifx\skv@provd\@empty
+ \expandafter\def\skv@prova{0}%
+ \else
+ \skvifintegerTF\skv@provd{%
+ \expandafter\let\skv@prova\skv@provd
+ }{%
+ \skv@err{Value of key 'count':\MessageBreak
+ initial \skvoxdetok\skv@provd not an integer}\skv@ehd
+ }%
+ \fi
+ \skv@foreach@swafalse
+ \ifx\skv@provc\@empty
+ % No tester but there may be a holder macro to test. The holder
+ % macro, on its own, isn't sufficient to conduct a test:
+ \let\skv@foreach@itemcounter\skv@prova
+ \else
+ \ifx\skv@provb\@empty\else
+ % If there isn't a holder macro or quantity to test, then no
+ % test is possible:
+ \expandafter\skvifescapedTF\expandafter{\skv@provb}{%
+ \expandafter\skvifntypeTF\expandafter{\skv@provb}{}{%
+ \skv@err{Value of key 'count in': more than 1
+ \MessageBreak token \skvoxdetok\skv@provb.
+ \MessageBreak I can't find holder macro}\skv@ehd
+ }%
+ }{%
+ \skv@err{Value of key 'count':\MessageBreak
+ holder macro \skvoxdetok\skv@provb not escaped}\skv@ehd
+ }%
+ \skv@foreach@swatrue
+ % \skv@tester is the second argument of \skv@foreach@maketester.
+ % \skv@tester is used in pushing the item counter:
+ \skvexpbracenext\skv@foreach@maketester\skv@provc\skv@tester\skvz@
+ \fi
+ \fi
+ }%
+ \skv@tempxifin{satisfying}{#1}{%
+ \skv@tempxifin{all}{#1}{%
+ % 'all' and 'satisfying' are present:
+ \skv@tempa#1\skv@nil
+ }{%
+ \skv@err{Value of key 'count':
+ \MessageBreak there is 'satisfying', but no 'all'}\skv@ehd
+ }%
+ }{%
+ \skv@tempxifin{all}{#1}{%
+ \skv@tempa#1satisfying\skv@nil
+ }{%
+ % No 'all' or 'satisfying': #1 should be only the counter macro:
+ \ifx\@nnil#1\@nnil
+ \skv@err{Value of key 'count' has no counter macro}\skv@ehd
+ \else
+ \skvifntypeTF{#1}{%
+ \skv@tempa#1all satisfying\skv@nil
+ }{%
+ \skv@err{Value of key 'count in': more than 1
+ \MessageBreak token '\detokenize{#1}'.
+ \MessageBreak I can't find counter macro}\skv@ehd
+ }%
+ \fi
+ }%
+ }%
+ \ifskv@foreach@swa
+ \skv@foreach@addtocallback{afterpre}{%
+ \noexpand\ifnum\noexpand\foreachitemcount=\@ne
+ \def\skvexpandonce\skv@prova{\number\skv@prova}%
+ \noexpand\fi
+ \skvexpandonce\skv@tester{%
+ \noexpand\skvpushnumber\skvexpandonce\skv@prova
+ }{}%
+ }%
+ \fi
+ \skvexpanded{\endgroup
+ \ifskv@foreach@swa
+ \skvcmdexit\skv@foreach@afterprecallback
+ \else
+ \skvcmdexit\skv@foreach@itemcounter
+ \fi
+ }%
+}
+
+% remember=<holder.macro> as <child.macro> initially <value>
+%
+\skvrobustdef*\skv@foreach@parseremember#1{%
+ \begingroup
+ \def\skv@tempxifin##1##2{%
+ \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}%
+ }%
+ \skv@tempxifin{(}{#1}{%
+ \skv@err{Value of key 'remember': '(' found.
+ \MessageBreak I don't accept this PGF format.
+ \MessageBreak Remove the parenthesis '(<your input>)'}\skv@ehd
+ }{}%
+ \def\skv@tempa##1as##2initially##3\skv@nil{%
+ \edef\skv@prova{\skvtrimspace{##1}}%
+ \edef\skv@provb{\skvtrimspace{##2}}%
+ \edef\skv@provc{\skvtrimspace{##3}}%
+ \skv@foreach@swafalse
+ \ifx\skv@prova\@empty
+ \skv@err{Value of key 'remember' has no holder macro:
+ \MessageBreak i.e., no macro that holds input}\skv@ehd
+ \else
+ \expandafter\skvifescapedTF\expandafter{\skv@prova}{}{%
+ \skv@err{Value of key 'remember':
+ \MessageBreak Holder macro \skvoxdetok\skv@prova not escaped}\skv@ehd
+ }%
+ \fi
+ \ifx\skv@provb\@empty
+ \skv@err{Value of key 'remember' has no child macro;
+ \MessageBreak i.e., no macro after 'as'}\skv@ehd
+ \else
+ \expandafter\skvifescapedTF\expandafter{\skv@provb}{%
+ \skv@foreach@swatrue
+ }{%
+ \skv@err{Value of key 'remember':
+ \MessageBreak Child \skvoxdetok\skv@provb not escaped}\skv@ehd
+ }%
+ \fi
+ }%
+ \skv@tempxifin{initially}{#1}{%
+ \skv@tempxifin{as}{#1}{%
+ \skv@tempa#1\skv@nil
+ }{%
+ \skv@err{Value of key 'remember':
+ \MessageBreak There is 'initially', but no 'as'}\skv@ehd
+ }%
+ }{%
+ \skv@tempxifin{as}{#1}{%
+ \skv@tempa#1initially\skv@nil
+ }{%
+ % No 'as' and 'initially':
+ \edef\skv@prova{\skvtrimspace{#1}}%
+ \ifx\skv@prova\@empty\else
+ % Go and raise error in \skv@tempa:
+ \skv@tempa#1as initially\skv@nil
+ \fi
+ }%
+ }%
+ \ifskv@foreach@swa
+ % Initially:
+ \skv@foreach@addtocallback{pre}{%
+ % Don't remove this \ifnum, otherwise the initial assignment
+ % will be overwritten on subsequent returns:
+ \noexpand\ifnum\noexpand\foreachitemcount=\@ne
+ \edef\skvexpandonce\skv@provb{%
+ \noexpand\unexpanded{\skvexpandonce\skv@provc}%
+ }%
+ \noexpand\fi
+ }%
+ \skv@foreach@addtocallback{post}{%
+ \let\skvexpandonce\skv@provb\skvexpandonce\skv@prova
+ }%
+ \fi
+ \skvexpanded{\endgroup
+ \ifskv@foreach@swa
+ \skvcmdexit\skv@foreach@precallback
+ \skvcmdexit\skv@foreach@postcallback
+ \fi
+ }%
+}
+
+% recall=<holder.macro> initially <value>.
+%
+% This builds a retainer macro of the form \<foreachlast><holder.name>.
+%
+% 'as' is invalid/illegal here, since a retainer macro is built internally.
+%
+\skvrobustdef*\skv@foreach@parserecall#1{%
+ \begingroup
+ \def\skv@tempxifin##1##2{%
+ \skvxifinTF{\detokenize{##1}}{\detokenize{##2}}%
+ }%
+ \skv@tempxifin{(}{#1}{%
+ \skv@err{Value of key 'recall': '(' found.
+ \MessageBreak I don't accept this PGF format.
+ \MessageBreak remove the parenthesis '()'}\skv@ehd
+ }{}%
+ \skv@foreach@swafalse
+ \def\skv@tempa##1initially##2\skv@nil{%
+ \edef\skv@prova{\skvtrimspace{##1}}%
+ \edef\skv@provb{\skvtrimspace{##2}}%
+ \ifx\skv@prova\@empty
+ \skv@err{Value of key 'recall' has no holder macro:
+ \MessageBreak i.e., no macro that holds input}\skv@ehd
+ \else
+ \expandafter\skvifntypeTF\expandafter{\skv@prova}{%
+ \expandafter\skvifescapedTF\expandafter{\skv@prova}{%
+ \edef\skv@elt{\expandafter\skvremovescape\skv@prova}%
+ \skv@foreach@swatrue
+ % Initially:
+ \skv@foreach@addtocallback{pre}{%
+ % Don't remove this \ifnum, otherwise the initial assignment
+ % will be overwritten on subsequent returns:
+ \noexpand\ifnum\noexpand\foreachitemcount=\@ne
+ \skvcsedef{foreachlast\skv@elt}{%
+ \noexpand\unexpanded{\skvexpandonce\skv@provb}%
+ }%
+ \noexpand\fi
+ }%
+ \skv@foreach@addtocallback{post}{%
+ \skvcslet{foreachlast\skv@elt}\skvexpandonce\skv@prova
+ }%
+ }{%
+ \skv@err{Value of key 'recall':
+ \MessageBreak \detokenize{#1} is not escaped}\skv@ehd
+ }%
+ }{%
+ \skv@err{Value of key 'recall':
+ \MessageBreak \detokenize{#1} is not one token}\skv@ehd
+ }%
+ \fi
+ }%
+ \skv@tempxifin{as}{#1}{%
+ \skv@err{Value of key 'recall': invalid 'as' found.
+ \MessageBreak This key doesn't expect 'as' since
+ \MessageBreak it automatically builds a retainer macro
+ \MessageBreak of the form \<foreachlast><holder.name>}\skv@ehd
+ }{%
+ \skv@tempxifin{initially}{#1}{%
+ \skv@tempa#1\skv@nil
+ }{%
+ \ifx\@nnil#1\@nnil\else
+ \skv@tempa#1initially\skv@nil
+ \fi
+ }%
+ }%
+ \skvexpanded{\endgroup
+ \ifskv@foreach@swa
+ \skvcmdexit\skv@foreach@precallback
+ \skvcmdexit\skv@foreach@postcallback
+ \fi
+ }%
+}
+% \skv@foreach@doreverselist{<parser>}{<listcmd>}
+\skvnewdef*\skv@foreach@doreverselist#1#2{%
+ \begingroup
+ \def\skv@tempb{}%
+ \def\skv@tempa##1#1##2\skv@reverse@stop{%
+ \if\relax\detokenize{##2}\relax\skv@reverse@stop\fi
+ \skv@tempa##2\skv@reverse@stop
+ \edef\skv@tempb{%
+ \skvexpandonce\skv@tempb\ifx\skv@tempb\@empty\else#1\fi
+ \unexpanded{##1}%
+ }%
+ }%
+ \def\skv@reverse@stop##1\skv@reverse@stop{\fi}%
+ \expandafter\skv@tempa#2#1\skv@reverse@stop
+ \let#2\skv@tempb
+ \skvaftergroupdef#2\endgroup
+}
+
+% Eg, \skv@dots@in<value>\skv@nil...\skv@nnil\skv@stop
+\skvnewdef*\skv@dots@in#1...#2#3\skv@stop{%
+ \ifx\skv@nnil#2\in@false\else\in@true\fi
+}
+
+\skvrobustdef*\skv@foreach@latehookerr{%
+ \def\skv@foreach@latehook{%
+ \begingroup
+ \let\s\string
+ \skv@err{A \noexpand\newforeach hook (\s\prependtobeginforeach,
+ \MessageBreak\s\appendtobeginforeach, \s\atbeginforeach,
+ \MessageBreak\s\prependtoendforeach, \s\appendtoendforeach,
+ \MessageBreak or \s\atendforeach) has been illegally
+ \MessageBreak issued within \s\newforeach}
+ {\s\newforeach\space hook command shouldn't be issued
+ within \s\newforeach.}%
+ \endgroup
+ }%
+ \skvletmanytocmd{%
+ \prependtobeginforeach,\appendtobeginforeach,\atbeginforeach,
+ \prependtoendforeach,\appendtoendforeach,\atendforeach
+ }\skv@foreach@latehook
+}
+
+\skvrobustdef*\skv@foreach@pushstate{%
+ \skvsavestate\skv@foreach@stack{%
+ \do\skv@foreach@starform\do\skv@foreach@parser
+ \do\skv@foreach@subparser\do\skv@foreach@listisamacro
+ \do\skv@foreach@processupto\do\skv@foreach@processempty
+ \do\skv@foreach@exittester\do\skv@foreach@continuetester
+ \do\skv@foreach@grow\do\skv@foreach@growleft\do\skv@foreach@growright
+ \do\skv@foreach@terminator\do\skv@foreach@recoverholders
+ \do\skv@foreach@normalizelist\do\skv@foreach@callback
+ \do\skv@foreach@hideparameters\do\skv@foreach@callback@hiddenparameters
+ \do\skv@foreach@auxcallback\do\skv@foreach@precallback
+ \do\skv@foreach@afterprecallback\do\skv@foreach@postcallback
+ \do\skv@foreach@onlyinitially
+ \do\foreachlistremainder\do\skv@foreach@mainloop
+ \do\skv@foreach@getnext\do\skv@foreach@picknext\do\skv@foreach@getrm
+ \do\skv@foreach@do@a\do\skv@foreach@do@b
+ % Macros '...lookahead...' need stacking in \foreachfox and when
+ % \newforeach is nested with \foreachfox:
+ \do\skv@foreach@lookahead@a\do\skv@foreach@lookahead@b
+ \do\skv@foreach@lookahead@c\do\skv@foreach@lookahead@d
+ \do\skv@foreach@paramlist\do\skv@foreach@holderlist
+ \do\skv@foreach@userlist\do\skv@foreach@inherit
+ \do\skv@foreach@keepdecimals\do\skv@foreach@keephighdecimals
+ \do\skv@foreach@itemcounter\do\skv@foreach@link
+ \do\skv@foreach@expandbeforefill\do\skv@foreach@expandlistonce
+ \do\skv@foreach@expandlisttwice\do\skv@foreach@expandlistfully
+ \do\skv@listbreakertoks\do\skv@listpausertoks
+ \do\skv@foreach@reverselist\do\foreachcurrentitem
+ \do\foreachnextitem\do\foreachitemcount\do\foreachprevitem
+ % The following commands are disabled on entry into the loop.
+ % Hence they need to be stacked here:
+ \do\prependtobeginforeach\do\appendtobeginforeach\do\atbeginforeach
+ \do\prependtoendforeach\do\appendtoendforeach\do\atendforeach
+ }\foreachnestdepth
+}
+\skvrobustdef*\skv@foreach@popstate{%
+ \skvrestorestate\skv@foreach@stack\foreachnestdepth
+}
+\skvnewlet\skv@foreach@nil\relax
+\skvnewdef*\skv@foreach@nnil{\skv@foreach@nil}
+\skvrobustdef*\newforeach{\skv@testst\skv@newforeach@beginprescan}
+\skvrobustdef*\skv@newforeach@beginprescan{%
+ \skv@inforeachtrue
+ \edef\skv@foreach@starform{0\ifskv@tempst0\else1\fi}%
+ \begingroup
+ \def\skv@foreach@holderlist{}%
+ \def\skv@tempa{%
+ \skvexpanded{\endgroup
+ \noexpand\skv@foreach@endprescan
+ {\skvexpandonce\skv@foreach@holderlist}%
+ }%
+ }%
+ \let\bgroup\relax
+ \skvifnextchar[{%
+ \endgroup\skv@foreach@scanarg
+ }{%
+ \skvifnextchar i{%
+ \endgroup
+ \skv@err{\string\newforeach: no holder macro seen}\skv@ehd
+ }{%
+ \skvifnextchar\skv@orig@bgroup{%
+ \endgroup
+ \skv@err{\string\newforeach: no holder macro seen}\skv@ehd
+ }{%
+ \skv@foreach@collectholders
+ }%
+ }%
+ }%
+}
+\skvrobustdef*\skv@foreach@collectholders#1{%
+ \edef\skv@foreach@holderlist{%
+ \skvexpandonce\skv@foreach@holderlist\skvtrimspace{#1}%
+ }%
+ \skvifnextchar[{%
+ \skv@tempa
+ }{%
+ \skvifnextchar i{%
+ \skv@tempa[]%
+ }{%
+ \skvifnextchar\skv@orig@bgroup{%
+ \skv@tempa[]%
+ }{%
+ \skv@foreach@collectholders
+ }%
+ }%
+ }%
+}
+\skvrobustdef*\skv@foreach@endprescan#1[#2]{%
+ \skvifblankTF{#1}{%
+ \skv@err{\string\newforeach: no holder macros seen}\skv@ehd
+ }{%
+ \skv@foreach@scanarg[#2]#1%
+ }%
+}
+\skvrobustdef*\skv@foreach@scanarg{\skv@testopt\skv@foreach@scanarg@a{}}
+\skvrobustdef*\skv@foreach@scanarg@a[#1]{%
+ \skv@foreach@pushstate
+ \skv@foreach@latehookerr
+ % \foreachitemcount must be a macro, not a counter, because it is stacked:
+ \def\foreachitemcount{0}%
+ % Don't confuse macros of various depths; reset them here:
+ \def\do##1{\def##1{}}%
+ \do\skv@foreach@itemcounter\do\skv@foreach@processupto
+ \do\skv@foreach@callback\do\skv@foreach@auxcallback
+ \do\skv@foreach@callback@hiddenparameters
+ \do\skv@foreach@precallback\do\skv@foreach@afterprecallback
+ \do\skv@foreach@postcallback\do\skv@foreach@onlyinitially
+ % The keys have to be set here, to determine if the list is a macro, etc.
+ % Since \skv@foreach@precallback are initialized in each nest, the
+ % keys have to be reset here. Reset all keys: they might have been
+ % fixed by the outer loop and the inner loop might assume the default
+ % values of the keys are those being used.
+ \skv@foreach@setkeys{#1}%
+ % We've set the keys; let's overrule \skv@foreach@expandlistonce if
+ % we had seen a star suffix. Don't overrule \skv@foreach@expandlisttwice
+ % and \skv@foreach@expandlistfully.
+ \if\skv@foreach@starform
+ \def\skv@foreach@expandlistonce{00}%
+ \fi
+ \ifcase0%
+ % Take only one case:
+ \if\skv@foreach@expandlistonce\else
+ \if\skv@foreach@expandlisttwice\else
+ \if\skv@foreach@expandlistfully\else 1\fi\fi\fi\relax
+ \def\skv@foreach@listisamacro{00}%
+ \else
+ \def\skv@foreach@listisamacro{01}%
+ \fi
+ \begingroup
+ % Collect item holders. Don't confuse explicit \bgroup for left brace:
+ \skv@cnta\skvz@
+ \def\skv@foreach@holderlist{}%
+ \let\bgroup\relax
+ \skvifnextchar i\skv@foreach@scanarg@c{%
+ \skvifnextchar\skv@orig@bgroup
+ \skv@foreach@scanarg@d\skv@foreach@scanarg@b
+ }%
+}
+% #1: one holer macro or subparser.
+\skvrobustdef*\skv@foreach@scanarg@b#1{%
+ % Odd items must be subparser:
+ \ifodd\skv@cnta
+ \ifnum\skv@cnta=\@ne
+ \skvifescapedTF{#1}{%
+ \skv@err{Token '\noexpand#1' cannot be a subparser;
+ \MessageBreak it seems to be a holder macro. I expected
+ \MessageBreak the subparser to be the token here.}\skv@ehd
+ }{%
+ \edef\skv@prova{\skvtrimspace{#1}}%
+ \let\elt\skvexpandonce
+ \let\skv@elt\skv@foreach@subparser
+ \if\elt\skv@prova\elt\skv@elt\else
+ % Don't stack \skv@warnsubparser, so that the following
+ % warning isn't called more than once in the inner loop.
+ \ifnum\skv@warnsubparser=\skvz@
+ \skvgadvanceno\skv@warnsubparser\@ne
+ \skv@warn{Scanned subparser '\elt\skv@prova' is different from
+ \MessageBreak the default or user-supplied subparser '\elt\skv@elt'.
+ \MessageBreak I have used '\elt\skv@prova', but please submit
+ \MessageBreak '\elt\skv@prova' as the value of the key
+ 'subparser'
+ \MessageBreak so that I can stop giving this warning.
+ }%
+ \fi
+ \let\skv@foreach@subparser\skv@prova
+ \fi
+ }%
+ \fi
+ \else
+ \skvifescapedTF{#1}{}{%
+ \skv@err{Token '\noexpand#1' is not escaped
+ \MessageBreak and can't be a holder macro}\skv@ehd
+ }%
+ \fi
+ \advance\skv@cnta\@ne
+ \edef\skv@foreach@holderlist{%
+ \skvexpandonce\skv@foreach@holderlist\skvtrimspace{#1}%
+ }%
+ \skvifnextchar i\skv@foreach@scanarg@c{%
+ \skvifnextchar\skv@orig@bgroup
+ \skv@foreach@scanarg@d\skv@foreach@scanarg@b
+ }%
+}
+\skvrobustdef*\skv@foreach@scanarg@c#1#2{%
+ \skvifstrcmpTF{#1#2}{in}{%
+ \skv@foreach@scanarg@d
+ }{%
+ \skv@err{I have seen 'i' but no expected 'in'}\skv@ehd
+ }%
+}
+\skvrobustdef*\skv@foreach@scanarg@d{%
+ \ifx\skv@foreach@holderlist\@empty
+ \skv@err{No item holder macros before 'in'
+ \MessageBreak or before left brace}\skv@ehd
+ \fi
+ \skvifnextchar\skv@orig@bgroup{%
+ \skv@foreach@scanarg@e
+ }{%
+ \if\skv@foreach@listisamacro
+ \expandafter\skv@foreach@scanarg@e
+ \else
+ \def\reserved@a##1{%
+ \skvifmacroTF{##1}{%
+ \def\skv@tempehd{Maybe a star (*) suffix after
+ \noexpand\newforeach or key 'expand list once', etc.,
+ \MessageBreak is missing.}%
+ }{%
+ \let\skv@tempehd\skv@ehd
+ }%
+ \skv@err{I expected a left brace for beginning of list,
+ \MessageBreak since you haven't told me that your
+ \MessageBreak list is a macro. Instead I found '\detokenize{##1}'.
+ \MessageBreak If your list is indeed a macro, you can
+ \MessageBreak either put star (*) after \noexpand\newforeach
+ \MessageBreak or use the key 'expand list once'
+ \MessageBreak or 'expand list twice' or 'list is a macro', etc.%
+ }\skv@tempehd
+ }%
+ \expandafter\reserved@a
+ \fi
+ }%
+}
+% #1: <list> or <listcmd>
+\skvrobustdef*\skv@foreach@scanarg@e#1{%
+ \edef\skv@foreach@userlist{\unexpanded{#1}}%
+ \skvifnextchar\skv@orig@bgroup\skv@foreach@scanarg@h{%
+ \skvifnextchar d\skv@foreach@scanarg@f\skv@foreach@scanarg@g
+ }%
+}
+\skvrobustdef*\skv@foreach@scanarg@f#1#2{%
+ \skvifstrcmpTF{#1#2}{do}{%
+ \skvifnextchar\skv@orig@bgroup
+ \skv@foreach@scanarg@h\skv@foreach@scanarg@g
+ }{%
+ \skv@err{I have seen 'd' but no the expected 'do'}\skv@ehd
+ }%
+}
+% We've exhausted all options for grabbing the callback, so now
+% look for terminator (default ;).
+%
+% 1. If there is no terminator ahead, the use of \skv@prova will trigger
+% 'the use of ... does not match its definition' or
+% 'runaway argument ...'.
+% 2. This covers the case when \newforeach or \foreach comes next in
+% the callback.
+\skvrobustdef*\skv@foreach@scanarg@g{%
+ \def\skv@prova##1{%
+ \def\skv@prova####1##1{%
+ % Look out for a case like 'parser=<parser>'.
+ % Eg, \newforeach[parser=;]. In this case, the value ';' of
+ % key 'parser' will mistakenly be assumed to be the callback
+ % terminator. It should be enclosed in braces.
+ \skvxifinTF{\detokenize{parser=}\relax}{\detokenize{####1}\relax}{%
+ \skvxifinTF{[}{\detokenize{####1}}{%
+ \skv@err{Put '##1' in braces for key 'parser=##1'.
+ \MessageBreak Try [parser={##1}]}
+ {Maybe parser '##1' is the value of a key/option of
+ \noexpand\newforeach and needs to be enclosed in braces.
+ The '##1' I have just encountered doesn't seem to be the
+ one ending a TikZ object. Maybe you need to do [parser={##1}].}%
+ }{%
+ % Otherwise, let's try continue:
+ \skvexpanded{%
+ \noexpand\skv@foreach@scanarg@h{\skvtrimspace{####1}##1}%
+ }%
+ }%
+ }{%
+ \skvexpanded{%
+ \noexpand\skv@foreach@scanarg@h{\skvtrimspace{####1}##1}%
+ }%
+ }%
+ }%
+ \skv@prova
+ }%
+ % In case callback terminator is currently active, rescan it.
+ \skvrescan\skv@foreach@terminator
+ \expandafter\skv@prova\expandafter{\skv@foreach@terminator}%
+}
+% #1: callback
+\skvrobustdef*\skv@foreach@scanarg@h#1{%
+ \skvexpanded{\endgroup
+ % The subparser may have changed along the way
+ % (see \skv@foreach@scanarg@b):
+ \skvcmdexit\skv@foreach@subparser
+ \skv@foreach@mainprocess
+ {\skvexpandonce\skv@foreach@holderlist}%
+ {\skvexpandonce\skv@foreach@userlist}%
+ {\skvtrimspace{#1}}%
+ }%
+}
+% #1: holder macros
+% #2: List or list command
+% #3: Callback
+\skvrobustdef*\skv@foreach@mainprocess#1#2#3{%
+ \edef\skv@foreach@userlist{%
+ \if\skv@foreach@expandlistonce
+ \expandafter\skvexpandonce
+ \else
+ \if\skv@foreach@expandlisttwice
+ \expandafter\expandafter\expandafter\skvexpandtwice
+ \else
+ \if\skv@foreach@expandlistfully
+ \expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter\@iden
+ \else
+ \expandafter\expandafter\expandafter\expandafter
+ \expandafter\expandafter\expandafter\unexpanded
+ \fi
+ \fi
+ \fi
+ {#2}%
+ }%
+ % Initial code, if any:
+ \skvcsuse{skv@foreach@atbeginhook@\skvrom\foreachnestdepth}%
+ \skvifdefTF\foreachprevitem{}{\def\foreachprevitem{}}%
+ \expandafter\skv@foreach@normalize\expandafter[\skv@foreach@parser]%
+ \skv@foreach@userlist
+ % Why 'keep double parser' here? Think of a list like 32//13,11/23/,...
+ \skvexpbracenext\skvdefinekeepdoubleparsernormalizer
+ \skv@foreach@subparser\skv@tempa
+ \edef\skv@foreach@userlist{\skvexpbracenext\skv@tempa\skv@foreach@userlist}%
+ \ifnum\foreachnestdepth=\skvz@
+ \breakallforeachloopsfalse
+ \fi
+ \skvbreakloopfalse
+ \foreachlastitemfalse
+ \def\skv@foreach@lookahead@a##1{%
+ \def\skv@foreach@picknext{##1.}%
+ \futurelet\skv@foreach@next\skv@foreach@lookahead@b
+ }%
+ \def\skv@foreach@lookahead@b{%
+ \ifx\skv@foreach@next[%
+ \expandafter\skv@foreach@lookahead@c
+ \else
+ \ifx\skv@foreach@next(%
+ \expandafter\expandafter\expandafter\skv@foreach@lookahead@d
+ \else
+ \expandafter\expandafter\expandafter\skv@foreach@picknext
+ \fi
+ \fi
+ }%
+ \def\skv@foreach@lookahead@c[##1]{\skv@foreach@picknext[{##1}]}%
+ \def\skv@foreach@lookahead@d(##1){\skv@foreach@picknext({##1})}%
+ \def\skv@foreach@mainloop##1{%
+ \def\skv@foreach@getnext####1##1####2\skv@foreach@stop{%
+ \edef\foreachnextitem{\skvexpandonce{\@gobble####1}}%
+ \ifx\foreachnextitem\skv@foreach@nnil
+ \foreachlastitemtrue
+ \def\foreachnextitem{}%
+ \fi
+ }%
+ \def\skv@foreach@do@a####1##1####2\skv@foreach@stop{%
+ \edef\foreachcurrentitem{\skvexpandonce{\@gobble####1}}%
+ \skvifxTF\foreachcurrentitem\skv@foreach@nnil{%
+ \skvbreakloopfalse
+ \foreachlastitemfalse
+ }{%
+ \skvifxTF\foreachcurrentitem\skv@listbreakertoks{%
+ \skv@foreach@getrm{####2}%
+ }{%
+ \skvifxTF\foreachcurrentitem\skv@listpausertoks{%
+ \message{^^J! List pause:
+ ^^JType x or X to quit, or <RETURN> to proceed^^J}%
+ \begingroup
+ \endlinechar\m@ne\global\read-1 to\@gtempa
+ \endgroup
+ \skvexpandarg\lowercase{\def\noexpand\@gtempa{\@gtempa}}%
+ \skvxifstrcmpTF\@gtempa{x}{%
+ \skv@foreach@getrm{####2}%
+ }{%
+ \skv@foreach@do@b{####2}%
+ }%
+ }{%
+ \skv@foreach@do@b{####2}%
+ }%
+ }%
+ }%
+ }%
+ \def\skv@foreach@do@b####1{%
+ \edef\foreachitemcount{\the\numexpr\foreachitemcount+1}%
+ \ifx\skv@foreach@itemcounter\@empty\else
+ \expandafter\let\skv@foreach@itemcounter\foreachitemcount
+ \fi
+ \skv@foreach@lookahead@a\skv@foreach@getnext####1\skv@foreach@stop
+ % If the user decides to continue after \foreachlistpauser is picked up,
+ % don't use \foreachlistpauser as an item:
+ \skvifxTF\foreachcurrentitem\skv@listpausertoks{}{%
+ \skvexpbracenext\skv@foreach@callback\foreachcurrentitem
+ \let\foreachprevitem\foreachcurrentitem
+ }%
+ \ifx\skv@foreach@processupto\@empty\else
+ \ifnum\foreachitemcount<\skv@foreach@processupto\relax\else
+ \skvbreakloop
+ \fi
+ \fi
+ \skvifdefboolTF{skvbreakloop}{%
+ \skv@foreach@getrm{####1}%
+ }{%
+ \skv@foreach@lookahead@a\skv@foreach@do@a####1\skv@foreach@stop
+ }%
+ }%
+ \def\skv@foreach@getrm####1{%
+ \ifbreakallforeachloops\else
+ \skvbreakloopfalse
+ \fi
+ \foreachlastitemfalse
+ \def\skv@prova########1\skv@foreach@nil##1{%
+ \edef\foreachlistremainder{\unexpanded{########1}}%
+ \skv@removetrailingparser{##1}\foreachlistremainder
+ }%
+ \skv@prova####1%
+ }%
+ \skvifxTF\skv@foreach@userlist\@empty{%
+ \if\skv@foreach@processempty\skvafterfi
+ \skv@foreach@callback{}%
+ \fi
+ }{%
+ \def\do####1{\if####1true\else false\fi}%
+ \skvexpandsecond{\skvautocompletelist*}{[%
+ % Note: the value of 'expand list once', etc., can't be
+ % transferred automatically to \skvautocompletelist since they
+ % have been used above to expand list.
+ parser={\skv@foreach@parser},
+ link={\skvexpandonce\skv@foreach@link},
+ grow left=\do\skv@foreach@growleft,
+ grow right=\do\skv@foreach@growright,
+ keep decimals=\do\skv@foreach@keepdecimals,
+ keep high decimals=\do\skv@foreach@keephighdecimals,
+ expand before fill=\do\skv@foreach@expandbeforefill
+ ]}\skv@foreach@userlist\skv@foreach@userlist
+ \if\skv@foreach@reverselist\skvafterfi
+ \expandafter\skv@foreach@doreverselist\expandafter
+ {\skv@foreach@parser}\skv@foreach@userlist
+ \fi
+ \expandafter\skv@foreach@lookahead@a\expandafter\skv@foreach@do@a
+ \skv@foreach@userlist##1\skv@foreach@nil##1\skv@foreach@stop
+ }%
+ }%
+ \skv@foreach@makeprecode{#1}%
+ \if\skv@foreach@recoverholders\else
+ \expandafter\skvsavestate\expandafter\skv@foreach@holderstate
+ \expandafter{\skv@foreach@holderlist}\skv@foreach@holderdepth
+ \fi
+ \skv@foreach@makeauxcallback{#3}%
+ \skvexpandbracenext\skv@foreach@mainloop\skv@foreach@parser
+ \skvcsuse{skv@foreach@atendhook@\skvrom\foreachnestdepth}%
+ \if\skv@foreach@recoverholders\else
+ \skvrestorestate\skv@foreach@holderstate\skv@foreach@holderdepth
+ \fi
+ \skv@foreach@popstate
+ \ifnum\foreachnestdepth=\skvz@
+ \def\skv@warnsubparser{0}%
+ \fi
+ \skv@inforeachfalse
+}
+
+% \skv@foreach@makeprecode{<holder.list>}
+%
+% 'Holder macro' here means, eg, \x and \y in
+%
+% \newforeach \x/\y in {1/a,2/b,3/c}{<code>}
+%
+\skvrobustdef*\skv@foreach@makeprecode#1{%
+ \begingroup
+ \skv@cnta\skvz@
+ \def\skv@foreach@holderlist{}%
+ \def\skv@foreach@paramlist{}%
+ \def\skv@prevholder{}%
+ \def\skv@tempa{#1}%
+ \expandafter\skv@foreach@normalize\expandafter
+ [\skv@foreach@subparser]\skv@tempa
+ \skvtfor*\skv@prova:=\skv@tempa\do{%
+ \ifx\skv@prova\skv@foreach@subparser
+ \ifnum\skv@cnta=\skvz@
+ \skv@err{Subparser '\skvoxdetok\skv@foreach@subparser' can't come
+ first in the list\MessageBreak of holder macros}\skv@ehd
+ \else
+ % Eg, if subparser is slash (/), \skv@foreach@paramlist will have
+ % the syntax: ##1/##2/...:
+ \edef\skv@foreach@paramlist{%
+ \skvexpandonce\skv@foreach@paramlist\skvexpandonce\skv@prova
+ }%
+ \fi
+ \else
+ \advance\skv@cnta\@ne
+ \edef\skv@elt{\expandafter\skvremovescape\skv@prova}%
+ \edef\skv@foreach@precallback{%
+ \skvexpandonce\skv@foreach@precallback
+ % Each given item-holder macro is now defined in terms of
+ % parameters of skv@foreach@auxcallback:
+ \edef\skvexpandonce\skv@prova{%
+ \noexpand\unexpanded{####\number\skv@cnta}%
+ }%
+ % If the current holder has no value, use the value of last holder:
+ \ifnum\skv@cnta>\@ne
+ \if\skv@foreach@inherit
+ \noexpand\ifx\skvexpandonce\skv@prova\noexpand\@empty
+ \let\skvexpandonce\skv@prova\skvexpandonce\skv@prevholder
+ \noexpand\fi
+ \fi
+ \fi
+ }%
+ \edef\skv@foreach@holderlist{%
+ \skvexpandonce\skv@foreach@holderlist
+ % The \do is for the individual entries of the stack of
+ % \skv@foreach@holderlist. It is required for stacking the
+ % holder list:
+ \noexpand\do\skvexpandonce\skv@prova
+ }%
+ \edef\skv@foreach@paramlist{%
+ \skvexpandonce\skv@foreach@paramlist########\number\skv@cnta
+ }%
+ \let\skv@prevholder\skv@prova
+ \fi
+ }%
+ % Add one extra parameter character to absorb extra subparsers that are
+ % added for incomplete list items:
+ \edef\skv@foreach@paramlist{%
+ \skvexpandonce\skv@foreach@paramlist
+ \skvexpandonce\skv@foreach@subparser
+ ########\number\numexpr\skv@cnta+1\relax
+ }%
+ \skvexpanded{\endgroup
+ \skvcmdexit\skv@foreach@holderlist
+ \skvcmdexit\skv@foreach@paramlist
+ \skvcmdexit\skv@foreach@precallback
+ }%
+}
+% Example (*):
+%
+% This example demonstrates why \skv@foreach@continuetester must be
+% located delicately, at where it is currently.
+%
+% \def\ditem{D}
+% \newforeach [
+% continue=\ifx\x\ditem\fi, remember=\x as \rx initially A
+% ] \x in {
+% B,(C1),D,E,[F1],G,H
+% }{%
+% $\overrightarrow{\rx\x}$\ifforeachlastitem.\else,\space\fi
+% }
+%
+% #1: callback
+\skvrobustdef*\skv@foreach@makeauxcallback#1{%
+ \begingroup
+ \def\skv@generatesubparser##1{%
+ \ifnum##1<10 \skvexpandonce\skv@foreach@subparser
+ \expandafter\skv@generatesubparser
+ \expandafter{\number\numexpr##1+1\expandafter}%
+ \fi
+ }%
+ % Add extra subparsers in case some items aren't subparser-complete:
+ \edef\skv@tempa{\skv@generatesubparser{1}}%
+ \edef\skv@foreach@callback@hiddenparameters{\unexpanded{#1}}%
+ \let\foreacheov\relax
+ \let\do\noexpand
+ \skvexpanded{\endgroup
+ \skvcmdexit\skv@foreach@callback@hiddenparameters
+ % Define auxiliary callback:
+ \def\do\skv@foreach@auxcallback\skv@foreach@paramlist\foreacheov{%
+ % Holder macro assignments:
+ \skvexpandonce\skv@foreach@precallback
+ % User tests/tasks, eg, if requested from 'evaluate' key:
+ \skvexpandonce\skv@foreach@afterprecallback
+ \do\ifnum\do\foreachitemcount=\@ne
+ \do\skv@foreach@onlyinitially
+ \do\fi
+ \ifx\skv@foreach@continuetester\@secondoftwo
+ \noexpand\skv@foreach@continuetester
+ \else
+ % Expose the parameter characters in \skv@foreach@continuetester.
+ % If the user wants to ignore the callback for some items, he can
+ % use the key 'continue=<condition>':
+ \skvexpandonce\skv@foreach@continuetester
+ \fi
+ {%
+ \relax
+ }{%
+ \if\skv@foreach@hideparameters
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {%
+ \noexpand\skv@foreach@callback@hiddenparameters
+ }{%
+ \unexpanded{#1}%
+ }%
+ % User tests/tasks, eg, if requested from the keys 'remember',
+ % 'exit when', etc:
+ \skvexpandonce\skv@foreach@postcallback
+ }%
+ }%
+ % Define the real callback:
+ \def\do\skv@foreach@callback####1{%
+ \do\skv@foreach@auxcallback####1\skvxonce\skv@tempa\foreacheov
+ }%
+ }%
+}
+\skvnewdef*\skv@ucalpha#1{%
+ \ifcase#1\or A\or B\or C\or D\or E\or F\or G\or H\or I\or J\or
+ K\or L\or M\or N\or O\or P\or Q\or R\or S\or T\or U\or V\or W\or
+ X\or Y\or Z\else?\fi
+}
+\skvnewdef*\skv@lcalpha#1{%
+ \ifcase#1\or a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or
+ k\or l\or m\or n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or
+ x\or y\or z\else?\fi
+}
+\skvnewdef*\skv@alphamap{%
+ {A}{a}{1}{B}{b}{2}{C}{c}{3}{D}{d}{4}{E}{e}{5}{F}{f}{6}{G}{g}{7}{H}{h}{8}%
+ {I}{i}{9}{J}{j}{10}{K}{k}{11}{L}{l}{12}{M}{m}{13}{N}{n}{14}{O}{o}{15}%
+ {P}{p}{16}{Q}{q}{17}{R}{r}{18}{S}{s}{19}{T}{t}{20}{U}{u}{21}{V}{v}{22}%
+ {W}{w}{23}{X}{x}{24}{Y}{y}{25}{Z}{z}{26}%
+}
+\skvrobustdef*\skv@reverselumap#1{%
+ \def\skv@prova##1##2##3##4\skv@nil{%
+ \ifx\@nnil##1%
+ \expandafter\@gobble
+ \else
+ \expandafter\@iden
+ \fi
+ {\skv@prova##4\skv@nil{##1}{##2}{##3}}%
+ }%
+ \edef#1{\expandafter\skv@prova\skv@alphamap\@nnil{}{}\skv@nil}
+}
+
+
+\skvquickkeys.define{skeyval/autocomplete}{%
+ .exec/\def\skv@autocomplete@parser{,};
+ parser/{,}/
+ \edef\skv@autocomplete@parser{\unexpanded{#1}}
+ \skvstripouterbraces{2}\skv@autocomplete@parser
+ \skvxifntypeTF{\detokenize{#1}}{%
+ \begingroup
+ % It is assumed that every n-type parser and subparser
+ % must have catcode 12:
+ \skvexpandnext{\catcode`}\skv@autocomplete@parser=12\relax
+ \skvrescan\skv@autocomplete@parser
+ \skvaftergroupdef\skv@autocomplete@parser\endgroup
+ }{}
+ ;
+ % This default value of 'link' is required by \skvautocompletelist:
+ .exec code/\def\skv@autocomplete@link{\@nil};
+ link/\@nil/
+ \edef\skv@prova{\unexpanded{#1}}%
+ \ifcase0%
+ \ifx\skv@prova\@empty 1\fi
+ \ifx\skv@prova\@nnil 1\fi\relax
+ \edef\skv@autocomplete@link{\unexpanded{#1}}%
+ \skvstripouterbraces{2}\skv@autocomplete@link
+ \fi
+ ;
+ grow/\@nil/
+ \edef\skv@prova{\unexpanded{#1}}%
+ \ifx\skv@prova\@nnil\else
+ \skvcsedef{skv@autocomplete@grow#1}{00}
+ \edef\skv@prova{\skvifstrcmpTF{#1}{left}{right}{left}}%
+ \skvcsedef{skv@autocomplete@grow\skv@prova}{01}%
+ \fi
+ /left,right
+ ;
+ .exec/
+ \def\skv@autocomplete@growleft{01}
+ \def\skv@autocomplete@growright{01}
+ ;
+ grow left/true/
+ \edef\skv@autocomplete@growleft{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ grow right/true/
+ \edef\skv@autocomplete@growright{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ % Keep the decimals in rounded numbers or dimensions when list is
+ % auto-completed. The value value of this key is 'true'.
+ keep decimals/true/
+ \edef\skv@autocomplete@keepdecimals{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ keep high decimals,keep only high decimals/true/
+ \edef\skv@autocomplete@keephighdecimals{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+ expand before fill,expand list before fill/true/
+ \edef\skv@autocomplete@expandbeforefill{0\skvifstrcmpTF{true}{#1}01}
+ /true,false
+ ;
+}
+
+% The keys 'link,grow' don't need presetting. The user must supply
+% values when they are called. In internal loops, their values will
+% have to be revised from those of the outer loop.
+%
+\skvquickkeys.preset{skeyval/autocomplete}{%
+ parser,grow left=false,grow right=false,
+ keep decimals=true,keep high decimals=false,
+ expand before fill=false
+}
+
+% \skv@autocomplete@addtolist<parser><add.new><listcmd>
+\skvrobustdef*\skv@autocomplete@addtolist#1#2#3{%
+ \edef#3{\skvexpandonce#3\ifx#3\@empty\else\unexpanded{#1}\fi#2}%
+}
+% \skv@autocomplete@zerostepwarn{<lower>}{<upper>}{<pt.or.nil>}
+\skvrobustdef*\skv@autocomplete@zerostepwarn#1#2#3{%
+ \skv@warn{The tokens '\detokenize{#1}', '\detokenize{#2}'
+ give nil step; '1#3' used.\MessageBreak
+ Maybe you used the font-dependent units\MessageBreak
+ 'ex' or 'em' \ifskv@latex before \skv@begindoctoks\fi}%
+}
+% \skvautocompletelist[<kvlist>]{<list>}{<returncmd>}
+% \skvautocompletelist*[<kvlist>]{<listcmd>}{<returncmd>}
+%
+% 1. Parse list of type {1,2,...,n,1,...,m} for auto completion.
+% Return outcome in <listcmd> or \skvcompletedlist.
+%
+\skvrobustdef*\skvautocompletelist{\skv@teststopt\skv@autocompletelist@a{}}
+\skvrobustdef*\skv@autocompletelist@a[#1]#2#3{%
+ \skv@usetempst{#2}\skv@autocomplete@userlist
+ \skvquickkeys.set{skeyval/autocomplete}{#1}%
+ \def\skv@inalphabetic{01}%
+ \def\skv@isupperalpha{01}%
+ \def\skv@preandpostdotspresent{01}%
+ % If the list is alphabetic or numbers, original unit is nil:
+ \def\skv@autocomplete@origunit{}%
+ \def\skvcompletedlist{}%
+ \skvexpandtwoargsonce
+ \skv@autocompletelist@b\skv@autocomplete@parser\skv@autocomplete@userlist
+ \let#3\skvcompletedlist
+}
+% \skv@autocompletelist@b{<parser>}{<list>}
+\skvrobustdef*\skv@autocompletelist@b#1#2{%
+ \edef\skv@tempa{\unexpanded{#2}}%
+ \skv@foreach@normalize[#1]\skv@tempa
+ \def\skv@prova##1{%
+ \skvxifinTF{...}{\detokenize{##1}}{%
+ \if\skv@autocomplete@expandbeforefill
+ \edef\skv@tempa{##1}%
+ \skv@foreach@normalize[#1]\skv@tempa
+ \else
+ \edef\skv@tempa{\unexpanded{##1}}%
+ \fi
+ \skvexpandargonce{\skv@autocompletelist@c{#1}}\skv@tempa
+ \skv@foreach@normalize[#1]\skvcompletedlist
+ }{%
+ \edef\skvcompletedlist{%
+ \skvaddlist{#1}\skvcompletedlist\skvtrimspace{##1}%
+ }%
+ }%
+ }%
+ \expandafter\skv@prova\expandafter{\skv@tempa}%
+}
+% \skv@autocompletelist@c{<parser>}{<list>}
+\skvrobustdef*\skv@autocompletelist@c#1#2{%
+ \skvxiffound{\relax...}\in{\relax\detokenize{#2}}\then
+ \skv@err{I can't find lower limit before '...'}\skv@ehd
+ \else
+ \skvxiffound{\relax\detokenize{#1}...}\in{\relax\detokenize{#2}}\then
+ \skv@err{I can't find lower limit before '...'}\skv@ehd
+ \fi
+ \fi
+ % \newforeach format is '<parser>...<parser>':
+ \skvxifinTF{\detokenize{#1...#1}}{\detokenize{#2}}{%
+ \skv@autocomplete@splitbeforedots{#1}{#2}%
+ \def\skv@prova##1#1##2#1...#1##3#1##4#1##5\skv@nil{%
+ \skvifblankTF{##3}{%
+ \skv@err{I can't find upper limit number or dimension,
+ \MessageBreak i.e., after symbool '...'}\skv@ehd
+ }{%
+ % \skv@autocompletelist@b may be reentered. Hence accumulate
+ % filled list:
+ \skviflacus{##1}\then\else
+ \edef\skvcompletedlist{%
+ \skvaddlist{#1}\skvcompletedlist\unexpanded{##1}%
+ }%
+ \fi
+ % Complete the list:
+ \skv@autocompletelist@d{#1}{##1}{##2}{##3}%
+ % In case the list is folded on ellipsis (...):
+ \skvifblankTF{##4}{}{\skv@autocompletelist@b{#1}{##4#1##5}}%
+ }%
+ }%
+ \expandafter\skv@prova\skv@tempa#1#1\skv@nil
+ }{%
+ \skv@autocompletelist@e{#1}{#2}%
+ }%
+}
+% skv@autocompletelist@d{<parser>}{<lower1>}{<lower2>}{<upperbound>}
+%
+% 1. No <guide> here.
+%
+\skvrobustdef*\skv@autocompletelist@d#1#2#3#4{%
+ \skvifxTF\skv@autocomplete@link\@nnil{%
+ % No <link> has been given. The list has '...' but presumably no link.
+ %
+ % \skv@autocompletelist@h{<parser>}{<guide>}{<lower1>}{<lower2>}{<upper>}
+ \skv@autocompletelist@h{#1}{}{#2}{#3}{#4}%
+ }{%
+ % <link> has been given by the user:
+ \skv@autocomplete@splitandgrow{#1}{#2}{#3}{#4}%
+ }%
+}
+%
+% \skv@autocompletelist@e{<parser>}{<list>}
+%
+% \skv@autocompletelist@e will auto-complete this list without
+% knowledge of the values of the keys 'link' and 'grow'. The syntax at (*)
+% above isn't recognized by the auto-completion scheme of skeyval.
+%
+% skeyval formats:
+%
+% {1pt,4pt,...pt,10pt} : no additional info. required
+% {A_2pt,A_4pt,A_...,A_10pt} : no additional info. required
+% {\pi0,\pi0.5,\pi...,\pi3} : no additional info. required
+% {0\pi,0.5\pi,...\pi,3\pi} : no additional info. required
+% {1pt,4pt,...,10pt} : link = pt, grow=left, or no addit. info.
+% {A_2pt,A_4pt,...,A_10pt} : link =_, grow=right
+%
+% The general PGF format with left and right guides (given as 'A_'
+% and 'pt') in
+%
+% {A_2pt,A_4pt,A_...pt,A_10pt}
+%
+% is still legal in skeyval.
+%
+\skvrobustdef*\skv@autocompletelist@e#1#2{%
+ \skv@autocomplete@splitbeforedots{#1}{#2}%
+ \def\skv@checkguideinbounds##1##2{%
+ \skv@foreach@swafalse
+ \def\do####1{%
+ \ifx\do####1\else
+ \skviflacus####1\then\else
+ \skvifinTF{##1}{####1}{}\skv@foreach@swatrue
+ \fi
+ \expandafter\do
+ \fi
+ }%
+ \do##2\do
+ \ifskv@foreach@swa
+ \skv@err{Guide token '\detokenize{#1}' not found in some
+ \MessageBreak of the elements: I can't complete
+ \MessageBreak the current list. This may be
+ \MessageBreak due to wrong direction of growth}\skv@ehd
+ \fi
+ }%
+ \def\skv@prova##1#1##2#1##3...##4#1##5#1##6#1##7\skv@nil{%
+ \skvifblankTF{##5}{%
+ \skv@err{I can't find upper limit number or dimension,
+ \MessageBreak i.e., after symbool '...'}\skv@ehd
+ }{%
+ % \skv@autocompletelist@b may be reentered. Hence
+ \skviflacus{##1}\then\else
+ \edef\skvcompletedlist{%
+ \skvaddlist{#1}\skvcompletedlist
+ \skvtrimspace{##1}%
+ }%
+ \fi
+ \let\do\unexpanded
+ \skvifblankTF{##3}{%
+ \skvifblankTF{##4}{%
+ \skv@err{No direction of growth before and/or after
+ \MessageBreak symbol '...'}\skv@ehd
+ }{%
+ % Eg, {2pt_A,4pt_A,...pt_A,10pt_A}. Here ##3 is nil, grow left.
+ \def\skv@autocomplete@growleft{00}%
+ \def\skv@autocomplete@growright{01}%
+ \skvexpanded{%
+ \skv@autocompletelist@f
+ {\do{#1}}{\do{##4}}{\do{##1}}{\do{##2}}{\do{##5}}%
+ }%
+ }%
+ }{%
+ \skvifblankTF{##4}{%
+ % Eg, {A_2pt,A_4pt,A_...,A_10pt}. Here ##4 is nil, grow right.
+ \def\skv@autocomplete@growright{00}%
+ \def\skv@autocomplete@growleft{01}%
+ \skvexpanded{%
+ \skv@autocompletelist@f
+ {\do{#1}}{\do{##3}}{\do{##1}}{\do{##2}}{\do{##5}}%
+ }%
+ }{%
+ % Eg, {A_2pt,A_4pt,A_...pt,A_10pt}.
+ \skvexpanded{%
+ \skv@autocompletelist@g
+ {\do{#1}}{\do{##3}}{\do{##4}}{\do{##1}}{\do{##2}}{\do{##5}}%
+ }%
+ }%
+ }%
+ % In case the list is folded on ellipsis (...):
+ \skvifblankTF{##6}{}{\skv@autocompletelist@b{#1}{##6#1##7}}%
+ }%
+ }%
+ \expandafter\skv@prova\skv@tempa#1#1#1\skv@nil
+}
+% \skv@autocompletelist@f
+% {<parser>}{<guide>}{<lower1>}{<lower2>}{<upper>}
+%
+% 1. Use the <guide> to get the constant and variable parts of the
+% elements.
+% 2. Use the variable parts to determine if the list is Alpah, alpha or
+% number type. In this format, the unit in dimension type of list may
+% appear in <guide>.
+% 3. Use the variable parts to work out the <step>.
+% 4. Call the relevant macro to fill the list.
+% 5. <lower1> has already been saved in \skvcompletedlist.
+%
+\skvrobustdef*\skv@autocompletelist@f#1#2#3#4#5{%
+ \skv@checkguideinbounds{#2}{{#3}{#4}{#5}}%
+ % Use the 'link' (#2) to get from {<lower1>}, {<lower2>} and {<upper>}
+ % the left or right sides of the elements that should be grown:
+ \def\skv@prova##1#2##2\skv@nil##3{%
+ \edef##3{\if\skv@autocomplete@growleft##1\else##2\fi}%
+ }%
+ % <lower1> is empty when there is only one element before ellipsis:
+ \skviflacus#3\then
+ \def\skv@tempa{}%
+ \else
+ \skv@prova#3\skv@nil\skv@tempa
+ \fi
+ \skv@prova#4\skv@nil\skv@tempb
+ \skv@prova#5\skv@nil\skv@tempc
+ \let\do\skvexpandonce
+ \skvexpandsecond
+ {\skv@autocompletelist@h{#1}{#2}}%
+ {{\do\skv@tempa}{\do\skv@tempb}{\do\skv@tempc}}%
+}
+% \skv@autocompletelist@g
+% {<parser>}{<predots>}{<postdots>}{<lower1>}{<lower2>}{<upper>}
+\skvrobustdef*\skv@autocompletelist@g#1#2#3#4#5#6{%
+ \def\skv@preandpostdotspresent{00}%
+ \skv@checkguideinbounds{#2}{{#4}{#5}{#6}}%
+ \skv@checkguideinbounds{#3}{{#4}{#5}{#6}}%
+ % For <lower1>, <lower2> and <upper>, get the tokens between
+ % <predots> and <postdots>. They are the ones to be grown.
+ \def\skv@prova##1#2##2#3##3\skv@nil##4{%
+ \edef##4{##2}%
+ }%
+ \ifx\@nnil#4\@nnil
+ \let\skv@tempa\@empty
+ \else
+ \skv@prova#4\skv@nil\skv@tempa
+ \fi
+ \skv@prova#5\skv@nil\skv@tempb
+ \skv@prova#6\skv@nil\skv@tempc
+ % Pass <guide> as empty to \skv@autocompletelist@h. Through out, the only
+ % reason for passing <guide> to \skv@autocompletelist@h is to restore
+ % it in \skv@autocomplete@restore. But while
+ % \skv@preandpostdotspresent is true, we won't do anything in
+ % \skv@autocomplete@restore.
+ \skvexpandsecond
+ {\skv@autocompletelist@h{#1}{}}%
+ {{\skv@tempa}{\skv@tempb}{\skv@tempc}}%
+ % Restore <predots> and <postdots>:
+ \def\do##1#1{%
+ \ifx\do##1\else
+ \edef\skvcompletedlist{%
+ \skvaddlist{#1}\skvcompletedlist
+ \unexpanded{#2}##1\unexpanded{#3}\skv@autocomplete@origunit
+ }%
+ \expandafter\do
+ \fi
+ }%
+ \expandafter\do\skv@completedlist@partial#1\do#1%
+}
+% \skv@autocompletelist@h{<parser>}{<guide>}{<lower1>}{<lower2>}{<upper>}
+%
+% 1. Use the variable parts to determine if the list is Alpah, alpha or
+% number type. In this format, the unit in dimension type of list may
+% appear in <guide>.
+% 2. Use the variable parts to work out the <step>.
+% 3. Call the relevant macro to fill the list.
+% 4. <lower1> has already been saved in \skvcompletedlist.
+%
+\skvrobustdef*\skv@autocompletelist@h#1#2#3#4#5{%
+ \def\skv@completedlist@partial{}%
+ \edef\skv@lowerlower{\ifx\@nnil#3\@nnil\else\unexpanded{#3}, \fi}%
+ \skvifloweralpha{#4}{%
+ \skv@foreach@swatrue
+ \ifx\@nnil#3\@nnil\else
+ \skvifloweralpha{#3}{}\skv@foreach@swafalse
+ \fi
+ \skvifloweralpha{#5}{}\skv@foreach@swafalse
+ \ifskv@foreach@swa
+ \ifx\@nnil#3\@nnil
+ \def\skv@autocomplete@step{1}%
+ \else
+ \edef\skv@autocomplete@step{\the\numexpr\lccode`#4-\lccode`#3}%
+ \ifnum\skv@autocomplete@step=\skvz@
+ \def\skv@autocomplete@step{1}%
+ \skv@autocomplete@zerostepwarn{#3}{#4}{}%
+ \fi
+ \fi
+ \def\skv@isupperalpha{01}%
+ % \skv@autocomplete@origunit remains nil on this branch.
+ \skv@autocomplete@fillalphabetic{#1}{#4}{#5}\skv@completedlist@partial
+ % Also update the items already entered in \skvcompletedlist.
+ \skv@autocomplete@restore{#1}{#2}\skv@completedlist@partial
+ \else
+ \skv@err{The tokens '\detokenize\expandafter{\skv@lowerlower#4, #5}'
+ \MessageBreak aren't of the same type}\skv@ehd
+ \fi
+ }{%
+ \skvifupperalpha{#4}{%
+ \skv@foreach@swatrue
+ \ifx\@nnil#3\@nnil\else
+ \skvifupperalpha{#3}{}\skv@foreach@swafalse
+ \fi
+ \skvifupperalpha{#5}{}\skv@foreach@swafalse
+ \ifskv@foreach@swa
+ \ifx\@nnil#3\@nnil
+ \def\skv@autocomplete@step{1}%
+ \else
+ \edef\skv@autocomplete@step{\the\numexpr\uccode`#4-\uccode`#3}%
+ \ifnum\skv@autocomplete@step=\skvz@
+ \def\skv@autocomplete@step{1}%
+ \skv@autocomplete@zerostepwarn{#3}{#4}{}%
+ \fi
+ \fi
+ \def\skv@isupperalpha{00}%
+ % \skv@autocomplete@origunit remains nil on this branch.
+ \skv@autocomplete@fillalphabetic{#1}{#4}{#5}\skv@completedlist@partial
+ \skv@autocomplete@restore{#1}{#2}\skv@completedlist@partial
+ \else
+ \skv@err{The tokens '\detokenize\expandafter{\skv@lowerlower#4, #5}'
+ \MessageBreak aren't of the same type}\skv@ehd
+ \fi
+ }{%
+ \skv@foreach@swatrue
+ \ifx\@nnil#3\@nnil\else
+ \skvifdimensionable{#3}{}\skv@foreach@swafalse
+ \fi
+ \skvifdimensionable{#4}{}\skv@foreach@swafalse
+ \let\skv@autocomplete@origunit\skv@dimunit
+ \skvifdimensionable{#5}{}\skv@foreach@swafalse
+ \ifx\skv@autocomplete@origunit\skv@dimunit\else
+ \skv@err{The units on \detokenize{'#4', '#5'} are different}\skv@ehd
+ \fi
+ \ifskv@foreach@swa
+ \ifx\@nnil#3\@nnil
+ \def\skv@autocomplete@step{1pt}%
+ \else
+ \edef\skv@autocomplete@step{\the\dimexpr#4-#3\relax}%
+ \ifdim\skv@autocomplete@step=\skvz@
+ \def\skv@autocomplete@step{1pt}%
+ \skv@autocomplete@zerostepwarn{#3}{#4}{pt}%
+ \fi
+ \fi
+ \skvexpandsecond
+ {\skv@autocomplete@fillnumordim{#1}}{{#4}{#5}}%
+ \skv@completedlist@partial
+ \skv@autocomplete@strippoint{#1}\skv@completedlist@partial
+ % Attach the constant part to the elements of the completed list.
+ % <lower1> was saved earlier in \skv@autocompletelist@e, and
+ % <lower2> and <upper> have been saved while filling the list.
+ % Always strip point and restore original unit here.
+ \skv@autocomplete@restore{#1}{#2}\skv@completedlist@partial
+ \else
+ \skv@foreach@swatrue
+ \ifx\@nnil#3\@nnil\else
+ \skvifdimensionable{#3pt}{}\skv@foreach@swafalse
+ \fi
+ \skvifdimensionable{#4pt}{}\skv@foreach@swafalse
+ \skvifdimensionable{#5pt}{}\skv@foreach@swafalse
+ \ifskv@foreach@swa
+ \ifx\@nnil#3\@nnil
+ \def\skv@autocomplete@step{1pt}%
+ \else
+ \edef\skv@autocomplete@step{\the\dimexpr#4pt-#3pt\relax}%
+ \ifdim\skv@autocomplete@step=\skvz@
+ \def\skv@autocomplete@step{1pt}%
+ \skv@autocomplete@zerostepwarn{#3}{#4}{pt}%
+ \fi
+ \fi
+ % \skv@autocomplete@origunit remains nil on this branch.
+ \skvexpandsecondonce
+ {\skv@autocomplete@fillnumordim{#1}}{{#4pt}{#5pt}}%
+ \skv@completedlist@partial
+ \skv@autocomplete@strippoint{#1}\skv@completedlist@partial
+ \skv@autocomplete@restore{#1}{#2}\skv@completedlist@partial
+ \else
+ \skv@err{Sorry, the tokens
+ '\detokenize\expandafter{\skv@lowerlower#4, #5}'
+ \MessageBreak are unparsable. I have given up on them.
+ \MessageBreak Did you miss something syntactic?
+ \MessageBreak See manual for acceptable syntaxes}\skv@ehd
+ \fi
+ \fi
+ }%
+ }%
+}
+% \skv@autocomplete@fillnumordim<parser><lower><upper><listcmd>
+\skvrobustdef*\skv@autocomplete@fillnumordim#1#2#3#4{%
+ \begingroup
+ \skv@autocomplete@getcomparator
+ \if\skv@autocomplete@stepisneg
+ \ifdim#3\skv@autocomplete@unit>#2\skv@autocomplete@unit\relax
+ \skv@err{Step '\skv@autocomplete@step' is negative but upperbound
+ \MessageBreak '\detokenize{#3}' is greater than lowerbound
+ '\detokenize{#2}'}\skv@ehd
+ \fi
+ \else
+ \ifdim#3\skv@autocomplete@unit<#2\skv@autocomplete@unit\relax
+ \skv@err{Step '\skv@autocomplete@step' is nonnegative but upperbound
+ \MessageBreak '\detokenize{#3}' is less than lowerbound
+ '\detokenize{#2}'}\skv@ehd
+ \fi
+ \fi
+ % The bounds may have decimal places. So the calculation has to be
+ % done with \dimexpr:
+ \edef\skv@upperlimit{\the\dimexpr#3\skv@autocomplete@unit}%
+ \edef\skv@lowerlimit{\the\dimexpr#2\skv@autocomplete@unit}%
+ \skv@autocomplete@addtolist{#1}\skv@lowerlimit#4%
+ \ifdim\skv@lowerlimit\skv@comparator\skv@upperlimit\relax
+ \def\do{%
+ \edef\skv@lowerlimit{%
+ \the\dimexpr\skv@lowerlimit
+ +\skv@autocomplete@step\skv@autocomplete@unit\relax
+ }%
+ \ifdim\skv@lowerlimit\skv@comparator\skv@upperlimit\relax
+ \skv@autocomplete@addtolist{#1}\skv@lowerlimit#4%
+ \expandafter\do
+ \fi
+ }%
+ \do
+ % The last item has to in 'pt', so that 'pt' can be stripped.
+ % Hence \dimexpr.
+ \skv@autocomplete@addtolist{#1}\skv@upperlimit#4%
+ \fi
+ \skvaftergroupdef#4\endgroup
+}
+% Fill Alpha or alpha.
+% \skv@autocomplete@fillalphabetic<parser><lower><upper><listcmd>
+\skvrobustdef*\skv@autocomplete@fillalphabetic#1#2#3#4{%
+ \begingroup
+ \def\skv@inalphabetic{00}%
+ \skv@autocomplete@getcomparator
+ \edef\skv@type{%
+ \if\skv@isupperalpha Upper\else Lower\fi case alphabetic%
+ }%
+ \edef\reserved@a{\if-\skv@autocomplete@step\else\skv@autocomplete@step\fi}%
+ \skvoifinteger\reserved@a{}{%
+ \skv@err{List is '\skv@type' type but\MessageBreak
+ step '\skv@autocomplete@step' isn't an integer}\skv@ehd
+ }%
+ \skv@autocomplete@addtolist{#1}{#2}#4%
+ \skvifstrcmpTF{#2}{#3}{}{%
+ \edef\skv@lowerlimit{#2}%
+ \edef\skv@upperlimit{#3}%
+ \skvexpandnext{\chardef\skv@lowerlimit`}\skv@lowerlimit\relax
+ \skvexpandnext{\chardef\skv@upperlimit`}\skv@upperlimit\relax
+ \edef\skv@lowerlimit{%
+ \the\numexpr\skv@lowerlimit-\if\skv@isupperalpha 64\else 96\fi
+ }%
+ \edef\skv@upperlimit{%
+ \the\numexpr\skv@upperlimit-\if\skv@isupperalpha 64\else 96\fi
+ }%
+ \edef\skv@charcase{\the\numexpr\skv@lowerlimit+\skv@autocomplete@step}%
+ \skvrecurse
+ \if\skv@isupperalpha
+ \edef\skv@tempa{\skv@ucalpha\skv@charcase}%
+ \else
+ \edef\skv@tempa{\skv@lcalpha\skv@charcase}%
+ \fi
+ \skv@autocomplete@addtolist{#1}\skv@tempa#4%
+ \edef\skv@charcase{\the\numexpr\skv@charcase+\skv@autocomplete@step}%
+ \while
+ \ifnum\skv@charcase\skv@comparator\skv@upperlimit\relax
+ \fi
+ \skv@autocomplete@addtolist{#1}{#3}#4%
+ }%
+ \skvaftergroupdef#4\endgroup
+}
+%
+% \skv@autocomplete@splitbeforedots{<parser>}{<list>}
+%
+% Get the one or two elements before '...' or before '<guide>,...'.
+%
+% {A_2pt,A_4pt,A_...pt,A_10pt} : no additional info. required
+% {a^1,a^3,a^...,a^9} : no additional info. required
+% {A_1,B_1,..._1,E_1} : no additional info. required
+% {1--,4--,...--,16--} : no additional info. required
+% {1pt,4pt,...pt,10pt} : no additional info. required
+% {A_2pt,A_4pt,A_...,A_10pt} : no additional info. required
+%
+% {a^1,a^3,...,a^9} : link = ^, grow = right
+% {A_1,B_1,...,E_1} : link = _, grow = left
+% {1--,4--,...,16--} : link = --, grow = left
+% {1pt,4pt,...,10pt} : link = pt, grow = left, or no addit. info.
+% {A_2pt,A_4pt,...,A_10pt} : link = _, grow = right
+%
+% The items prior to the two before '<guide>...' or before '...'
+% are called 'all-before-the-two' (AB2). Collect in \skv@tempa the two
+% items before '<guide>...' or before '...' together with the rest of the
+% list. Save the AB2 items in \skvcompletedlist.
+%
+% Return \skvcompletedlist and \skv@tempa.
+%
+\skvrobustdef*\skv@autocomplete@splitbeforedots#1#2{%
+ % First count all the elements before '<guide><parser>...' or '...'.
+ % We're already sure that argument #2 contains '<guide><parser>...'
+ % or '...'. \skvcompletedlist has been initialized before here.
+ \begingroup
+ \skv@cnta\skvz@
+ \def\do##1#1{%
+ \skvifinTF{...}{##1}{%
+ % Gobble the rest:
+ \def\do####1\skv@nil{}%
+ }{%
+ \advance\skv@cnta\@ne
+ }%
+ \do
+ }%
+ \do#2#1\skv@nil
+ \ifnum\skv@cnta>\tw@
+ \@tempcnta\m@ne
+ \def\do##1#1{%
+ \advance\@tempcnta\@ne
+ \ifnum\@tempcnta=\numexpr\skv@cnta-\tw@\relax
+ \def\do####1\skv@nil{\def\skv@tempa{##1#1####1}}%
+ \else
+ \edef\skvcompletedlist{%
+ \skvaddlist{#1}\skvcompletedlist\unexpanded{##1}%
+ }%
+ \fi
+ \do
+ }%
+ \do#2#1\skv@nil
+ \else
+ \ifnum\skv@cnta=\@ne
+ % There is only one element before '<guide><parser>...' or '...'.
+ % Hence simply left-pad argument #2 with <parser> to give the
+ % impression of at least 2 elements:
+ \def\skv@tempa{#1#2}%
+ \else
+ \ifnum\skv@cnta=\tw@
+ \def\skv@tempa{#2}%
+ \else
+ \ifnum\skv@cnta=\skvz@
+ \skv@err{List <<\detokenize{#2}>>\MessageBreak
+ contains symbol '...' but not a lowerbound}\skv@ehd
+ \fi
+ \fi
+ \fi
+ \fi
+ \skvexpanded{\endgroup
+ \skvcmdexit\skvcompletedlist\skvcmdexit\skv@tempa
+ }%
+}
+% \skv@autocomplete@splitandgrow{<parser>}{<lower1>}{<lower2>}{<upperbound>}
+%
+% {0\pi,0.5\pi,...,3\pi} : link = \pi ; grow left
+% {1--,4--,...,10--} : link = -- ; grow left
+% {2pt,4pt,...,10pt} : link = pt ; grow left (or no additional info.)
+% {A_1,C_1,...,Q_1} : link = _ ; grow left
+% {2^a,2^c,...,2^q} : link = ^ ; grow right
+%
+% 1. Providing the link avoids the need to use the syntax of PGF's
+% \foreach, such as {0\pi,0.5\pi,...\pi,3\pi}. But skeyval can also
+% autocomplete lists like {0\pi,0.5\pi,...\pi,3\pi}.
+% 2. We already know that the key 'link' will reject empty values.
+%
+\skvrobustdef*\skv@autocomplete@splitandgrow#1#2#3#4{%
+ \ifx\skv@autocomplete@growleft\skv@autocomplete@growright
+ \skv@err{I can't grow the list in both directions.
+ \MessageBreak Maybe you haven't indicated the
+ \MessageBreak direction of growth (left or right),
+ \MessageBreak or both directions are 'true'.}
+ {Try one of the keys 'grow=left or right',
+ \MessageBreak 'grow left=true or false',
+ 'grow right=true or false'}\skv@ehd
+ \fi
+ \begingroup
+ \def\skv@prova##1{%
+ \skv@foreach@swatrue
+ \skviflacus#2\then\else
+ \skvifinTF{##1}{#2}{}\skv@foreach@swafalse
+ \fi
+ \skvifinTF{##1}{#3}{}\skv@foreach@swafalse
+ \skvifinTF{##1}{#4}{}\skv@foreach@swafalse
+ \ifskv@foreach@swa\else
+ \edef\skv@provb{\ifx\@nnil#2\@nnil\else\unexpanded{#2}, \fi}%
+ \skv@err{No link '##1' in one of
+ '\detokenize\expandafter{\skv@provb#3, #4}'}\skv@ehd
+ \fi
+ \def\skv@prova####1##1####2\skv@nil{%
+ \if\skv@autocomplete@growright
+ \edef\skv@prova{\skvtrimspace{####1##1}}%
+ \else
+ \edef\skv@prova{\skvtrimspace{##1####2}}%
+ \fi
+ \def\do########1{{\skvtrimspace{########1}}}%
+ % \skv@autocompletelist@f<parser><guide><lower1><lower2><upper>
+ \skvexpanded{\endgroup
+ \noexpand\skv@autocompletelist@f
+ {\unexpanded{#1}}{\skvexpandonce\skv@prova}\do{#2}\do{#3}\do{#4}%
+ }%
+ }%
+ \skv@prova#3\skv@nil
+ }%
+ \expandafter\skv@prova\expandafter{\skv@autocomplete@link}%
+}
+\skvrobustdef*\skv@autocomplete@getcomparator{%
+ \begingroup
+ % <unit> isn't required in alphabetic sequences:
+ \if\skv@inalphabetic\else
+ \let\skvreversedo\@iden
+ \edef\skv@provb{\skvexpbracenext\skvreverse\skv@autocomplete@step}%
+ \def\skv@prova##1##2##3\skv@nil{%
+ \skvxifinTF{,\detokenize{##2##1},}{,\skvoxdetok\skv@validunit,}{%
+ % That is, the sequence is made up of dimensions.
+ \def\skv@autocomplete@unit{}%
+ }{%
+ \def\skv@autocomplete@unit{pt}%
+ }%
+ }%
+ \expandafter\skv@prova\skv@provb\skv@nil
+ \fi
+ % You can't use \ifnum or \ifdim here, since for alphanumeric sequences
+ % \skv@autocomplete@step isn't a dimension.
+ \def\skv@prova##1##2\skv@nil{%
+ \edef\skv@autocomplete@stepisneg{0\if-##10\else1\fi}%
+ }%
+ \expandafter\skv@prova\skv@autocomplete@step\skv@nil
+ \edef\skv@comparator{\if\skv@autocomplete@stepisneg>\else<\fi}%
+ \let\do\skvcmdexit
+ \skvexpanded{\endgroup
+ \do\skv@autocomplete@stepisneg\do\skv@comparator
+ \if\skv@inalphabetic\else\do\skv@autocomplete@unit\fi
+ }%
+}
+\begingroup
+\catcode`P=12 \lccode`P=112
+\catcode`T=12 \lccode`T=116
+\lowercase{\endgroup
+ \def\skv@autocomplete@strippoint#1#2{%
+ \def\reserved@a##1#1\relax{\def#2{##1}}%
+ \def\do##1.##2PT#1{%
+ \ifx\do##1\else##1%
+ \if\skv@autocomplete@keephighdecimals
+ \ifdim.##2pt>.5pt\relax##2\fi
+ \else
+ \if\skv@autocomplete@keepdecimals
+ \ifnum##2>\skvz@.##2\fi
+ \fi
+ \fi
+ \unexpanded{#1}%
+ \expandafter\do
+ \fi
+ }%
+ \edef#2{\expandafter\do#2#1\do.PT#1}%
+ \expandafter\reserved@a#2\relax
+ }
+}
+% \skv@autocomplete@restore{<parser>}{<guide>}{<listcmd>}
+%
+% Restore guide and, in the case of dimension sequences, 'original unit'.
+%
+\skvrobustdef*\skv@autocomplete@restore#1#2#3{%
+ \if\skv@preandpostdotspresent
+ % Leave it: <predots> and <postdots> will be restored in
+ % \skv@autocompletelist@g.
+ \else
+ \def\do##1#1{%
+ \ifx\do##1\else
+ \edef\skvcompletedlist{%
+ \skvaddlist{#1}\skvcompletedlist
+ \if\skv@autocomplete@growleft
+ ##1\skv@autocomplete@origunit\unexpanded{#2}%
+ \else
+ \unexpanded{#2}##1\skv@autocomplete@origunit
+ \fi
+ }%
+ \expandafter\do
+ \fi
+ }%
+ \expandafter\do#3#1\do#1%
+ \fi
+}
+
+
+\skv@for@restorecatcodes
+\endinput
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-ltxcmds.tex b/macros/latex/contrib/skeyval/tex/skeyval-ltxcmds.tex
new file mode 100644
index 0000000000..30accb688a
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-ltxcmds.tex
@@ -0,0 +1,316 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-ltxcmds.tex', version 1.3, 2013/05/15. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup%
+\let\e\endlinechar\edef\p{\the\e}\e13\edef\n{\the\catcode\e}%
+\xdef\skv@ltxcmds@restorecatcodes{%
+ \let\noexpand\skv@ltxcmds@restorecatcodes\relax%
+ \endlinechar=\p\relax\catcode\number\e=\n\relax%
+ \catcode\string`\noexpand`\string=\the\catcode\string``\relax%
+ \catcode\string`\noexpand=\string=\the\catcode\string`=\relax%
+}%
+\endgroup%
+\endlinechar\string=13\relax%
+\catcode13\string=5\relax%
+\catcode\string``\string=12\relax
+\catcode\string`=\string=12\relax
+\long\def\skvgobble#1{}
+\def\do#1{\catcode`\expandafter\skvgobble\string#1=\the\catcode`#1\relax}
+\edef\skv@ltxcmds@restorecatcodes{%
+ \unexpanded\expandafter{\skv@ltxcmds@restorecatcodes}%
+ \do\ \do\%\do\@\do\(\do\)\do\[\do\]\do\|\do\:\do\;\do\,\do\.%
+ \do\>\do\<\do\!\do\*\do\+\do\-\do\^\do\_\do\&\do\$\do\~\do\'%
+ \do\"\do\
+}
+\catcode`\ =10\relax
+\catcode`\@=11 \catcode`\(=12 \catcode`\)=12 \catcode`\[=12
+\catcode`\]=12 \catcode`\|=12 \catcode`\:=12 \catcode`\;=12
+\catcode`\,=12 \catcode`\*=12 \catcode`\+=12 \catcode`\-=12
+\catcode`\<=12 \catcode`\>=12 \catcode`\!=12 \catcode`\.=12
+\catcode`\^=07 \catcode`\_=08 \catcode`\&=04 \catcode`\$=03
+\catcode`\~=13 \catcode`\%=14 \catcode`\'=12 \catcode`\"=12
+
+\csname skeyval-ltxcmds-loaded\endcsname
+\expandafter\let\csname skeyval-ltxcmds-loaded\endcsname\endinput
+
+\message{skeyval-ltxcmds 2013/05/15 v1.3 LaTeX header for skeyval (AM)}
+
+\countdef\m@ne=22 \m@ne=-1
+\def\wlog{\immediate\write\m@ne}
+\countdef\count@=255
+\dimendef\dimen@=0
+\dimendef\dimen@i=1
+\dimendef\dimen@ii=2
+\skipdef\skip@=0
+\toksdef\toks@=0
+\newif\if@tempswa
+\newcount\@tempcnta
+\newcount\@tempcntb
+\newdimen\@tempdima
+\newdimen\@tempdimb
+\newdimen\@tempdimc
+\newbox\@tempboxa
+\newskip\@tempskipa
+\newskip\@tempskipb
+\newtoks\@temptokena
+\def\@nnil{\@nil}
+\def\@empty{}
+\def\space{ }
+\def\@space{ }
+\long\def\@firstofone#1{#1}
+\let\@iden\@firstofone
+\long\def\@firstoftwo#1#2{#1}
+\long\def\@secondoftwo#1#2{#2}
+\long\def\@gobble#1{}
+\long\def\@gobbletwo#1#2{}
+\lowercase{\def\@gobblespace} {}
+\def\@nameuse#1{\csname#1\endcsname}
+\def\@namedef#1{\expandafter\def\csname#1\endcsname}
+\let\l@ngrel@x\relax
+\def\loop#1\repeat{%
+ \def\iterate{#1\relax\expandafter\iterate\fi}%
+ \iterate\let\iterate\relax
+}
+\let\repeat\fi
+\protected\def\newif#1{%
+ \count@\escapechar
+ \escapechar\m@ne
+ \let#1\iffalse
+ \ltx@booldef#1\iftrue
+ \ltx@booldef#1\iffalse
+ \escapechar\count@
+}
+\protected\def\ltx@booldef#1#2{%
+ \expandafter\def\csname\expandafter\@gobbletwo\string#1%
+ \expandafter\@gobbletwo\string#2\endcsname{\let#1#2}%
+}
+\long\protected\def\@ifnextchar#1#2#3{%
+ \let\reserved@d=#1%
+ \def\reserved@a{#2}%
+ \def\reserved@b{#3}%
+ \futurelet\@let@token\@ifnch
+}
+\def\@ifnch{%
+ \ifx\@let@token\@sptoken
+ \let\reserved@c\@xifnch
+ \else
+ \ifx\@let@token\reserved@d
+ \let\reserved@c\reserved@a
+ \else
+ \let\reserved@c\reserved@b
+ \fi
+ \fi
+ \reserved@c
+}
+\lowercase{\lowercase{\let\@sptoken= } }
+\lowercase{\def\@xifnch} {\futurelet\@let@token\@ifnch}
+\let\kernel@ifnextchar\@ifnextchar
+\long\def\@testopt#1#2{\kernel@ifnextchar[{#1}{#1[{#2}]}}
+\protected\def\@expandtwoargs#1#2#3{%
+ \edef\reserved@a{\noexpand#1{#2}{#3}}\reserved@a
+}
+\edef\@backslashchar{\expandafter\@gobble\string\\}
+\newif\ifin@
+\def\strip@prefix#1>{}
+\protected\def\@onelevel@sanitize#1{%
+ \edef#1{\expandafter\strip@prefix\meaning#1}%
+}
+\long\protected\def\g@addto@macro#1#2{%
+ \begingroup
+ \toks@\expandafter{#1#2}%
+ \xdef#1{\the\toks@}%
+ \endgroup
+}
+% In case we call \@latex@error, etc, without LaTeX:
+\newwrite\@unused
+\def\typeout#1{%
+ \begingroup
+ \let\protect\string
+ \immediate\write\@unused{#1}%
+ \endgroup
+}
+\let\MessageBreak\relax
+\protected\def\GenericInfo#1#2{%
+ \begingroup
+ \def\MessageBreak{^^J#1}%
+ \let\protect\string
+ \immediate\write\m@ne{#2\on@line.}%
+ \endgroup
+}
+\protected\def\GenericWarning#1#2{%
+ \begingroup
+ \def\MessageBreak{^^J#1}%
+ \let\protect\string
+ \immediate\write\@unused{^^J#2\on@line.^^J}%
+ \endgroup
+}
+
+\begingroup
+\lccode`\@=`\ %
+\lccode`\~=`\ %
+\lccode`\}=`\ %
+\lccode`\{=`\ %
+\lccode`\T=`\T%
+\lccode`\H=`\H%
+\catcode`\ =11\relax%
+\lowercase{\endgroup%
+\protected\def\GenericError#1#2#3#4{%
+\begingroup%
+\immediate\write\@unused{}%
+\def\MessageBreak{^^J}%
+\let\protect\string%
+\edef%
+\@err@ % \@err@
+{{#4}}%
+\errhelp
+\@err@ % \@err@
+\let
+\@err@ % \@err@
+\@empty
+\def\MessageBreak{^^J#1}%
+\def~{\errmessage{%
+#2.^^J^^J%
+#3^^J%
+Type H <return> for immediate help%
+\@err@ % \@err@
+}}%
+~%
+\endgroup}}%
+
+\def\PackageError#1#2#3{%
+ \GenericError{%
+ (#1)\@spaces\@spaces\@spaces\@spaces
+ }{%
+ Package #1 Error: #2%
+ }{%
+ See the #1 package documentation for explanation.%
+ }{#3}%
+}
+\def\PackageWarning#1#2{%
+ \GenericWarning{%
+ (#1)\@spaces\@spaces\@spaces\@spaces
+ }{%
+ Package #1 Warning: #2%
+ }%
+}
+\def\PackageWarningNoLine#1#2{%
+ \PackageWarning{#1}{#2\@gobble}%
+}
+\def\PackageInfo#1#2{%
+ \GenericInfo{%
+ (#1) \@spaces\@spaces\@spaces
+ }{%
+ Package #1 Info: #2%
+ }%
+}
+\def\ClassError#1#2#3{%
+ \GenericError{%
+ (#1) \space\@spaces\@spaces\@spaces
+ }{%
+ Class #1 Error: #2%
+ }{%
+ See the #1 class documentation for explanation.%
+ }{#3}%
+}
+\def\ClassWarning#1#2{%
+ \GenericWarning{%
+ (#1) \space\@spaces\@spaces\@spaces
+ }{%
+ Class #1 Warning: #2%
+ }%
+}
+\def\ClassWarningNoLine#1#2{%
+ \ClassWarning{#1}{#2\@gobble}%
+}
+\def\ClassInfo#1#2{%
+ \GenericInfo{%
+ (#1) \space\space\@spaces\@spaces
+ }{%
+ Class #1 Info: #2%
+ }%
+}
+\def\@latex@error#1#2{%
+ \GenericError{%
+ \space\space\space\@spaces\@spaces\@spaces
+ }{%
+ LaTeX Error: #1%
+ }{%
+ See the LaTeX manual or LaTeX Companion for explanation.%
+ }{#2}%
+}
+\let\@latexerr\@latex@error
+\def\@latex@warning#1{%
+ \GenericWarning{%
+ \space\space\space\@spaces\@spaces\@spaces
+ }{%
+ LaTeX Warning: #1%
+ }%
+}
+\let\@warning\@latex@warning
+\def\@warningnoline#1{\@latex@warning{#1\@gobble}}
+\def\@latex@info#1{%
+ \GenericInfo{%
+ \@spaces\@spaces\@spaces
+ }{%
+ LaTeX Info: #1%
+ }%
+}
+\def\@infonoline#1{\@latex@info{#1\@gobble}}
+\errorcontextlines=\m@ne
+\ifnum\inputlineno=\m@ne
+ \let\on@line\@empty
+\else
+ \def\on@line{ on input line \the\inputlineno}
+\fi
+
+\def\@spaces{\space\space\space\space}
+\def\@ehd{%
+ There is a problem here. Investigate it before
+ \MessageBreak proceeding. Try typing <return>
+ to proceed.\MessageBreak If that doesn't work,
+ type X <return> to quit.
+}
+\def\showoverfull{\tracingonline\@ne}
+\def\loggingoutput{%
+ \tracingoutput\@ne\showboxbreadth\maxdimen
+ \showboxdepth\maxdimen\errorstopmode
+}
+\def\loggingall{%
+ \tracingcommands\tw@\tracingstats\tw@
+ \tracingpages\@ne\tracinglostchars\@ne
+ \tracingmacros\tw@\tracingparagraphs\@ne
+ \tracingrestores\@ne\errorcontextlines\maxdimen
+ \loggingoutput
+}
+\def\tracingall{\loggingall\showoverfull}
+
+\skv@ltxcmds@restorecatcodes
+\endinput
+
+%% End of file 'skeyval-ltxcmds.tex'.
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-ltxpatch.sty b/macros/latex/contrib/skeyval/tex/skeyval-ltxpatch.sty
new file mode 100644
index 0000000000..fee051aa61
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-ltxpatch.sty
@@ -0,0 +1,444 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-ltxpatch.sty', version 1.3, 2013/05/15. %
+% %
+% The rationale for this package: the patch in 'xkvltxp' package isn't %
+% strong enough. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode044 12 % ,
+\def\skv@prova{\endgroup
+ \def\do##1,{%
+ \ifx\do##1\else
+ \catcode##1\string=\the\catcode##1\relax
+ \expandafter\do
+ \fi
+ }%
+ \edef\skv@ltxp@restorecodes{\do35,64,123,125,61,59,13,\do,}%
+}
+\skv@prova
+
+\edef\skv@ltxp@restorecodes{%
+ \unexpanded\expandafter{\skv@ltxp@restorecodes}%
+ \endlinechar\the\endlinechar\relax
+}
+\endlinechar13 %
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode061 12 % =
+\catcode044 12 % ,
+\def\do#1=#2,{%
+ \ifx\do#1\else
+ \edef\skv@ltxp@restorecodes{%
+ \unexpanded\expandafter{\skv@ltxp@restorecodes}%
+ \catcode#1=\the\catcode#1\relax
+ }%
+ \catcode#1=#2\relax
+ \expandafter\do
+ \fi
+}
+\do 032=10,033=12,036=03,038=04,040=12,041=12,042=12,043=12,%
+ 059=12,045=12,047=12,058=12,063=12,091=12,093=12,126=13,\do=,%
+
+\NeedsTeXFormat{LaTeX2e}[2011/06/27]
+\ProvidesPackage{skeyval-ltxpatch}
+ [2013/05/15 v1.3 Patches for LaTeX2e kernel options processing (AM)]
+
+\ifdefined\skvz@\else\newdimen\skvz@\fi
+\def\@space{ }
+\protected\def\skvltxptracingall{%
+ \tracinggroups\@ne\tracingifs\@ne\loggingall\tracingassigns\@ne
+ \tracingonline\skvz@\tracingifs\skvz@
+}
+\let\skvltxploggingall\skvltxptracingall
+
+\def\skvltxp@cmptwo#1#2\@@a#3#4\@@b#5{%
+ \csname @#5#1#3first\else second\fi oftwo\endcsname
+}
+
+\begingroup
+\lccode`\&=0 \catcode`\&=7 \lccode`\!=0 \catcode`\!=8
+\lowercase{\endgroup
+ \def\skvltxp@ifleadspace#1{\skvltxp@ifl@adspace!#1! &}%
+ \def\skvltxp@ifl@adspace#1! #2&{%
+ \skvltxp@ifnull{#2}\@secondoftwo\@firstoftwo
+ }
+ \def\skvltxp@ifnull#1{\skvltxp@cmptwo#1&\@@a&\@@b\ifx}
+ \def\skvltxp@ifx#1#2{\skvltxp@cmptwo#1&\@@a#2!\@@b\ifx}
+ \def\skvltxp@trimspace#1{\skvltxp@trimspace@a.#1& &}
+ \def\skvltxp@trimspace@a#1 &{\skvltxp@trimspace@b#1&}
+ \def\skvltxp@trimspace@b#1&#2{%
+ \unexpanded\expandafter{%
+ \romannumeral0%
+ \expandafter\skvltxp@ifleadspace\expandafter{\@gobble#1}{%
+ \@gobble#1%
+ }{%
+ \expandafter\@space\@gobble#1%
+ }%
+ }%
+ }
+}
+\protected\def\skvltxp@despacecontent#1{%
+ \edef#1{\expandafter\skvltxp@trimspace\expandafter{#1}}%
+}
+
+% \skvltxp@setupnormalizer{<parser>}<normalizer.cmd>
+% <normalizer.cmd> should not be used for normalizing keyval lists.
+\protected\def\skvltxp@setupnormalizer#1#2{%
+ \begingroup
+ \lccode`\~=`#1\relax
+ \lowercase{\endgroup
+ \def#2##1{%
+ \unexpanded\expandafter
+ {\romannumeral\skvltxp@activeparser#1##1#1~\skv@nil}%
+ }%
+ \def\skvltxp@activeparser##1~##2\skv@nil{%
+ \skvltxp@ifnull{##2}
+ {\skvltxp@spaceparser##1 #1\skv@nil}
+ {\skvltxp@activeparser##1#1##2\skv@nil}%
+ }%
+ }%
+ \def\skvltxp@spaceparser##1 #1##2\skv@nil{%
+ \skvltxp@ifnull{##2}
+ {\skvltxp@parserspace##1#1 \skv@nil}
+ {\skvltxp@spaceparser##1#1##2\skv@nil}%
+ }%
+ \def\skvltxp@parserspace##1#1 ##2\skv@nil{%
+ \skvltxp@ifnull{##2}
+ {\skvltxp@doubleparser##1#1#1\skv@nil}
+ {\skvltxp@parserspace##1#1##2\skv@nil}%
+ }%
+ \def\skvltxp@doubleparser##1#1#1##2\skv@nil{%
+ \skvltxp@ifnull{##2}{%
+ \skvltxp@ifnull{##1}{0 }{0\expandafter\@space\@gobble##1}%
+ }{%
+ \skvltxp@doubleparser##1#1##2\skv@nil
+ }%
+ }%
+}
+\skvltxp@setupnormalizer{,}\skvltxp@commanormalize
+
+\newif\ifbreakkerpaloop
+\def\kerpaloopdepth{0}
+% \kerpaloop{<parser>}{<list>}{<1.parameter.callback>}
+% \kerpaloop*{<parser>}{<listcmd>}{<1.parameter.callback>}
+\protected\def\kerpaloop{\@ifstar{\skv@kerpaloop1}{\skv@kerpaloop0}}
+\def\skv@kerpaloop#1#2#3#4{%
+ \xdef\kerpaloopdepth{\the\numexpr\kerpaloopdepth+1}%
+ \def\skv@k@rpaloop{kerpaloop@\romannumeral\kerpaloopdepth}%
+ \breakkerpaloopfalse
+ \@namedef{\skv@k@rpaloop}##1#2{%
+ \skvltxp@ifx{##1}\kerpaloop{%
+ \breakkerpaloopfalse
+ }{%
+ #4\relax
+ \ifbreakkerpaloop
+ \breakkerpaloopfalse
+ \begingroup
+ \@namedef\skv@k@rpaloop####1\kerpaloop#2{\endgroup}%
+ \fi
+ \@nameuse\skv@k@rpaloop
+ }%
+ }%
+ \edef\reserved@a{%
+ \if0#1\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+ {\unexpanded{#3}}{\unexpanded\expandafter{#3}}%
+ }%
+ \ifx\reserved@a\@empty\expandafter\@gobble\else\expandafter\@iden\fi
+ {%
+ \csname\skv@k@rpaloop\expandafter\endcsname
+ \reserved@a#2\kerpaloop#2%
+ }%
+ \xdef\kerpaloopdepth{\the\numexpr\kerpaloopdepth-1}%
+}
+% \skvltxp@getoptionnames<cmd.in><cmd.out>
+\def\skvltxp@getoptionnames#1#2{%
+ \def#2{}%
+ \edef#1{\expandafter\skvltxp@commanormalize\expandafter{#1}}%
+ \def\do##1=##2=##3\skv@nil{%
+ \edef#2{\ifx\@empty#2\else#2,\fi##1}%
+ }%
+ \kerpaloop*{,}#1{\do##1==\skv@nil}%
+}
+\def\@ptionlist#1{%
+ \@ifundefined{opt@#1}{}{\unexpanded\expandafter
+ \expandafter\expandafter{\csname opt@#1\endcsname}}%
+}
+\def\@if@ptions#1#2#3{%
+ \@expandtwoargs\@if@pti@ns{\@ptionlist{#2.#1}}{\unexpanded{#3}}%
+}
+\def\@if@pti@ns#1#2{%
+% \skvltxp@setupnormalizer{,}%
+ \edef\skv@options@i{\skvltxp@commanormalize{#1}}%
+ \edef\skv@options@ii{\skvltxp@commanormalize{#2}}%
+ \ifx\skv@options@i\skv@options@ii
+ \def\skv@tempa{\expandafter\@firstoftwo\@gobbletwo}%
+ \else
+ \ifx\skv@options@ii\@empty
+ \ifx\skv@options@i\@empty
+ \def\skv@tempa{\expandafter\@firstoftwo\@gobbletwo}%
+ \else
+ \def\skv@tempa{\expandafter\@secondoftwo\@gobbletwo}%
+ \fi
+ \else
+ \let\skv@tempa\@iden
+ \fi
+ \fi
+ \skv@tempa{%
+ \let\skv@tempa\@firstoftwo
+ \def\do##1{%
+ \@expandtwoargs\in@{,\detokenize{##1},}%
+ {,\detokenize\expandafter{\skv@options@i},}%
+ \ifin@\else\let\skv@tempa\@secondoftwo\breakkerpalooptrue\fi
+ }%
+ \kerpaloop*{,}\skv@options@ii{\do{##1}}%
+ }%
+ \skv@tempa
+}
+\def\@onefilewithoptions#1[#2][#3]#4{%
+ \@pushfilename
+ \xdef\@currname{#1}%
+ \global\let\@currext#4%
+ \expandafter\let\csname\@currname.\@currext-h@@k\endcsname\@empty
+ \let\CurrentOption\@empty
+ \@reset@ptions
+ \makeatletter
+ \@ifl@aded\@currext{#1}{%
+ \@if@ptions\@currext{#1}{#2}{}{%
+ % Merge the two options lists:
+ \let\skv@tempa\skv@options@i
+ \skvltxp@ifnull{#2}{}{%
+ \def\do##1{%
+ \@expandtwoargs\in@{,\detokenize{##1},}%
+ {,\detokenize\expandafter{\skv@tempa},}%
+ \ifin@\else
+ \edef\skv@tempa{%
+ \ifx\skv@tempa\@empty\else
+ \detokenize\expandafter{\skv@tempa},\fi
+ \detokenize{##1}%
+ }%
+ \fi
+ }%
+ \kerpaloop*{,}\skv@options@ii{\do{##1}}%
+ }%
+ \@onelevel@sanitize\skv@options@i
+ \@onelevel@sanitize\skv@options@ii
+ \@latex@error{Option clash for \@cls@pkg\@space #1}{%
+ The package '#1' has already been loaded
+ with \ifx\skv@options@i\@empty no options\MessageBreak\else
+ options:\MessageBreak\@space\@space[\skv@options@i]\fi.
+ \MessageBreak There has now been an attempt to load it with
+ \ifx\skv@options@ii\@empty no options\else options
+ \MessageBreak\@space\@space[\skv@options@ii]\fi.
+ \MessageBreak Adding the global options\MessageBreak
+ \@space\@space'\skv@tempa'\MessageBreak
+ to your \noexpand\documentclass declaration may fix this problem.
+ }%
+ }%
+ }{%
+ \@pass@ptions\@currext{#2}{#1}%
+ \global\expandafter
+ \let\csname ver@\@currname.\@currext\endcsname\@empty
+ \InputIfFileExists{\@currname.\@currext}{}{%
+ \@missingfileerror\@currname\@currext
+ }%
+ \let\@unprocessedoptions\@@unprocessedoptions
+ \csname\@currname.\@currext-h@@k\endcsname
+ \expandafter\let\csname\@currname.\@currext-h@@k\endcsname\@undefined
+ \@unprocessedoptions
+ }%
+ \def\skv@tempa##1 v##2 ##3\@nil##4{%
+ \edef##4{'##1\ifx\\##2\\\else\@space v##2\fi'}%
+ }%
+ \skv@tempa#3 v \@nil\skv@tempb
+ \expandafter\expandafter\expandafter\skv@tempa
+ \csname ver@#1.\@currext\expandafter\endcsname
+ \@space v \@nil\skv@tempc
+ \@ifl@ter\@currext{#1}{#3}{}{%
+ \@expandtwoargs\AtEndDocument{%
+ \noexpand\@latex@warning@no@line{%
+ You requested,\on@line, version\MessageBreak
+ \skv@tempb\@space of \@cls@pkg\@space #1,\MessageBreak
+ but only version \skv@tempc\MessageBreak is available
+ }%
+ }{}%
+ }%
+ \ifx\@currext\@clsextension
+ \let\LoadClass\@twoloadclasserror
+ \fi
+ \@popfilename
+ \@reset@ptions
+}
+\protected\def\ProcessOptions{%
+ \let\ds@\@empty
+ \edef\@curroptions{\@ptionlist{\@currname.\@currext}}%
+ \ifx\@classoptionslist\relax
+ \let\@classoptionslist@a\relax
+ \else
+ % LaTeX can't process options with values. So we filter out
+ % option values:
+ \skvltxp@getoptionnames\@classoptionslist\@classoptionslist@a
+ \fi
+ \skvltxp@getoptionnames\@curroptions\@curroptions@a
+ \@ifstar\@xprocess@ptions\@process@ptions
+}
+\def\@process@ptions{%
+ \@for\CurrentOption:=\@declaredoptions\do{%
+ \ifx\CurrentOption\@empty\else
+ \@expandtwoargs\in@{,\CurrentOption,}{%
+ ,\ifx\@currext\@clsextension\else
+ \ifx\@classoptionslist@a\relax\else\@classoptionslist@a,\fi\fi
+ \@curroptions@a,}%
+ \ifin@
+ \@use@ption
+ \expandafter\let\csname ds@\CurrentOption\endcsname\@empty
+ \fi
+ \fi
+ }%
+ \@process@pti@ns
+}
+\def\@xprocess@ptions{%
+ \ifx\@currext\@clsextension\else
+ \@for\CurrentOption:=\@classoptionslist@a\do{%
+ \ifx\CurrentOption\@empty\else
+ \@expandtwoargs\in@{,\CurrentOption,}{,\@declaredoptions,}%
+ \ifin@
+ \@use@ption
+ \expandafter\let\csname ds@\CurrentOption\endcsname\@empty
+ \fi
+ \fi
+ }%
+ \fi
+ \@process@pti@ns
+}
+\def\@process@pti@ns{%
+ \@for\CurrentOption:=\@curroptions@a\do{%
+ \@ifundefined{ds@\CurrentOption}{\@use@ption\default@ds}{\@use@ption}%
+ }%
+ \@for\CurrentOption:=\@declaredoptions\do{%
+ \expandafter\let\csname ds@\CurrentOption\endcsname\relax
+ }%
+ \let\CurrentOption\@empty
+ \let\@fileswith@pti@ns\@@fileswith@pti@ns
+ \AtEndOfPackage{\let\@unprocessedoptions\relax}%
+}
+\def\@pass@ptions#1#2#3{%
+ \def\reserved@a{#2}%
+ \def\reserved@b{\CurrentOption}%
+ \ifx\reserved@a\reserved@b
+ \@ifundefined{opt@#3.#1}{%
+ \@temptokena\expandafter{#2}%
+ }{%
+ \@temptokena\expandafter\expandafter\expandafter
+ {\csname opt@#3.#1\endcsname}%
+ \@temptokena\expandafter\expandafter\expandafter{%
+ \expandafter\the\expandafter\@temptokena\expandafter,#2}%
+ }%
+ \else
+ \@ifundefined{opt@#3.#1}{%
+ \@temptokena{#2}%
+ }{%
+ \@temptokena\expandafter\expandafter\expandafter
+ {\csname opt@#3.#1\endcsname}%
+ \@temptokena\expandafter{\the\@temptokena,#2}%
+ }%
+ \fi
+ \expandafter\xdef\csname opt@#3.#1\endcsname{\the\@temptokena}%
+}
+\def\OptionNotUsed{%
+ \ifx\@currext\@clsextension
+ \let\reserved@a\CurrentOption
+ \@onelevel@sanitize\reserved@a
+ \xdef\@unusedoptionlist{%
+ \@unusedoptionlist
+ \ifx\@unusedoptionlist\@empty\else,\fi
+ \reserved@a
+ }%
+ \fi
+}
+
+\def\@use@ption{%
+ \begingroup
+ \skvltxp@despacecontent\CurrentOption
+ \@onelevel@sanitize\reserved@a
+ \@onelevel@sanitize\@unusedoptionlist
+ \def\skv@tempa{}%
+ \def\do##1=##2=##3\@nil{%
+ \edef\reserved@a{\skvltxp@trimspace{##1}}%
+ }%
+ \kerpaloop*{,}\@unusedoptionlist{%
+ \do##1==\@nil
+ \ifx\reserved@a\CurrentOption\else
+ \edef\skv@tempa{%
+ \skv@tempa\ifx\skv@tempa\@empty\else,\fi##1%
+ }%
+ \fi
+ }%
+ \global\let\@unusedoptionlist\skv@tempa
+ \endgroup
+ \csname ds@\CurrentOption\endcsname
+}
+\def\@fileswith@pti@ns#1[#2]#3[#4]{%
+ \ifx\@clsextension#1%
+ \ifx\@classoptionslist\relax
+ \@temptokena{#2}%
+ \xdef\@classoptionslist{\the\@temptokena}%
+ \def\reserved@a{%
+ \@onefilewithoptions#3[#2][#4]#1\@documentclasshook
+ }%
+ \else
+ \def\reserved@a{\@onefilewithoptions#3[#2][#4]#1}%
+ \fi
+ \else
+ \@temptokena{#2}%
+ \def\reserved@b##1,{%
+ \ifx\@nnil##1\relax\else
+ \ifx\relax##1\relax\else
+ \noexpand\@onefilewithoptions##1%
+ [\the\@temptokena][#4]\noexpand\@pkgextension
+ \fi
+ \expandafter\reserved@b
+ \fi
+ }%
+ \edef\reserved@a{\zap@space#3 \@empty}%
+ \edef\reserved@a{\expandafter\reserved@b\reserved@a,\@nnil,}%
+ \fi
+ \reserved@a
+}
+\let\@@fileswith@pti@ns\@fileswith@pti@ns
+
+\skv@ltxp@restorecodes
+\endinput
+
+%% End of file `skeyval-ltxpatch.sty'.
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-pstkey.sty b/macros/latex/contrib/skeyval/tex/skeyval-pstkey.sty
new file mode 100644
index 0000000000..caa843aafe
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-pstkey.sty
@@ -0,0 +1,87 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-pstkey.sty', version 1.3, 2013/05/15. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode044 12 % ,
+\def\skv@prova{\endgroup
+ \def\do##1,{%
+ \ifx\do##1\else
+ \catcode##1\string=\the\catcode##1\relax
+ \expandafter\do
+ \fi
+ }%
+ \edef\skv@pst@restorecodes{\do35,64,123,125,61,59,13,\do,}%
+}
+\skv@prova
+
+\edef\skv@pst@restorecodes{%
+ \unexpanded\expandafter{\skv@pst@restorecodes}%
+ \endlinechar\the\endlinechar\relax
+}
+\endlinechar13 %
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode061 12 % =
+\catcode044 12 % ,
+\def\do#1=#2,{%
+ \ifx\do#1\else
+ \edef\skv@pst@restorecodes{%
+ \unexpanded\expandafter{\skv@pst@restorecodes}%
+ \catcode#1=\the\catcode#1\relax
+ }%
+ \catcode#1=#2\relax
+ \expandafter\do
+ \fi
+}
+\do 032=10,033=12,036=03,038=04,040=12,041=12,042=12,043=12,%
+ 059=12,045=12,047=12,058=12,063=12,091=12,093=12,126=13,\do=,%
+
+\NeedsTeXFormat{LaTeX2e}[2011/06/27]
+\ProvidesPackage{skeyval-pstkey}
+ [2013/05/15 v1.3 LaTeX/package wrapper for skeyval-pstkey.tex (AM)]
+
+\expandafter\ifx\csname skeyval-pstkey-loaded\endcsname
+\endinput\else
+ \input skeyval-pstkey
+\fi
+\skvdeclareoption*{%
+ \PackageWarning{skeyval-pstkey}
+ {Unknown option '\CurrentOption' ignored}%
+}
+\skvprocessoptions
+\skv@pst@restorecodes
+\endinput
+
+%% End of file `skeyval-pstkey.sty'.
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-pstkey.tex b/macros/latex/contrib/skeyval/tex/skeyval-pstkey.tex
new file mode 100644
index 0000000000..18a97c4e72
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-pstkey.tex
@@ -0,0 +1,94 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-pstkey.tex', version 1.3, 2013/05/15. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup%
+\let\e\endlinechar\edef\p{\the\e}\e13\edef\n{\the\catcode\e}%
+\xdef\skv@pst@restorecatcodes{%
+ \let\noexpand\skv@pst@restorecatcodes\relax%
+ \endlinechar=\p\relax\catcode\number\e=\n\relax%
+ \catcode\string`\noexpand`\string=\the\catcode\string``\relax%
+ \catcode\string`\noexpand=\string=\the\catcode\string`=\relax%
+}%
+\endgroup%
+\endlinechar\string=13\relax%
+\catcode13\string=5\relax%
+\catcode\string``\string=12\relax
+\catcode\string`=\string=12\relax
+\def\skvgobble#1{}
+\def\do#1{\catcode`\expandafter\skvgobble\string#1=\the\catcode`#1\relax}
+\edef\skv@pst@restorecatcodes{%
+ \unexpanded\expandafter{\skv@pst@restorecatcodes}%
+ \do\ \do\%\do\@\do\(\do\)\do\[\do\]\do\|\do\:\do\;\do\,\do\.%
+ \do\>\do\<\do\!\do\*\do\+\do\-\do\^\do\_\do\&\do\$\do\~\do\'%
+ \do\"\do\
+}
+\catcode`\ =10\relax
+\catcode`\@=11 \catcode`\(=12 \catcode`\)=12 \catcode`\[=12
+\catcode`\]=12 \catcode`\|=12 \catcode`\:=12 \catcode`\;=12
+\catcode`\,=12 \catcode`\*=12 \catcode`\+=12 \catcode`\-=12
+\catcode`\<=12 \catcode`\>=12 \catcode`\!=12 \catcode`\.=12
+\catcode`\^=07 \catcode`\_=08 \catcode`\&=04 \catcode`\$=03
+\catcode`\~=13 \catcode`\%=14 \catcode`\'=12 \catcode`\"=12
+
+\csname skeyval-pstkey-loaded\endcsname
+\expandafter\let\csname skeyval-pstkey-loaded\endcsname\endinput
+
+\def\skv@pst@afterfi#1\fi{\fi#1}
+\def\skv@pst@afterelse#1\else#2\fi{\fi#1}
+
+\ifx\ProvidesFile\@undefined\skv@pst@afterelse
+ \message{File 'skeyval-pstkey.tex' 2013/05/15 v1.3
+ PSTricks specialization of skeyval package (AM)}
+ \input skeyval-core
+\else\skv@pst@afterfi
+ \ProvidesFile{skeyval-pstkey.tex}
+ [2013/05/15 v1.3 PSTricks specialization of skeyval (AM)]
+ \@addtofilelist{skeyval-pstkey.tex}
+ \@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}}
+\fi
+
+\def\pst@famlist{}
+\def\pst@addfams#1{%
+ \skvcommaloop{#1}\skv@tempa{%
+ \skvxifin{,\skv@tempa,}{,\pst@famlist,}{}{%
+ \edef\pst@famlist{\pst@famlist,\skv@tempa}%
+ }%
+ }%
+}
+\def\psset{\skvexpandbracenext{\skv@testopt\pss@t}\pst@famlist}
+\def\pss@t[#1]#2{\skvsetkeys+[psset]{#1}{#2}\ignorespaces}
+\def\@psset#1,\@nil{%
+ \edef\skv@tempa{\skvsetkeys+[psset]{\pst@famlist}}%
+ \skv@tempa{#1}%
+}
+
+\skv@pst@restorecatcodes
+\endinput
+
+%% End of file 'skeyval-pstkey.tex'.
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-testclass.cls b/macros/latex/contrib/skeyval/tex/skeyval-testclass.cls
new file mode 100644
index 0000000000..771d60160f
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-testclass.cls
@@ -0,0 +1,321 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-testclass.cls', version 1.3, 2013/05/15. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\ProvidesClass{skeyval-testclass}[2013/05/15 v1.3 skeyval test class (AM)]
+\NeedsTeXFormat{LaTeX2e}[2011/06/27]
+\@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}}
+\@ifpackageloaded{xcolor}{}{\RequirePackage{xcolor}}
+\@ifpackageloaded{pifont}{}{\RequirePackage{pifont}}
+\@ifpackageloaded{tikz}{}{\RequirePackage{tikz}}
+
+\ifdefined\skvtestcnt\else\newcount\skvtestcnt\fi
+\skvatbegineverypage{\skvcl@maybewm}
+\let\skvcl@maybewm\relax
+\def\skvcl@watermark{%
+ \tikz[overlay,remember picture]{%
+ \node [\skvcl@watermarkcolor,inner sep=0pt,rotate=45,align=center,
+ scale=\skvcl@watermarkscale,font=\fontseries{b}\fontfamily{bch}%
+ \fontsize{\skvcl@fontsize@a}{\skvcl@fontsize@b}\selectfont] at
+ ([shift={(\skvcl@watermarkxshift,-\skvcl@watermarkyshift)}]%
+ current page.north west){%
+ \skvcl@watermarktext
+ };
+ }%
+}
+
+\skvrobustdef*\skvcl@titlecmds{%
+ \setcounter{footnote}{0}%
+ \def\do##1{\global\let##1\@empty}%
+ \do\@thanks\do\@author\do\@date\do\@title
+ \def\do##1{\global\let##1\relax}%
+ \do\thanks\do\maketitle\do\@maketitle\do\title\do\author\do
+ \date\do\and\let\do\relax
+ \let\@fnsymbol\orig@fnsymbol
+}
+\let\orig@fnsymbol\@fnsymbol
+
+\skvrobustredef*\skv@fnsymbol#1{%
+ \unskip\ifcase#1\or\ding{'106}\or\ding{'110}\or\ding{'111}\or
+ \ding{'112}\or\ding{'113}\or\ding{'114}\or\ding{'121}\or
+ \ding{'122}\else\@ctrerr\fi
+}
+\skvrobustdef*\skvcl@newfootnotestyle{%
+ \def\@makefnmark{%
+ \rlap{\@textsuperscript{\normalfont\skv@fnsymbol\@thefnmark}}%
+ }%
+ \long\def\@makefntext##1{%
+ \parindent1em\relax\noindent
+ \hb@xt@1.8em{\hss\@textsuperscript{%
+ \normalfont\skv@fnsymbol\@thefnmark}%
+ }%
+ ##1%
+ }%
+}
+\skvnewlet\skv@sav@footnote\footnote
+\skvnewlet\skv@sav@thanks\thanks
+\AtEndOfPackage{%
+ \skvdisablekeys[SKVC]{title}{insertwatermark}%
+}
+\AtBeginDocument{%
+ \def\footnote{\unskip\skv@sav@footnote}%
+ \def\thanks{\unskip\skv@sav@thanks}%
+ \skvdisablekeys[SKVC]{textemphasis}{dummy-option}%
+ \skvdisablekeys[SKVC]{title}{%
+ maketitlepage,firstpagenumber,pagenumberstyle
+ }%
+}
+\let\skvcl@settitlepageno\@gobble
+
+% Example of option and nonoption keys:
+\skvordkeys[KV]{fam}{testkey1,testkey2}[value]{}
+\skvoptionkeys[KV]{fam}{testkey1}
+\skvnonoptionkeys[KV]{fam}{testkey2}
+
+% LaTeX will zap spaces in key name, anyway. So our options don't have
+% spaces within themselves.
+
+\directkeys*{%
+ .every unknown option={
+ \PassOptionsToClass{\CurrentOption}{article}
+ },
+ .message type when disabled option is invoked=error,
+ .prefix=SKVC,
+ % Extended text emphasis:
+ .family=textemphasis,
+ .hp=xem@,
+ .new options={
+ .initialize keys after define,
+ .ord/{testkey1,testkey2,testkey3}/default,
+ .bool/useitalic/true,
+ .bool/usebold/true,
+ .bool/usecolor/true,
+ .cmd/color/red,
+ .bool/make-textemphasis-inactive/true/
+ \ifskvindef\else
+ \skvifbool xem@make-textemphasis-inactive\then
+ \PackageInfo{skeyval-testclass}
+ {Extended text emphasis has been made inactive}
+ \let\xem\emph
+ \fi
+ \fi
+ ,
+ .ord/dummy-option/\@nil,
+ },
+ .links={
+ useitalics/useitalic,
+ usecolour/usecolor,
+ colour/color,
+ },
+ .option keys = {testkey1},
+ .nonoption keys = {testkey2,testkey3},
+ % Modifying the article title:
+ .change family=title,
+ .hp=skvcl@,
+ .new options={
+ .bool/putdate/true,
+ .cmd/datefont/\large,
+ .bool/clearpage/true,
+ .bool/maketitlepage/true/
+ \skvifbool skvcl@maketitlepage\then
+ \ifskvindef\else
+ \PassOptionsToClass{titlepage}{article}
+ \fi
+ \fi
+ ,
+ .cmd/firstpagenumber/\@nil/
+ \ifx\skvcl@firstpagenumber\@nnil\else
+ \skvensureinteger{page number}\skvcl@firstpagenumber
+ \AtBeginDocument{%
+ \gdef\pagenumbering##1{%
+ \global\c@page\skvcl@firstpagenumber\relax
+ \gdef\thepage{\csname @##1\endcsname\c@page}%
+ }%
+ % Default:
+ \pagenumbering{arabic}%
+ \let\skvcl@settitlepageno\@iden
+ }%
+ \fi
+ ,
+ .cmd/pagenumberstyle/\@nil/
+ \ifx\skvcl@pagenumberstyle\@nnil\else
+ \skvafterbegindocument{\pagenumbering{#1}}%
+ \fi
+ ,
+ .cmd/pretitleskip/10pt,
+ .cmd/posttitleskip/10pt,
+ .cmd/authorfont/\large,
+ .cmd/titlefont/\huge,
+ .bool/insertwatermark/true/
+ \skvifbool skvcl@insertwatermark\then
+ \ifskvindef\else
+ \let\skvcl@maybewm\skvcl@watermark
+ \fi
+ \fi
+ ,
+ .cmd/watermarkxshift/.5\paperwidth,
+ .cmd/watermarkyshift/.5\paperheight,
+ .cmd/watermarktext/DRAFT/
+ \skvstripouterbraces{2}\skvcl@watermarktext
+ ,
+ .cmd/fontsize/{14.4,17}/
+ \def\skvcl@fontsize@a{#1}\def\skvcl@fontsize@b{#2}
+ ,
+ .arg/fontsize/{#1,#2},
+ .cmd/watermarkscale/5,
+ .cmd/watermarkcolor/gray!55,
+ },
+ .slots={
+ showdate/putdate=#1,
+ first-page-number/firstpagenumber=#1,
+ titlepage/maketitlepage=#1,
+ },
+ % Ececute the options in the current family. If any of the options
+ % isn't found, report error (ie, don't save the key to the list of
+ % 'remaining keys'). Unknown options should be flagged immediately.
+ % Use '.execute options+' or '.execute options in all families' to
+ % execute options in multiple families.
+ .execute options={
+ putdate,datefont,clearpage=false,pretitleskip,posttitleskip,
+ authorfont,titlefont,watermarkscale,firstpagenumber,
+ insertwatermark=false,watermarkxshift,watermarkyshift,
+ watermarktext,watermarkcolor,fontsize
+ },
+ .families={textemphasis,title},
+ .process options in all families,
+}
+%\show\skvcurrentpoxkeys
+
+% testkey1 is an option key: don't set it outside option list:
+% \skvsetkeys[SKVC]{textemphasis}{testkey1}
+
+\skvrobustdef*\setupskvtestclass{%
+ \skvsetkeys*+[SKVC]{textemphasis,title}%
+}
+
+% Setting up extended text emphasis:
+\skvrobustdef*\setuptextemphasis#1{\skvsetkeys[SKVC]{textemphasis}{#1}}
+\newcommand*\xem[1]{\xem@emph{\xem@bold{\xem@colortext{\xem@color}{#1}}}}
+\newcommand*\xem@emph{%
+ \skvifbool xem@useitalic\then
+ \expandafter\emph
+ \else
+ \expandafter\@firstofone
+ \fi
+}
+\newcommand*\xem@bold{%
+ \skvifbool xem@usebold\then
+ \expandafter\textbf
+ \else
+ \expandafter\@firstofone
+ \fi
+}
+\newcommand*\xem@colortext{%
+ \skvifbool xem@usecolor\then
+ \expandafter\textcolor
+ \else
+ \expandafter\@secondoftwo
+ \fi
+}
+
+\LoadClass{article}
+
+\if@titlepage
+ \renewcommand\maketitle{%
+ \ifskvcl@clearpage
+ \clearpage
+ \fi
+ \begin{titlepage}%
+ \skvcl@newfootnotestyle
+ \let\footnotesize\small
+ \let\footnoterule\relax
+ \let\footnote\thanks
+ \null\vfil
+ \vskip\skvcl@pretitleskip\relax
+ \begin{center}%
+ {\skvcl@titlefont\@title\par}%
+ \vskip\skvcl@posttitleskip\relax
+ {%
+ \skvcl@authorfont
+ \lineskip.75em\relax
+ \begin{tabular}[t]{c}%
+ \@author
+ \end{tabular}\par
+ }%
+ \vskip1.5em\relax
+ \skvifbool skvcl@putdate\then{{\skvcl@datefont\@date}}\fi
+ \end{center}\par
+ \@thanks
+ \vfil\null
+ \end{titlepage}%
+ \skvcl@settitlepageno{\c@page\skvcl@firstpagenumber\relax}%
+ \skvcl@titlecmds
+ }
+\else
+ \renewcommand\maketitle{%
+ \par
+ \begingroup
+ \skvcl@newfootnotestyle
+ \if@twocolumn
+ \ifnum\col@number=\@ne
+ \@maketitle
+ \else
+ \twocolumn[\@maketitle]%
+ \fi
+ \else
+ \newpage
+ \global\@topnum\z@
+ \@maketitle
+ \fi
+ \thispagestyle{plain}\@thanks
+ \endgroup
+ \skvcl@titlecmds
+ }
+ \def\@maketitle{%
+ \newpage
+ \null
+ \vskip\skvcl@pretitleskip\relax
+ \begin{center}%
+ \let\footnote\thanks
+ {\skvcl@titlefont\@title\par}%
+ \vskip\skvcl@posttitleskip\relax
+ {\skvcl@authorfont
+ \lineskip.5em\relax
+ \begin{tabular}[t]{c}%
+ \@author
+ \end{tabular}\par
+ }%
+ \vskip1em\relax
+ \skvifbool skvcl@putdate\then{\skvcl@datefont\@date}\fi
+ \end{center}%
+ \par
+ \vskip1.5em\relax
+ }
+\fi
+
+\endinput
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-testpkg.sty b/macros/latex/contrib/skeyval/tex/skeyval-testpkg.sty
new file mode 100644
index 0000000000..23a949e483
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-testpkg.sty
@@ -0,0 +1,456 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-testpkg.sty', version 1.3, 2013/05/15. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\ProvidesPackage{skeyval-testpkg}
+ [2013/05/15 v1.3 skeyval test package (AM)]
+\NeedsTeXFormat{LaTeX2e}
+\@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}}
+\RequirePackage{graphicx}
+
+\skvdisabledkeysmessagetype{warning}
+
+%%++++++++++++++++ Passing options to packages +++++++++++++++++++%%
+
+\skvdeclarebooloption[SKVT]<testpkg>[skvtp@]{verbose}[true]{}
+
+% Declare options with default values that will be used when the options
+% are called without user values.
+%
+\skvdeclarepassedoptionsloadpackage[SKVT]{testpkg}{%
+ hyperref={colorlinks,breaklinks},xcolor=svgnames
+}
+
+%%+++++++++++++++++++ Producing arbitrary texts +++++++++++++++++%%
+
+% The key 'align' could have defined using \skvchoicekey, as in
+% 'shadowbox' family below.
+\newcommand*\justified{}
+\skvordkey[SKVT]{abrtext}{align}[right]{%
+ \skvifcase\skvxifstrcmpTF{#1}
+ {left}{\def\mpfalign{flushleft}}
+ {right}{\def\mpfalign{flushright}}
+ {center}{\def\mpfalign{center}}
+ {justified}{\def\mpfalign{justified}}
+ \elsedo
+ \PackageError{skeyval-testpkg}
+ {Invalid value `#1' for align}
+ {You have issued an illegal value `#1' for option `align'.}%
+ \endif
+}
+
+\skvzcmdkey[SKVT]{abrtext}[mpf]{text style}[\rmfamily]{}
+\skvcmdkey[SKVT]{abrtext}[mpf]{author}[Karl Berry]{}
+\skvzboolkey[SKVT]{abrtext}[mpf]{show author}[true]{}
+
+% Using pointers to expand values of keys while setting keys:
+\def\alignval{right}
+\def\alignvalb{\alignval}
+\def\stextstyle{\sffamily}
+
+\skvsetkeys[SKVT]{abrtext}{
+ align=.expand twice{\alignvalb},
+ text style=.expand once{\stextstyle},author,show author
+}
+
+%%+++++++++++++++++++++++++++ Citations +++++++++++++++++++++++++++%%
+
+% Keys defined by \skvdefinekeys are automatically initialiized when
+% the option 'initialize' is true. In general, to save initialize
+% key values at key definition, you need to call \skvsaveinitialvaluekeys
+% before defining the keys.
+
+\skvsaveinitialvaluekeys[SKVT]{citation}{put frame,width,show author,author,
+ textcolor,fonttype,leftmargin,rightmargin,preskip,framecolor,shadecolor,
+ frame thickness}
+
+\newbox\skv@testbox
+\skvdefinekeys*[SKVT]{citation}[ctt@]{%
+ .cmd/width/\hsize,
+ .zbool/show author/true,
+ .cmd/author//, % empty default
+ .zbool/put frame/true,
+ .cmd/framecolor/black,
+ .cmd/shadecolor/white,
+ .cmd/textcolor/black,
+ .zcmd/frame thickness/.4pt,
+ .cmd/fonttype/\normalfont,
+ .cmd/leftmargin/\leftmargin,
+ .cmd/rightmargin/\rightmargin,
+ .cmd/preskip/0ex,
+ .cmd/width/\textwidth,
+ .ord/dummy key/\@nil,
+}
+% Keys defined by \skvdefinekeys are automatically initialiized when
+% the option 'initialize' is true. When \skvsaveinitialvaluekeys has been
+% called for a set of keys, those keys can be initialized via
+% \skvinitializekeys:
+\skvinitializekeys[SKVT]{citation}[dummy key]
+
+\newcommand\newcitation[2][]{%
+ \skvsetkeys[SKVT]{citation}{#1}%
+ \sbox\skv@testbox{%
+ \ctt@fonttype
+ \textit{\textcolor{\ctt@textcolor}{\ctt@author}}%
+ }%
+ \list{}{%
+ \setlength\leftmargin{\ctt@leftmargin}%
+ \setlength\rightmargin{\ctt@leftmargin}%
+ }%
+ \vspace*{\ctt@preskip}%
+ \item\relax
+ \ifctt@putframe
+ \begingroup
+ \fboxrule\ctt@framethickness\relax
+ \fcolorbox{\ctt@framecolor}{\ctt@shadecolor}{%
+ \fi
+ \parbox{\ctt@width}{%
+ \ctt@fonttype\textcolor{\ctt@textcolor}{\ignorespaces#2}%
+ \ifctt@showauthor
+ \hspace*{\fill}\nolinebreak[1]%
+ \quad\hspace*{\fill}\finalhyphendemerits\z@\relax
+ \usebox\skv@testbox
+ \fi
+ }%
+ \ifctt@putframe}\endgroup\fi
+ \endlist
+ % Restore default values of keys:
+ \skvinitializekeys[SKVT]{citation}[]
+}
+
+
+%%++++++++++++++++++++++++ Shadow boxes ++++++++++++++++++++++%%
+
+\newdimen\shadowspread
+
+\skvdefinekeys*[SKVT]{shadowbox}[shb@]{%
+ .zbool/put frame/true,
+ .bool/shadow/true,
+ .cmd/framecolor/black,
+ .cmd/shadecolor/white,
+ .cmd/shadowcolor/gray!55,
+ .cmd/boxwidth/1.5cm,
+ .ord/framesize/.5pt/\def\currfboxrule{#1},
+ .ord/shadowsize/2pt/\shadowspread=\dimexpr#1\relax,
+ .choice/align/center/{%
+ center.do=\def\curralign##1{\hfil##1\hfil},
+ right.do=\def\curralign##1{\hfill##1},
+ left.do=\def\curralign##1{##1\hfill},
+ justified.do=\let\curralign\@iden
+ }
+}
+
+\skvdefinekeys*[SKVT]{testfam}[shb@]{%
+ .zbool/put shadow/true,% Test zbool
+ .zcmd/shade color/gray!55, % Test .zcmd
+}
+
+\skvdisablekeys[SKVT]{testfam}{put shadow, shade color}
+
+% Presetting and posetting keys.
+%
+% 1. 'Presetting keys' means set the following keys whenever
+% \setkeys is called. These keys should be set BEFORE the keys
+% listed in the current argument of \setkeys are set, provided
+% that these keys aren't listed in the current argument of \setkeys.
+% If these keys appear in the current argument of \setkeys,
+% then obviously the user has new values for them or he wants
+% the keys to be set with their default values.
+%
+% 2. 'Postsetting keys' means set the following keys whenever
+% \setkeys is called. These keys should be set AFTER the keys
+% listed in the current argument of \setkeys are set, provided
+% that these keys aren't listed in the current argument of \setkeys.
+%
+% 3. The command \presetkeys of the xkeyval package expects both
+% 'head' and 'tail'. The skeyval package splits \presetkeys into two,
+% hopefully less confusing, commands: \skvpresetkeys and
+% \skvpostsetkeys.
+%
+% 4. There is also command \skvpreposetkeys, which combines
+% \skvpresetkeys and \skvpostsetkeys. This expects both head and
+% tail and is equivalent to xkeyval's \presetkeys.
+
+\skvpresetkeys[SKVT]{shadowbox}{%
+ put frame,framecolor=black,framesize=.8pt,boxwidth=1.5cm,align=center,
+ shadecolor=gray!15
+}
+
+\skvpostsetkeys[SKVT]{shadowbox}{%
+ shadow=.use value{put frame},shadowcolor=.use value{framecolor}!40,
+ shadowsize=\dimexpr.use value{framesize}*5\relax
+}
+
+\newcommand*\newshadowbox[2][]{%
+ \skvsetkeys[SKVT]{shadowbox}{#1}%
+ \begingroup
+ \ifshb@putframe
+ \fboxrule=\dimexpr\currfboxrule\relax
+ \else
+ \fboxrule=0pt
+ \fi
+ \ifshb@shadow\else\shadowspread=0pt \fi
+ \sbox\z@{\fcolorbox{\shb@framecolor}{\shb@shadecolor}{%
+ \hb@xt@\shb@boxwidth{\curralign{#2}}%
+ }}%
+ \hskip\shadowspread
+ \color{\shb@shadowcolor}%
+ \rule[-\dp0]{\wd0}{\dimexpr\ht0+\dp0\relax}%
+ \llap{\raisebox{\shadowspread}{\box0\hskip\shadowspread}}%
+ \endgroup
+}
+
+%%++++++++++++++++++++++++ The \directkeys command ++++++++++++++++++++%%
+
+% The following are meant to demonstrate the use of the macro \directkeys:
+
+\ifdefined\skvtestcnt
+ \skvtestcnt\z@
+\else
+ \newcount\skvtestcnt
+\fi
+\def\logsetting{%
+ \advance\skvtestcnt\@ne
+ \typeout{'\skvcurrentkey' set: no.
+ \ifnum\skvtestcnt<10 0\fi\the\skvtestcnt, %
+ path: \skvcurrentprefix/\skvcurrentfamily}%
+}
+
+\directkeys{%
+ % #1 will be the user-value of the handler 'some handler'.
+ .new handlers = {
+ .some handler=\def\x##1{##1*#1},
+ .phantom handler=,
+ },
+ .handler let = {
+ .another handler=.some handler,
+ .do nothing handler=.phantom handler
+ },
+ .kill handlers={
+ .another handler,
+ .do nothing handler
+ },
+ .define handlers={
+ .j handler=\def\x##1{##1*#1},
+ .j handler=\def\y##1{##1*#1},
+ },
+ .define narg handlers={
+ .j1 handler={2}{\def\x##1{##1*#1*#2}},
+ .j2 handler={3}{\def\x##1{##1*#1*#2*#3}}
+ },
+ .new narg handlers={
+ % Error: handler j1 already exists:
+ % .j1 handler={2}{\def\x##1{##1*#1*#2}},
+ .k handler={2}{\def\x##1{##1*#1*#2}},
+ .l handler={3}{\def\x##1{##1*#1*#2*#3}}
+ },
+ .reserve handlers={reservedx , reservedy},
+ .holder prefix = mp@,
+ .prefix = KV,
+ .families = {fam1, fam2},
+ .add family = {fam3},
+ .add families = {fama,famb,famc},
+ .ignore families = {fama,famb,famc},
+ .restore families = {fama,famb},
+ .restore paths = {KVA/fama,KVD/famc},
+% .ignore keys = {keyb,keyc},
+ .new keys = {
+ .ord/keya/keya-default,
+ .cmd/keyb/keyb-default/\def\x##1{##1#1},
+ .cmd/keyc/keyc-default,
+ .choice*/keyd/center
+ /{ right.do=\def\val@r{#1},
+ left.do=\def\val@l{#1},
+ center.do=\def\val@c{#1}
+ }
+ /\def\yes{value accepted}
+ /\def\no{value rejected},
+ .bool/keye/true/
+ \ifskvindef\else\logsetting\fi
+ \ifmp@keye\def\y##1{##1#1}\fi
+ ,
+ .bool/keyf/true/,
+ .bool/keyg/true/
+ },
+ .push path,
+ .path = KV/fam1,
+ .set keys = {keyd},
+ .pop path,
+ .ignore keys = {keyb,keyc},
+ % Stop processing this list:
+ % .list break,
+ .restore keys = {keyb,keyc},
+ .preset keys = {keyb,keyc},
+ .postset keys = {keyb,keyc},
+ % Save unknown keys in the default macro \<pref>@<fam>@rmkeys:
+ .save unknown keys = true,
+ .save unknown keys in = \macroa,
+ .set keys = {keya,keyb,keyc,keyd,keye},
+ .set keys = {keya=keya-value,keyb=\def\y####1{####1}},
+ .set keys* = {keya=keya-value,keyf},
+ .set keys* = {keya=keya-value,keyf},
+ .ignore keys = {keyf},
+ .set rmkeys*,
+ % Execute arbitrary code:
+ .exec code=\def\x#1{#1},
+ % Nesting of \directkeys is possible. Pre-entry and post-entry
+ % topologies are independent. At the end of the nest,
+ % prevailing variables of \directkeys revert to their previous
+ % (pre-door) values:
+ \directkeys{
+ .paths = {KVA/fam3,KVB/fam3},
+ .holder prefix = hp@,
+ .define keys = {
+ .cmd/keya/keya-default/\def\x##1{##1#1},
+ .ord/keyb/keyb-default,
+ },
+ .set keys = {keya=vala},
+ },
+ .exec code = \def\keycval{true},
+ % Prepend slot keye to key1 and key2:
+ .prepend slot={key1/{keye=.expanded{\keycval}},key2/{keye=false}},
+ % Multi-prepend slots:
+ .prepend slot={{key3,key4}/{keye=true,keyf=true},key5/{keye=false}},
+ % Prepend slot keyd to key6:
+ .prepend slot={key6/{keyd=right}},
+ % Append slots keye and keyf to key7 and key8.
+ % '.slots' and '.slot' are equivalent to '.append slots'
+ % and '.append slot'.
+ .append slot={key7/{keye=true},key8/{keyf=false}},
+ % The next two link keyb and keyc to key9. #1 here refers to the
+ % current value of key9. The same effect can be achieved directly
+ % via the '.link' handler:
+ .prepend slot={key9/{keyb=#1}},
+ .append slot={key9/{keyc=#1}},
+ .set keys = {key9=val9},
+ % Link keye and keyf to key10 and key11. The values of key10 and
+ % key11 are used to set keye and keyf. key10 and key11 are hence
+ % 'parent keys'.
+ .link = {key10/keye, {key11,key12}/{keyf,keyg}},
+ .set keys = {key10=true},
+ .ignore key = keyf,
+ .save unknown keys in = \macrob,
+ .setkeys = {keya,keyb,keyf},
+ .disable keys = {keye,keyf},
+}
+
+%%++++++++++++++++++++++ Collecting body of environment +++++++++++++++++%%
+
+\skvmakekeys[
+ .prefix=KV,
+ .family=collectbody,
+ .hp=mp,
+ .initialize,
+ .endlinechar=-1
+]{%
+ .cmd/title//,
+ .zcmd/title scale/1,
+ .zcmd/body scale/1,
+ .cmd/width/\textwidth,
+ .zcmd/title text style//,
+ .zcmd/body text style//,
+ .cmd/action//
+}
+
+\newsavebox{\boxbody}
+\newenvironment{collectbody}[1][]{%
+ \skvusekeys[.prefix=KV,.family=collectbody]{#1}%
+ \ifx\mptitle\@empty\else\skvafterfi
+ \begin{center}%
+ \scalebox{\mptitlescale}{\mptitletextstyle\mptitle}%
+ \end{center}%
+ \fi
+ \begin{lrbox}{\boxbody}%
+ \begin{minipage}{\mpwidth}%
+ \mpbodytextstyle\mpaction
+}{%
+ \end{minipage}%
+ \end{lrbox}%
+ \scalebox{\mpbodyscale}{\usebox{\boxbody}}%
+}
+
+
+%%+++++++++++++++++++++ Changing the key parser ++++++++++++++++++++%%
+
+\setupskeyval{key parser={;}}
+\skvafterdefinekeys{\setupskeyval{keyparser={,}}}
+\skvdefinekeys*[SKVT]{example}[exm@]{%
+ .zbool/put frame/true;
+ .cmd/shadecolor/green;
+ .ord/framesize/.5pt/\def\currfboxrule{#1};
+ .choice/align/center/{%
+ center.do=\def\curralign##1{\hfil##1\hfil},
+ right.do=\def\curralign##1{\hfill##1},
+ left.do=\def\curralign##1{##1\hfill},
+ justified.do=\let\curralign\@iden
+ };
+}
+
+%%++++++++++++++++++++++++++ Options section ++++++++++++++++++++++%%
+
+\def\skvtp@unknownoptions{}
+
+\skvunknownoptionhandler[SKVT]<abrtext,shadowbox,citation,testpkg>{%
+ \edef\skvtp@unknownoptions{%
+ \skvtp@unknownoptions\ifx\skvtp@unknownoptions\@empty\else,\fi
+ #3%
+ }%
+ \AtEndDocument{%
+ \ifx\skvtp@unknownoptions\@empty\else
+ \PackageWarningNoLine{skeyval-testpkg}
+ {Unknown keys: \skvtp@unknownoptions}%
+ \fi
+ }%
+}
+\skvexecuteoptions[SKVT]<abrtext>{align=.expanded{\alignval},
+ text style=.expand once{\stextstyle},author,show author
+}
+
+\skvprocessoptions*+[SKVT]<abrtext,shadowbox,citation,testpkg>\relax
+%\skvrestrictedprocessoptions*+[SKVT]<abrtext,shadowbox,citation,testpkg>\relax
+
+\skvcomment
+Here you could also use:
+
+\directkeys{
+ .mega process options*={
+ .prefix=SKVT,
+ .families={abrtext,shadowbox,citation,testpkg},
+ }
+}
+
+or
+
+\directkeys{
+ .prefix=SKVT,
+ .families={abrtext,shadowbox,citation,testpkg},
+ .copy class options and process options in all families,
+}
+\endcomment
+
+\endinput
diff --git a/macros/latex/contrib/skeyval/tex/skeyval-view.sty b/macros/latex/contrib/skeyval/tex/skeyval-view.sty
new file mode 100644
index 0000000000..a09335b6b0
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval-view.sty
@@ -0,0 +1,425 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval-view.sty', version 1.3, 2013/05/15. %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode044 12 % ,
+\def\skv@prova{\endgroup
+ \def\do##1,{%
+ \ifx\do##1\else
+ \catcode##1\string=\the\catcode##1\relax
+ \expandafter\do
+ \fi
+ }%
+ \edef\skv@view@restorecodes{\do35,64,123,125,61,59,13,\do,}%
+}
+\skv@prova
+
+\edef\skv@view@restorecodes{%
+ \unexpanded\expandafter{\skv@view@restorecodes}%
+ \endlinechar\the\endlinechar\relax
+}
+\endlinechar13 %
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode061 12 % =
+\catcode044 12 % ,
+\def\do#1=#2,{%
+ \ifx\do#1\else
+ \edef\skv@view@restorecodes{%
+ \unexpanded\expandafter{\skv@view@restorecodes}%
+ \catcode#1=\the\catcode#1\relax
+ }%
+ \catcode#1=#2\relax
+ \expandafter\do
+ \fi
+}
+\do 032=10,033=12,036=03,038=04,040=12,041=12,042=12,043=12,%
+ 059=12,045=12,047=12,058=12,063=12,091=12,093=12,126=13,\do=,%
+
+\NeedsTeXFormat{LaTeX2e}[2011/06/27]
+\ProvidesPackage{skeyval-view}
+ [2013/05/15 v1.3 Viewer utility for skeyval package (AM)]
+\@ifpackageloaded{skeyval}{}{\RequirePackage{skeyval}}
+\directkeys*{%
+ .path=SKVV/skvview,
+ .holder prefix=skvv@,
+ .initialize keys after define=false,
+ .every unknown option={
+ \PackageWarning{skeyval-view}{Unknown option '\CurrentOption' ignored}%
+ },
+ .new options={
+ % LaTeX's options processor will zap the option names. So these keys
+ % can't have spaces between their parts.
+ .ord/{xcolor-options,load-xcolor-with}//
+ \edef\skvv@xcoloroptions{\unexpanded{#1}}
+ \skvstripouterbraces{1}\skvv@xcoloroptions,
+ .bool/tabulate/true
+ },
+ .execute options={
+ tabulate=true,xcolor-options=false,load-xcolor-with=false
+ },
+ .copy class options and process options
+}
+\skvnewregisters\toks{\skvv@toksa}
+\AtEndOfPackage{%
+ \let\ifskvv@tempsw\ifskvv@tabulate
+ \skvv@tabulatefalse
+ \skvdisablekeys[SKVV]{skvview}{xcolor-options,load-xcolor-with}%
+ \let\ifskvv@tabulate\ifskvv@tempsw
+}
+
+\@ifpackageloaded{longtable}{}{\RequirePackage{longtable}}
+\@ifpackageloaded{xcolor}{}{\RequirePackage[\skvv@xcoloroptions]{xcolor}}
+\skvnewbools[skvv@]{colii,coliii,coliv,colv}
+\newwrite\skvv@out
+\skvnewnumbers[skvv@]{depth,nra}
+
+\directkeys*{
+ .path=SKVV/skvview,
+ .holder prefix=skvv@,
+ .initialize keys after define=false,
+ .define keys={
+ .ord/{file,wcolsep,weol}/\@nil/
+ \skvcsedef{skvv@\skvcurrentkey}{\unexpanded{#1}}
+ \skvaftercsname{\skvstripouterbraces{1}}{skvv@\skvcurrentkey}
+ \skvaftercsname\skvdespacecontent{skvv@\skvcurrentkey}
+ ,
+ .ord/{prefix,family,type,default,columns}/\@nil/
+ \skvcsedef{skvv@\skvcurrentkey}{\unexpanded{#1}}
+ \skvaftercsname{\skvstripouterbraces{1}}{skvv@\skvcurrentkey}
+ \skvaftercsname\skvcsvnormalize{skvv@\skvcurrentkey}
+ ,
+ .bool/{view,vlabels,wlabels}/true,
+ .ord/length of default/20/\def\skvv@lengthofdefa{#1},
+ .cmd/color/black,
+ },
+ .set keys={
+ prefix,family,type,default,file,columns,wcolsep=&,weol=\\,
+ view,vlabels=false,wlabels=false,color,length of default
+ },
+ .links={
+ show/view,
+ key type/type,
+ {prefixes,only those with prefix,only those with prefixes}/prefix,
+ {families,only those in family,only those in families}/family,
+ {defaults,only those with default,only those with defaults}/default,
+ view output/view,
+ write to file/file,
+ {view labels,show labels}/vlabels,
+ {view wlabels,show wlabels}/wlabels,
+ wend of line/weol,
+ wcolumn separation/wcolsep,
+ word length of default/length of default
+ },
+ .style={
+ only those without default/default=[none],
+ },
+}
+
+% Use \setupviewkeys to change viewing specifications without actually
+% displaying (or writing to file) the key list:
+%
+\skvrobustdef*\setupviewkeys{\skvsetkeys[SKVV]{skvview}}
+
+\let\skvv@db\@empty
+\skvrobustdef*\skvv@dotabulate#1#2#3{%
+ \ifskvv@tabulate
+ \begingroup
+ \edef\skv@tempa{\detokenize{#3}}%
+ \skv@getshortformofcontent\skvv@lengthofdefa\skv@tempa\skv@ival
+ \skvxaddtolist{,}\skvv@db{%
+ #1=\ifx\skvcurrentprefix\@empty\else
+ \skvcurrentprefix\fi=\skvcurrentfamily=#2=\skv@ival
+ }%
+ \skvaftergroupdef\skvv@db\endgroup
+ \fi
+}
+\protected\def\skv@ordkey@a#1#2[#3]#4{%
+ \skvifstrcmpTF{#3}{^skv^}{%
+ \skvv@dotabulate{#2}{ordinary}{[none]}%
+ }{%
+ \skv@definedefault{#2}{#3}%
+ \skvv@dotabulate{#2}{ordinary}{#3}%
+ }%
+ % Pointers on key #2 have been stripped in \skv@ordkey.
+ % 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
+ }%
+}
+\protected\def\skv@cmdkey#1#2[#3]#4{%
+ \skv@strippointersfromkey{#2}%
+ \skvifdefboolTF{skv@st}{%
+ \skv@definedefault\skvcurrentkey{#3}%
+ \skvv@dotabulate\skvcurrentkey{command}{#3}%
+ }{%
+ \skvv@dotabulate\skvcurrentkey{command}{[none]}%
+ }%
+ % 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}}%
+ \skvcsedef{\skv@header\skvcurrentkey.@cbk}{%
+ \skvcslet{\skv@prova}\noexpand\skvcurrentvalue
+ \unexpanded{#4}%
+ }%
+}
+\protected\def\skv@choicekey@g{%
+ \skvcommaparse*\skv@currlist\skv@prova{%
+ \skvexpbracenext\skv@strippointersfromkey\skv@prova
+ \ifx\skv@default\skv@rej
+ \skvv@dotabulate\skvcurrentkey{choice}{[none]}%
+ \else
+ \skvexpanded{%
+ \noexpand\skvv@dotabulate
+ {\skvxonce\skvcurrentkey}{choice}{\skvxonce\skv@default}%
+ \noexpand\skv@definedefault
+ {\skvxonce\skvcurrentkey}{\skvxonce\skv@default}%
+ }%
+ \fi
+ \skvcsedef{\skv@header\skvcurrentkey.@cbk}{%
+ \skvcslet{\skv@hp\skvcurrentkey}\noexpand\skvcurrentvalue
+ \the\skv@temptoks
+ }%
+ }%
+}
+\protected\def\skv@boolkey@c#1#2#3#4{%
+ \if\skv@typetogkey
+ \skvdeftog{\skv@zapornot{\skv@zapsw}{#2}}%
+ \else
+ \skvcsnewif{\skv@zapornot{\skv@zapsw}{#2}}%
+ \fi
+ \skvifdefboolTF{skv@st}{%
+ \skv@definedefault{#1}{#3}%
+ \skvv@dotabulate{#1}{\if\skv@typetogkey toggle\else bool\fi}{#3}%
+ }{%
+ \skvv@dotabulate{#1}{\if\skv@typetogkey toggle\else bool\fi}{[none]}%
+ }%
+ \edef\skv@tempa##1##2{%
+ \noexpand\skv@sttrue
+ \ifskv@pl\noexpand\skv@pltrue\else\noexpand\skv@plfalse\fi
+ \skv@checkchoice[\noexpand\skv@value]{##1}{true,false}##2%
+ }%
+ \skv@temptoks\expandafter{\skv@tempa{##1}{#4}}%
+ \skvcsedef{\skv@header#1.@cbk}{\the\skv@temptoks}%
+}
+% #2=styles, #3=default, #4=callback
+\protected\def\skv@appendslots@a#1#2[#3]#4{%
+ \skvcommaparse{#1}\skv@prova{%
+ \skvexpbracenext\skv@strippointersfromkey\skv@prova
+ \skvexpanded{%
+ \skvifstrcmpTF{#3}{^skv^}{%
+ % When using \skvaddslots, signal keys will otherwise be added
+ % in the database twice (while treating prepended and appended
+ % slots).
+ \ifskv@addslots@appending\else
+ \skvv@dotabulate{\skvcurrentkey}{slot/style}{[none]}%
+ \fi
+ }{%
+ \skv@definedefault{\skvcurrentkey}{\unexpanded{#3}}%
+ \ifskv@addslots@appending\else
+ \skvv@dotabulate{\skvcurrentkey}{slot/style}{\unexpanded{#3}}%
+ \fi
+ }%
+ \skv@appendslots@b{\skvcurrentkey}\unexpanded{{#2}{#4}}%
+ }%
+ }%
+}
+
+\skvbuildmacrostack\skvv@state{%
+ \do\skvv@prefix\do\skvv@family\do\skvv@type\do\skvv@default
+ \do\skvv@file\do\skvv@columns\do\skvv@wcolsep\do\skvv@weol
+ \do\skvv@color\do\ifskvv@view\do\ifskvv@vlabels\do\ifskvv@wlabels
+}{2}
+
+\skvnewdef*\skvv@@view{%
+ \ifskvv@tabulate
+ 0\ifskvv@view 0\else 1\fi
+ \else
+ 01%
+ \fi
+}
+\skvrobustdef*\skvv@skvview#1{%
+ \skvsetkeys[SKVV]{skvview}{#1}%
+ \ifx\skvv@default\@nnil\else\@onelevel@sanitize\skvv@default\fi
+ \ifx\skvv@columns\@nnil
+ \skvsetnumber\skvv@nra5\relax
+ \skvv@coliitrue\skvv@coliiitrue\skvv@colivtrue\skvv@colvtrue
+ \else
+ \skvsetnumber\skvv@nra\@ne
+ \skvxifinTF{,prefix,}{,\skvv@columns,}{%
+ \skvadvanceno\skvv@nra\@ne\skvv@coliitrue
+ }{%
+ \skvv@coliifalse
+ }%
+ \skvxifinTF{,family,}{,\skvv@columns,}{%
+ \skvadvanceno\skvv@nra\@ne\skvv@coliiitrue
+ }{%
+ \skvv@coliiifalse
+ }%
+ \skvxifinTF{,type,}{,\skvv@columns,}{%
+ \skvadvanceno\skvv@nra\@ne\skvv@colivtrue
+ }{%
+ \skvxifinTF{,key type,}{,\skvv@columns,}{%
+ \skvadvanceno\skvv@nra\@ne\skvv@colivtrue
+ }{%
+ \skvv@colivfalse
+ }%
+ }%
+ \skvxifinTF{,default,}{,\skvv@columns,}{%
+ \skvadvanceno\skvv@nra\@ne\skvv@colvtrue
+ }{%
+ \skvv@colvfalse
+ }%
+ \fi
+ \if\skvv@@view
+ \protected@edef\skv@prova{%
+ \noexpand\begin{longtable}[l]{*\skvv@nra l}%
+ \\\noexpand\hline
+ \normalfont Key
+ \ifskvv@colii&\normalfont Prefix\fi
+ \ifskvv@coliii&\normalfont Family\fi
+ \ifskvv@coliv&\normalfont Type\fi
+ \ifskvv@colv&\normalfont Default\fi
+ \\\noexpand\hline
+ \noexpand\endfirsthead\noexpand\multicolumn{\skvv@nra}{l}{%
+ \normalfont\emph{Continued from previous page}}%
+ \\\noexpand\hline
+ \normalfont Key
+ \ifskvv@colii&\normalfont Prefix\fi
+ \ifskvv@coliii&\normalfont Family\fi
+ \ifskvv@coliv&\normalfont Type\fi
+ \ifskvv@colv&\normalfont Default\fi
+ \\\noexpand\hline\noexpand
+ \endhead\noexpand\hline
+ \noexpand\multicolumn{\skvv@nra}{r}{%
+ \normalfont\emph{Continued on next page}}%
+ \\\noexpand\endfoot\noexpand\hline
+ \noexpand\endlastfoot
+ }%
+ \skvv@toksa\expandafter{\skv@prova}%
+ \fi
+ \ifx\skvv@file\@nnil\else
+ \immediate\openout\skvv@out\skvv@file
+ \fi
+ \skvcommaloop*\skvv@db\skv@prova{%
+ \skv@swatrue
+ \expandafter\skvv@skvview@a\skv@prova\skv@nil
+ }%
+ \if\skvv@@view
+ \skvaddtotoks\skvv@toksa{\end{longtable}}%
+ \begingroup
+ \color{\skvv@color}%
+ \ttfamily\the\skvv@toksa
+ \endgroup
+ \fi
+ \ifx\skvv@file\@nnil\else\immediate\closeout\skvv@out\fi
+}
+\skvnewdef*\skvv@skvview@a#1=#2=#3=#4=#5\skv@nil{%
+ \skvv@ifin{#2}\skvv@prefix
+ \skvv@ifin{#3}\skvv@family
+ \skvv@ifin{#4}\skvv@type
+ \skvv@ifin{#5}\skvv@default
+ \ifskv@swa
+ \if\skvv@@view
+ \edef\skv@prova{%
+ #1\ifskvv@colii&#2\fi\ifskvv@coliii&#3\fi
+ \ifskvv@coliv&#4\fi\ifskvv@colv&#5\fi
+ \ifskvv@vlabels\noexpand\label{#2/#3/#1}\fi
+ }%
+ \skvoaddtotoks\skvv@toksa{\skv@prova\\}%
+ \fi
+ \ifx\skvv@file\@nnil\else
+ \immediate\write\skvv@out{%
+ #1\ifskvv@colii\skvv@wcolsep#2\fi
+ \ifskvv@coliii\skvv@wcolsep#3\fi
+ \ifskvv@coliv\skvv@wcolsep#4\fi
+ \ifskvv@colv\skvv@wcolsep#5\fi
+ \ifskvv@wlabels\string\label{#2/#3/#1}\fi
+ \skvexpandonce\skvv@weol
+ }%
+ \fi
+ \fi
+}
+\skvrobustdef*\skvv@ifin#1#2{%
+ \ifx#2\@nnil\else
+ \skvxifinTF{,\detokenize{#1},}{,\skvoxdetok{#2},}{}\skv@swafalse
+ \fi
+}
+\directkeys*{
+ .path=SKVV/skvvshow,
+ .holder prefix=skvvs@,
+ .initialize keys after define,
+ .new keys={
+ .ord/{.show,.show table}//
+ \skvifdefboolTF{skvindef}{}{
+ \edef\skvvs@show{\unexpanded{#1}}
+ \skvstripouterbraces{2}\skvvs@show
+ \ifx\skvvs@show\@empty\else\skvafterfi
+ \skvpushstate\skvv@state\skvv@depth
+ \skvexpbracenext\skvv@skvview\skvvs@show
+ \skvpopstate\skvv@state\skvv@depth
+ \fi
+ },
+ .ord/.exec code/\@nil/
+ \edef\skvvs@execcode{\unexpanded{#1}}
+ \ifx\skvvs@execcode\@nnil\else
+ \expandafter\skvvs@execcode
+ \fi
+ },
+}
+
+\skvrobustdef*\skvviewkeys{\skvsetkeys[SKVV]{skvvshow}}
+\skvnewlet\skvshowkeys\skvviewkeys
+
+\skv@view@restorecodes
+\endinput
+
+%% End of file 'skeyval-view.sty'.
diff --git a/macros/latex/contrib/skeyval/tex/skeyval.sty b/macros/latex/contrib/skeyval/tex/skeyval.sty
new file mode 100644
index 0000000000..0bd5722fca
--- /dev/null
+++ b/macros/latex/contrib/skeyval/tex/skeyval.sty
@@ -0,0 +1,971 @@
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+% This is file 'skeyval.sty', version 1.3, 2013/05/15. %
+% %
+% NOTE %
+% %
+% Beginning from version 1.0, 2012/09/01, the skeyval package has changed %
+% radically. Users of pre-version 1.0 of the package can load it now by %
+% calling: %
+% %
+% \usepackage[compatibility]{skeyval} %
+% \RequirePackage[compatibility]{skeyval} %
+% or %
+% \usepackage{skeyval-bc} %
+% \RequirePackage{skeyval-bc} %
+% %
+% LICENSE %
+% %
+% This package and accompanying files may be distributed and/or %
+% modified under the conditions of the LaTeX Project Public License, %
+% either version 1.3 of this license or any later version. The latest %
+% version of this license is in http://www.latex-project.org/lppl.txt %
+% and version 1.3 or later is part of all distributions of LaTeX %
+% version 2005/12/01 or later. %
+% %
+% The LPPL maintenance status of this software is 'author-maintained'. %
+% %
+% This software is provided 'as it is', without warranty of any kind, %
+% either expressed or implied, including, but not limited to, the %
+% implied warranties of merchantability and fitness for a particular %
+% purpose. %
+% %
+% DISTRIBUTION %
+% %
+% The following files constitute the skeyval bundle and must be %
+% distributed as a whole: %
+% %
+% README, skeyval.sty, skeyval-core.tex, skeyval-for.tex, %
+% skeyval-view.sty, skeyval-ltxpatch.sty, skeyval-ltxcmds.tex, %
+% skeyval-pstkey.sty, skeyval-pstkey.tex, skeyval-testclass.cls, %
+% skeyval-testpkg.sty, skeyval-pokayoke1, skeyval-pokayoke2, %
+% skeyval-view-pokayoke1. %
+% %
+% Copyright (c) 2010-2013 Ahmed Musa (amusa22@gmail.com). %
+%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
+
+\begingroup
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode044 12 % ,
+\def\skv@prova{\endgroup
+ \def\do##1,{%
+ \ifx\do##1\else
+ \catcode##1\string=\the\catcode##1\relax
+ \expandafter\do
+ \fi
+ }%
+ \edef\skv@restorecodes{\do35,64,123,125,61,59,13,\do,}%
+}
+\skv@prova
+
+\edef\skv@restorecodes{%
+ \unexpanded\expandafter{\skv@restorecodes}%
+ \endlinechar\the\endlinechar\relax
+}
+\endlinechar13 %
+\catcode035 06 % #
+\catcode064 11 % @
+\catcode123 01 % {
+\catcode125 02 % }
+\catcode061 12 % =
+\catcode044 12 % ,
+\def\do#1=#2,{%
+ \ifx\do#1\else
+ \edef\skv@restorecodes{%
+ \unexpanded\expandafter{\skv@restorecodes}%
+ \catcode#1=\the\catcode#1\relax
+ }%
+ \catcode#1=#2\relax
+ \expandafter\do
+ \fi
+}
+\do 032=10,033=12,036=03,038=04,040=12,041=12,042=12,043=12,%
+ 059=12,045=12,047=12,058=12,063=12,091=12,093=12,126=13,\do=,%
+
+\ProvidesPackage{skeyval}[2013/05/15 v1.3 Robust key-value parser (AM)]
+\NeedsTeXFormat{LaTeX2e}[2011/06/27]
+
+\input skeyval-core
+
+\skvrobustdef*\skvafterendpackage{%
+ \skvifcsdefTF{\@currname.\@currext-skv@endpkghook}{}{%
+ \@namedef{\@currname.\@currext-skv@endpkghook}{}%
+ }%
+ \expandafter\g@addto@macro
+ \csname\@currname.\@currext-skv@endpkghook\endcsname
+}
+\skvrobustdef*\skvafterpackage#1{%
+ \skvafterbegindocument{%
+ \skvifcsdefTF{ver@#1.\@pkgextension}{}{%
+ \skv@warn{Package '#1' was never loaded}%
+ }%
+ }
+ \skvifcsdefTF{ver@#1.\@pkgextension}{%
+ \@firstofone
+ }{%
+ \skvappendtomacro{#1.\@pkgextension-skv@endpkghook}%
+ }%
+}
+\xdef\@popfilename{%
+ \unexpanded{%
+ \csname\@currname.\@currext-skv@endpkghook\endcsname
+ \expandafter\let
+ \csname\@currname.\@currext-skv@endpkghook\endcsname\relax
+ }%
+ \unexpanded\expandafter{\@popfilename}%
+}
+\skvundef\skv@documentclass
+\skvrobustdef*\skv@getdocumentclass{%
+ \ifcase0%
+ \ifx\@filelist\@undefined 1\fi
+ \ifx\@filelist\relax 1\fi
+ \ifx\@filelist\@gobble 1\fi\relax
+ \skvcommaparse*\@filelist\skv@tempa{%
+ \filename@parse\skv@tempa
+ \ifx\filename@ext\@clsextension
+ \skvifcsdefFT{opt@\filename@area\filename@base.\filename@ext}{}{%
+ \edef\skv@documentclass{%
+ \filename@area\filename@base.\filename@ext
+ }%
+ }%
+ \fi
+ \ifx\skv@documentclass\@undefined\else\skvbreakloop\fi
+ }%
+ \fi
+}
+
+% The following packages need access to the original \@classoptionslist:
+\skvnewdef*\skv@optionprocessorpackages{%
+ xkeyval,kvoptions,catoptions,biblatex,pgfopts,ltxkeys%
+}
+% Filter class options to remove those with '=':
+\skvrobustdef*\skv@filterclassoptions{%
+ \ifcase0%
+ \ifx\@classoptionslist\@undefined 1\fi
+ \ifx\@classoptionslist\relax 1\fi\relax
+ \global\let\skv@filterclassoptions\relax
+ \skvkvnormalize\@classoptionslist
+ \let\skvoriginalclassoptionslist\@classoptionslist
+ \let\skv@classoptionslist\@classoptionslist
+ \let\@classoptionslist\@empty
+ \skvcommaloop*\skvoriginalclassoptionslist\skv@tempa{%
+ \skvxifinTF{=}{\skvexpandonce\skv@tempa}{}{%
+ \skvaddtolist*\@classoptionslist\skv@tempa
+ }%
+ }%
+ \def\@fileswith@ptions##1[##2]##3{%
+ \edef\skv@tempa{\unexpanded{##3}}%
+ \skvcsvnormalize\skv@tempa
+ \skvcommaloop*\skv@optionprocessorpackages\skv@prova{%
+ \skvxifinTF{,\skv@prova,}{,\skv@tempa,}{%
+ \let\@classoptionslist\skvoriginalclassoptionslist
+ \skvbreakloop
+ }{}%
+ }%
+ \skvifnextchar[{\@fileswith@pti@ns##1[##2]##3}%
+ {\@fileswith@pti@ns##1[##2]##3[]}%
+ }%
+ \fi
+}
+\skvrobustdef*\skvbeforebegindocument{%
+ \skvgappendtomacro\skv@beforebegindoc
+}
+\skvnewdef*\skv@beforebegindoc{}
+\skvprependtomacro\document{%
+ \endgroup
+ \let\skvbeforebegindocument\@firstofone
+ \skv@beforebegindoc
+ \gdef\skvbeforebegindocument{\skv@notprerr\skvbeforebegindocument}%
+ \global\let\skv@beforebegindoc\relax
+ \begingroup
+}
+\skvrobustdef*\skvafterbegindocument{%
+ \skvgappendtomacro\skv@afterbegindoc
+}
+\skvnewdef*\skv@afterbegindoc{}
+\skvgappendtomacro\document{%
+ \let\skvafterbegindocument\@firstofone
+ \skv@afterbegindoc
+ \gdef\skvafterbegindocument{\skv@notprerr\skvafterbegindocument}%
+ \global\let\skv@afterbegindoc\relax
+ \ignorespaces
+}
+\skvrobustdef*\skv@notprerr#1{%
+ \@latex@error{Command \detokenize{#1} should be used only
+ in preamble}\skv@ehd
+}
+\skvnewdef*\skv@everypagehook{}
+\skvrobustdef*\skvatbegineverypage{\skvgappendtomacro\skv@everypagehook}
+\skvafterbegindocument{%
+ \let\skv@savedoutputpage\@outputpage
+ \def\@outputpage{%
+ \let\skv@savedbegindvi\@begindvi
+ \def\@begindvi{%
+ \skv@everypagehook
+ \skv@savedbegindvi
+ }%
+ \skv@savedoutputpage
+ \let\@begindvi\skv@savedbegindvi
+ }%
+}
+
+\skvnewdef*\skv@preamblecmdhook{}
+\skvrobustdef*\skvonlypreamble#1{%
+ \def\skv@provb##1{%
+ \skvifntypeTF{##1}{}{%
+ \skv@err{More than one macro
+ \MessageBreak '\detokenize{##1}'.
+ \MessageBreak Maybe a comma is missing in the list}\skv@ehd
+ }%
+ \skvxifinTF{\detokenize{\do##1}}{\skvoxdetok\skv@preamblecmdhook}{%
+ \skv@warn{Command '\noexpand##1' multiply
+ \MessageBreak submitted to \string\skvonlypreamble: ignored}%
+ }{%
+ \xdef\skv@preamblecmdhook{%
+ \skvexpandonce\skv@preamblecmdhook\unexpanded{\do##1}%
+ }%
+ }%
+ }%
+ \skvcommaparse{#1}\skv@prova{%
+ \expandafter\skv@provb\expandafter{\skv@prova}%
+ }%
+}
+\AtEndOfPackage{%
+ \skvafterbegindocument{%
+ \def\do#1{%
+ \skvifdefTF#1{%
+ \gdef#1{\@latexerr{'\string#1' is a preamble command}\skv@ehd}%
+ }{%
+ \ifx\relax#1\else
+ \@@warning{Undefined command '\unexpanded{#1}'
+ \MessageBreak appeared in \string\skvonlypreamble.
+ \MessageBreak Only defined commands should be
+ \MessageBreak submitted to \string\skvonlypreamble.}%
+ \fi
+ }%
+ }%
+ \skv@preamblecmdhook
+ \let\skv@preamblecmdhook\relax
+ \let\do\relax
+ }%
+}
+
+%%+++++++++++++++++ Utilities for handling options ++++++++++++++++%%
+
+% \skvunknownoptionhandler[<prefixes>]<<families>>{<handler>}
+%
+\skvrobustdef*\skvunknownoptionhandler{%
+ \skv@testopt\skv@unknownoptionhandler\skvdefaultprefix
+}
+\skvrobustdef*\skv@unknownoptionhandler[#1]{%
+ \skvifnextchar<{\skv@unkn@wnoptionhandler{#1}}%
+ {\skv@unkn@wnoptionhandler{#1}<\@currname.\@currext>}%
+}
+\skvrobustdef*\skv@unkn@wnoptionhandler#1<#2>{%
+ \skv@unknownkeyhandler[#1]{#2}%
+}
+\skvrobustdef*\skv@testopte#1{\skv@testopta{\skv@t@stopte{#1}}}
+\skvrobustdef*\skv@t@stopte#1{\skv@testopt{\skv@t@st@pte{#1}}\skvdefaultprefix}
+\skvrobustdef*\skv@t@st@pte#1[#2]{%
+ % Only one prefix is allowed:
+ \skvxifinTF{,}{\detokenize{#2}}{%
+ \skv@err{Only one prefix is allowed, but you gave '#2'}\skv@ehd
+ }{%
+ \skv@makeprefix{#2}%
+ \skvifnextchar<{\skv@@t@st@pte{#1}}%
+ {\skv@@t@st@pte{#1}<\@currname.\@currext>}%
+ }%
+}
+\skvrobustdef*\skv@@t@st@pte#1<#2>{%
+ \edef\skv@fams{#2}%
+ \skvxifinTF{,}{\detokenize{#2}}{%
+ \skvcsvnormalize\skv@fams
+ }{%
+ \skvdespacecontent\skv@fams
+ }%
+ \skv@testopt{#1}{}%
+}
+
+\skvrobustdef*\skveveryunknownoption{\skvdeclareoption*}
+% \skvdeclareoption[<pref>]<<fam>>{<key>}[<defa>]{<callback>}
+% \skvdeclareoption*{<message>}
+\skvrobustdef*\skvdeclareoption{%
+ \let\@fileswith@pti@ns\@badrequireerror
+ \let\skvdefkey\skvordkey
+ \skvifstar\skv@dox\skv@dox@a
+}
+% \skvdeclarevoidoption[<pref>]<<fam>>{<key>}[<defa>]{<callback>}
+\skvrobustdef*\skvdeclarevoidoption{%
+ \let\@fileswith@pti@ns\@badrequireerror
+ \let\skvdefkey\skvvoidkey
+ \skv@dox@a
+}
+% \skvdeclareobsoleteoption
+% [<pref>]{<fam>}{<obsolete key>}{<new key>}[<defa>]{<callback>}
+\skvrobustdef*\skvdeclareobsoleteoption{%
+ \let\@fileswith@pti@ns\@badrequireerror
+ \let\skvdefkey\skvobsoletekey
+ \skv@dox@a
+}
+
+% \skvdeclarebooloption[<pref>]<<fam>>[<mp>]{<key>}[<defa>]{<callback>}
+\skvrobustdef*\skvdeclarebooloption{%
+ \let\@fileswith@pti@ns\@badrequireerror
+ \let\skvdefkey\skvboolkey
+ \skv@dox@a
+}
+% \skvdeclarecmdoption[<pref>]<<fam>>[<mp>]{<key>}[<defa>]{<callback>}
+\skvrobustdef*\skvdeclarecmdoption{%
+ \let\@fileswith@pti@ns\@badrequireerror
+ \let\skvdefkey\skvcmdkey
+ \skv@dox@a
+}
+
+% Our default action for unknown options is tied to \@currname
+% and \@currext:
+\skvrobustdef\skv@dox#1{%
+ \skvcsedef{skv@dox@\@currname.\@currext}{%
+ \unexpanded{%
+ \ifx\skvcurrentvalue\skv@novaluetoks
+ \def\skvcurrentvalue{no value}%
+ \fi
+ #1%
+ }%
+ }%
+}
+\skvrobustdef*\skv@dox@a{\skv@testopt\skv@dox@b\skvdefaultprefix}
+\skvrobustdef*\skv@dox@b[#1]{%
+ \skvifnextchar<{\skv@dox@c{#1}}{\skv@dox@c{#1}<\@currname.\@currext>}%
+}
+\skvrobustdef*\skv@dox@c#1<#2>{\skvdefkey[#1]{#2}}
+
+% Declare options with default values that will be used when the options
+% are called without user values.
+%
+% \skvdeclarepassedoptions[<pref>]{<fam>}{<option>=<default>,...}
+%
+% Example:
+%
+% \skvdeclarepassedoptions[KV]{fam}{%
+% hyperref={colorlinks,breaklinks},xcolor=svgnames
+% }
+%
+\skvrobustdef*\skvdeclarepassedoptions{%
+ \skv@testopt\skv@declarepassedoptions\skvdefaultprefix
+}
+\skvrobustdef*\skv@declarepassedoptions[#1]#2#3{%
+ \skvparsekvlist{#3}\skv@tempa{%
+ \skvexpbracenext\skv@kvsplit\skv@tempa{%
+ \skvdeclareoption[#1]<#2>{##1}[##2]{%
+ \skvifcsdefTF{ver@##1.sty}{%
+ \skv@warn{Package '##1' has been loaded and
+ \MessageBreak now you're passing options to it.
+ \MessageBreak Instruction ignored}%
+ }{%
+ \skvpassoptionstopackage{####1}{##1}%
+ \AtBeginDocument{%
+ \skvifpackageloadedTF{##1}{}{%
+ \skv@warn{Options were passed to package
+ \MessageBreak '##1' but it was never loaded}%
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+}
+% \skvpassoptionstopackage{<opts>}{<pkg>}
+\skvrobustdef*\skvpassoptionstopackage{\skv@passoptions{sty}}
+\skvrobustdef*\skvpassoptionstoclass{\skv@passoptions{cls}}
+\skvrobustdef*\skv@passoptions#1#2#3{%
+ \begingroup
+ \edef\@elt{opt@\skvtrimspace{#3}.#1}%
+ \skvcsxdef{\@elt}{%
+ \skvifcsdefFT{\@elt}{}{\@nameuse{\@elt},}%
+ \skvtrimspace{#2}%
+ }%
+ \endgroup
+}
+
+% Pass options to package and load the package after processing options.
+%
+% \skvdeclarepassedoptionsloadpackage
+% [<pref>]{<fam>}{<option>=<default>,...}
+%
+\skvrobustdef*\skvdeclarepassedoptionsloadpackage{%
+ \skv@testopt\skv@declarepassedoptions@load\skvdefaultprefix
+}
+\skvrobustdef*\skv@declarepassedoptions@load[#1]#2#3{%
+ \skvparsekvlist{#3}\skv@tempa{%
+ \skvexpbracenext\skv@kvsplit\skv@tempa{%
+ \skvdeclareoption[#1]<#2>{##1}[##2]{%
+ \skvifcsdefTF{ver@##1.sty}{%
+ \skv@warn{Package '##1' has been loaded and
+ \MessageBreak now you've asked for it to be
+ \MessageBreak loaded again. Instruction ignored}%
+ }{%
+ \skvafterprocessoptions{%
+ \RequirePackage[####1]{##1}%
+ }%
+ }%
+ }%
+ }%
+ }%
+}
+
+% \skvexecuteoptions[<pref>]<fams>[<na>]{<kvlist>}
+% \skvexecuteoptions+[<pref>]<fams>[<na>]{<kvlist>}
+%
+% This has no star (*) variant; any star suffix is quietly ignored.
+%
+\skvrobustdef*\skvexecuteoptions{%
+ \skv@testopte{\skv@stfalse\skv@setkeys@a}%
+}
+
+% \skvprocessoptions*+[<pref>]{<fams>}[<na>]
+%
+% 1. If not using LaTeX, then no processing of options.
+% 2. The plus (+) variant of \skvprocessoptions will process the options
+% in all the listed families. The star (*) form of \skvprocessoptions
+% -- like in LaTeX2e -- will also copy and use class options.
+% 3. Class options are always processed first, but class options that ocurr
+% also as local/package options are dropped from the list of options
+% to be processed. That is, package options always take priority over
+% class options.
+% 4. The \ProcessOptionsX of xkeyval package doesn't expect any plus (+)
+% suffix: it processes options only in a single family.
+%
+% 5. \skvpackagelist contains the list of loaded packages with their
+% options that are found on the current paths. See
+% <https://groups.google.com/forum/#!topic/comp.text.tex/XErNCMcT_jc>
+% for the rationale. Example:
+%
+% \usepackage[option1,option2]{foobar}
+% \show\skvpackagelist
+% \expandafter\show\csname foobar.sty.poxkeys\endcsname
+%
+\skvnewlet\skvpackagelist\@empty
+\skvrobustdef*\skvprocessoptions{%
+ \skv@getdocumentclass
+ \ifdefined\skv@documentclass
+ \global\let\skv@getdocumentclass\relax
+ \skv@filterclassoptions
+ \fi
+ \skv@testopte\skv@pox
+}
+\skvnewlet\skv@savprocessoptions\skvprocessoptions
+\skvrobustdef*\skv@badprocessoptions{%
+ \skv@testopte{%
+ \skv@err{\noexpand\skvprocessoptions can't be nested}\skv@ehd
+ }%
+}
+\skvrobustdef*\skv@pox[#1]{%
+ \skv@inpoxtrue
+ \let\@fileswith@pti@ns\@badrequireerror
+ \let\skvprocessoptions\skv@badprocessoptions
+ \begingroup
+ \edef\skv@userclassorpackage{\@currname.\@currext}%
+ \let\skv@classoptionsfound\@empty
+ \let\skv@classorpackageoptions\@empty
+ % The list of pox keys for each family, simply for taking
+ % pox keys outside the current scope:
+ \let\skv@exitpoxkeys\@empty
+ % The list of pox keys in all familes:
+ \let\skvcurrentpoxkeys\@empty
+ \ifx\skv@userclassorpackage\skv@documentclass
+ \skv@inclasstrue
+ \let\@unusedoptionlist\skv@classoptionslist
+ \else
+ \skv@inclassfalse
+ \ifcase0%
+ \ifx\skv@classoptionslist\@undefined 1\fi
+ \ifx\skv@classoptionslist\@empty 1\fi
+ \ifx\skv@classoptionslist\relax 1\fi\relax
+ \ifskv@st
+ \def\ifkeyundef##1##2##3{\skvexpanded{\skvifkeydefFT[##1]{##2}{##3}}}%
+ \skvcommaloop*\skv@classoptionslist\CurrentOption{%
+ \expandafter\expandafter\expandafter
+ \skv@g@tkeyname\CurrentOption=\skv@getname@nil\skvcurrentkey
+ % Test if key is defined in one of the families. The search will
+ % stop as soon as the key is found in any of the families.
+ \ifkeyundef\skvcurrentprefix\skv@fams\skvcurrentkey{}{%
+ \edef\skv@classoptionsfound{%
+ \skvaddlist,\skv@classoptionsfound\skvexpandonce\CurrentOption
+ }%
+ \expandafter\skv@removeoption\expandafter{\CurrentOption}%
+ }%
+ }%
+ \ifx\skv@classoptionsfound\@empty\else
+ \skvexpbracenext\skv@getnamesofkeys\skv@classoptionsfound\skv@tempd
+ \skvexpbracenext\skv@getpoxkeys\skv@tempd
+ \fi
+ \fi
+ \fi
+ \fi
+ \skvletcs\skv@classorpackageoptions{opt@\@currname.\@currext}%
+ \ifx\skv@classorpackageoptions\relax
+ \def\skv@classorpackageoptions{}%
+ \fi
+ \skvifemptyTF\skv@classorpackageoptions{}{%
+ \skvexpbracenext\skv@getnamesofkeys\skv@classorpackageoptions\skv@tempd
+ \skvexpbracenext\skv@getpoxkeys\skv@tempd
+ % Package options have higher priority than class options. Hence
+ % filter class options \skv@classoptionsfound that are also present
+ % as package options \skv@classorpackageoptions:
+ \skvifxTF\skv@userclassorpackage\skv@documentclass{}{%
+ \skvifemptyTF\skv@classoptionsfound{}{%
+ \skvcommaloop*\skv@classoptionsfound\CurrentOption{%
+ \expandafter\skv@g@tkeyname\CurrentOption=\skv@getname@nil\skv@tempa
+ \skvxifinTF{,\skvoxdetok\skv@tempa,}{,\skvoxdetok\skv@tempd,}{}{%
+ \edef\skv@classorpackageoptions{%
+ \skvaddlist,\skv@classorpackageoptions
+ \skvexpandonce\CurrentOption
+ }%
+ }%
+ }%
+ }%
+ }%
+ }%
+ % Get document class options that are on the current paths:
+ \ifx\skv@userclassorpackage\skv@documentclass
+ \def\skvclassoptionsfound{}%
+ \skvcommaloop*\skv@classorpackageoptions\skv@prova{%
+ \expandafter\skv@g@tkeyname\skv@prova=\skv@getname@nil\skvcurrentkey
+ \edef\skv@prova{[\skvcurrentprefix]{\skv@fams}{\skvcurrentkey}}%
+ \expandafter\skvifkeydefTF\skv@prova{%
+ \edef\skvclassoptionsfound{%
+ \skvaddlist,\skvclassoptionsfound\skvcurrentkey
+ }%
+ }{}%
+ }%
+ \else
+ \let\skvclassoptionsfound\skv@classoptionsfound
+ \fi
+ % \skvpackagelist is populated by all calls to \skvprocessoptions.
+ \skvletcs\skv@prova{\@currname.\@currext.poxkeys}%
+ \edef\skvpackagelist{%
+ \skvaddlist,\skvpackagelist
+ \skvifdefFT\skv@prova{}{\@currname.\@currext{\skv@prova}}%
+ }%
+ \let\do\skvcmdexit
+ \skvexpanded{\endgroup
+ \do\skvclassoptionsfound\do\skvcurrentpoxkeys
+ \do\skvpackagelist\do\@unusedoptionlist
+ \skvboolexit\ifskv@inclass\skv@exitpoxkeys
+ % There may be preset keys even when \skv@classorpackageoptions is empty:
+ \skvsetkeys\ifskv@pl+\fi[\skvcurrentprefix]{\skv@fams}[#1]%
+ {\skvexpandonce\skv@classorpackageoptions}%
+ }%
+ \skvcslet{skv@dox@\@currname.\@currext}\relax
+ \skv@inpoxfalse
+ \let\@fileswith@pti@ns\@@fileswith@pti@ns
+ \let\skvprocessoptions\skv@savprocessoptions
+ \AtEndOfPackage{\let\@unprocessedoptions\relax}%
+ \csname skv@\@currname.\@currext @afterprocess@hook\endcsname
+ \skvcslet{skv@\@currname.\@currext @afterprocess@hook}\relax
+}
+
+% \skvprocessoptionswithclassoptions*+[<pref>]{<fams>}[<na>]
+%
+% 1. The star (*) suffix is always assumed present, even when the
+% user hasn't put it.
+%
+\skvrobustdef*\skvprocessoptionswithclassoptions{%
+ \skv@testopte\skv@processoptionswithclassoptions
+}
+\skvrobustdef*\skv@processoptionswithclassoptions[#1]{%
+ \skv@sttrue\skv@pox[#1]%
+}
+
+% \skvprocessoptionswithoutclassoptions*+[<pref>]{<fams>}[<na>]
+%
+% 1. The star (*) suffix is always assumed absent, even when the
+% user has put it.
+%
+\skvrobustdef*\skvprocessoptionswithoutclassoptions{%
+ \skv@testopte\skv@processoptionswithoutclassoptions
+}
+\skvrobustdef*\skv@processoptionswithoutclassoptions[#1]{%
+ \skv@stfalse\skv@pox[#1]%
+}
+
+% \skv@getpoxkeys{<keys>}
+%
+% 1. Get pox keys (ie, keys processed as options) from package or
+% class options.
+% 2. This isn't a user command! See \skvgetdefinedkeys in file
+% skeyval-core.tex.
+\skvrobustdef*\skv@getpoxkeys#1{%
+ \begingroup
+ \skvcommaloop*\skv@fams\skvcurrentfamily{%
+ \skv@makeheader\skvcurrentfamily
+ % Prepare to take poxkeys outside the group:
+ \skvxifinTF{\skvoxdetok\skv@header}{\skvoxdetok\skv@exitpoxkeys}{}{%
+ \edef\skv@exitpoxkeys{%
+ \skvexpandonce\skv@exitpoxkeys
+ \noexpand\skvcsexit{\skvcurrentpath.@poxkeys}%
+ }%
+ }%
+ \edef\skv@prova{\@currname.\@currext.poxkeys}%
+ \skvxifinTF{\skvoxdetok\skv@prova}{\skvoxdetok\skv@exitpoxkeys}{}{%
+ \edef\skv@exitpoxkeys{%
+ \skvexpandonce\skv@exitpoxkeys\noexpand\skvcsexit{\skv@prova}%
+ }%
+ }%
+ \skvcommaloop{#1}\skvcurrentkey{%
+ \skvifcsdefFT{\skv@header\skvcurrentkey.@cbk}{}{%
+ \skvletcs\skv@prova{\skvcurrentpath.@poxkeys}%
+ \skvifdefTF\skv@prova{%
+ \skvxifinTF{,\skvcurrentkey,}{,\skv@prova,}{}{%
+ \skvcsedef{\skvcurrentpath.@poxkeys}{%
+ \skvaddlist,\skv@prova\skvcurrentkey
+ }%
+ }%
+ }{%
+ \skvcsedef{\skvcurrentpath.@poxkeys}{\skvcurrentkey}%
+ }%
+ \skvletcs\skv@prova{\@currname.\@currext.poxkeys}%
+ \skvifdefTF\skv@prova{%
+ \skvxifinTF{,\skvcurrentkey,}{,\skv@prova,}{}{%
+ \skvcsedef{\@currname.\@currext.poxkeys}{%
+ \skvaddlist,\skv@prova\skvcurrentkey
+ }%
+ }%
+ }{%
+ \skvcsedef{\@currname.\@currext.poxkeys}{\skvcurrentkey}%
+ }%
+ \skvxifinTF{,\skvcurrentkey,}{,\skvcurrentpoxkeys,}{}{%
+ \edef\skvcurrentpoxkeys{%
+ \skvaddlist,\skvcurrentpoxkeys\skvcurrentkey
+ }%
+ }%
+ }%
+ }%
+ }%
+ \let\do\skvcmdexit
+ \skvexpanded{\endgroup
+ \do\skvcurrentpoxkeys
+ % We need the list in \skv@exitpoxkeys outside the current scope.
+ % It will be used to take poxkeys (on each path) outside the scope
+ % in \skv@pox:
+ \do\skv@exitpoxkeys
+ % We need the poxkeys on each path outside the current scope:
+ \skv@exitpoxkeys
+ }%
+}
+
+% +++++++++ Utilities for handling options via \directkeys +++++++++%
+
+% \dirkeys@declareoptions{<star>}{<list>}
+%
+% <star>, if present, means new options.
+%
+\skvrobustdef*\dirkeys@declareoptions#1#2{%
+ \let\@fileswith@pti@ns\@badrequireerror
+ \begingroup
+ % The boolean skv@inopt differs from skv@inpox. skv@inopt is only
+ % meant to set the default family in \dirkeys@setdefaultpath
+ % when dealing with options.
+ \skv@inopttrue
+ \def\skv@tempa{}%
+ \edef\skv@tempb{\unexpanded{#2}}%
+ \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
+}
+% \dirkeys@executeoptions{<plus sign or empty>}{<kvlist>}
+%
+% 1. <no-plus> = Execute options on ONLY the first path found. If an
+% option isn't found on the given paths, report error (ie,
+% don't save the option to the list of 'remaining keys'). Unknown
+% options should be flagged by an error immediately. Hence no
+% star (*) form of \dirkeys@executeoptions.
+% 2. <plus> = Execute options on all the prevailing paths. If an
+% option isn't found on the given paths, flag error.
+%
+\skvrobustdef*\dirkeys@executeoptions#1#2{%
+ \begingroup
+ \skv@inopttrue
+ % If the number of families is greater than one, gnored keys
+ % from different families will mixed. This is the case even in
+ % \skvsetkeys.
+ \skvemptify{\skv@igkeys,\skv@fams}%
+ \@tempcnta\skvz@
+ \def\skv@pathdo##1##2{%
+ \advance\@tempcnta\@ne
+ \def\skv@pref{##1}%
+ \ifnum\@tempcnta=\@ne
+ \def\skv@firstpref{##1}%
+ \else
+ \ifx\skv@pref\skv@firstpref\else
+ \skv@err{You can't use multiple prefixes when
+ \MessageBreak calling the handler '.execute options'.
+ \MessageBreak Check your values of '.prefix' and '.paths'}\skv@ehd
+ \fi
+ \fi
+ \skvxifinTF{,##2,}{,\skv@fams,}{}{%
+ \edef\skv@fams{\skvaddlist,\skv@fams##2}%
+ }%
+ \skvletcs\skv@prova{##1/##2/.@ignoredkeys}%
+ \ifdefined\skv@prova
+ \edef\skv@igkeys{\skvaddlist,\skv@igkeys\skv@prova}%
+ \fi
+ }%
+ \dirkeys@pathlist
+ \ifx\skv@fams\@empty
+ \skv@err{No family before calling '.execute options'}\skv@ehd
+ \fi
+ \skvexpanded{\endgroup
+ \skvsetkeys#1[\skv@pref]{\skv@fams}[\skv@igkeys]%
+ }{#2}%
+}
+\skvrobustdef*\dirkeys@processoptions#1#2{%
+ \begingroup
+ \skv@inopttrue
+ % If the number of families is greater than one, gnored keys
+ % from different families will mixed. This is the case even in
+ % \skvprocessoptions.
+ \skvemptify{\skv@igkeys,\skv@fams}%
+ \@tempcnta\skvz@
+ \def\skv@pathdo##1##2{%
+ \advance\@tempcnta\@ne
+ \def\skv@pref{##1}%
+ \ifnum\@tempcnta=\@ne
+ \def\skv@firstpref{##1}%
+ \else
+ \ifx\skv@pref\skv@firstpref\else
+ \skv@err{You can't use multiple prefixes when
+ \MessageBreak calling the handler '.process options'.
+ \MessageBreak Check your values of '.prefix' and '.paths'}\skv@ehd
+ \fi
+ \fi
+ \skvxifinTF{,##2,}{,\skv@fams,}{}{%
+ \edef\skv@fams{\skvaddlist,\skv@fams##2}%
+ }%
+ \skvletcs\skv@prova{##1/##2/.@ignoredkeys}%
+ \ifdefined\skv@prova
+ \edef\skv@igkeys{\skvaddlist,\skv@igkeys\skv@prova}%
+ \fi
+ }%
+ \dirkeys@pathlist
+ \ifx\skv@fams\@empty
+ \skv@err{No family before calling '.process options'}\skv@ehd
+ \fi
+ \skvexpanded{\endgroup
+ \skvprocessoptions#1#2[\skv@pref]<\skv@fams>[\skv@igkeys]%
+ }%
+}
+
+% ++++++++ Keys for the handler <.mega process options> +++++++++ %
+
+\directkeys*{%
+ .path={SKV/megapox},
+ .holder prefix=dirkeys@pox@,
+ .initialize keys after define=true,
+ .new keys={
+ .ord/.ignore options//
+ \def\dirkeys@pox@igkeys{#1}
+ \skvstripouterbraces{2}\dirkeys@pox@igkeys
+ ,
+ .ord/{.prefix,.options prefix}/\skvdefaultprefix/
+ \skv@ifoneprefix{#1}{%
+ \edef\dirkeys@pox@pref{#1}
+ \skvstripouterbraces{2}\dirkeys@pox@pref
+ }{%
+ \skv@err{Only one prefix is allowed in
+ \MessageBreak processing options}\skv@ehd
+ }
+ ,
+ .ord/{.family,.families,.options families,.options family}/
+ \@currname.\@currext/
+ \edef\dirkeys@pox@fams{#1}
+ \skvstripouterbraces{2}\dirkeys@pox@fams
+ \skv@makepaths\dirkeys@pox@pref\dirkeys@pox@fams
+ \dirkeys@megapox@pathlist\skv@pathdo
+ ,
+ .ord/{path,.paths,.option path,.option paths}/
+ {KV/\@currname.\@currext}/
+ \skv@formatpaths{#1}\dirkeys@megapox@pathlist
+ ,
+ .ord/{.copy class options,.include class options}/true/
+ \edef\dirkeys@pox@copyclass{0\skvifstrcmpTF{#1}{true}{0}{1}}
+ ,
+ },
+}
+
+\skvnewnumbers[skv@]{megapoxdepth}
+\skvrobustdef*\dirkeys@megaprocessoptions#1{%
+ \skvpushfunctions\dirkeys@megapox{%
+ \do\dirkeys@pathlist\do\skv@pathdo\do\dirkeys@megapox@pathlist
+ \do\dirkeys@pox@igkeys\do\dirkeys@pox@copyclass
+ }\skv@megapoxdepth
+ \skvemptify{\dirkeys@megapox@pathlist,\dirkeys@pox@igkeys}%
+ \let\dirkeys@pox@pref\skvdefaultprefix
+ \def\dirkeys@pox@copyclass{01}%
+ \skvsetkeys[SKV]{megapox}{#1}%
+ \ifx\dirkeys@pox@igkeys\@empty
+ % So that all '...@ignoredkeys' will be undefined:
+ \let\dirkeys@pox@igkeys\undefined
+ \fi
+ \let\dirkeys@pathlist\dirkeys@megapox@pathlist
+ \def\skv@pathdo##1##2{%
+ \skvcslet{##1/##2/.@ignoredkeys}\dirkeys@pox@igkeys
+ }%
+ \dirkeys@pathlist
+ \skvexpanded{%
+ \dirkeys@processoptions\if\dirkeys@pox@copyclass*\fi{+}%
+ }%
+ \skvpopfunctions\dirkeys@megapox\skv@megapoxdepth
+}
+
+% +++++++++++++ Handlers for executing and processing options ++++++++++++ %
+
+\directkeys*{%
+ .new handlers={
+ {.action for unknown options,.action for unknown options}={
+ \let\@fileswith@pti@ns\@badrequireerror
+ \skv@dox{#1}
+ },
+ {.declare option,.declare options,.define option,.define options}={
+ \dirkeys@declareoptions{}{#1}
+ },
+ {.new option,.new options}={
+ \dirkeys@declareoptions{*}{#1}
+ },
+ {.execute options,.executeoptions,.execute options in one family}={
+ \dirkeys@executeoptions{}{#1}
+ },
+ {.execute options*,.executeoptions*}={
+ \skv@err
+ {Handler '.execute options*' is undefined}
+ {Handler '.execute options' has no star (*) variant,
+ \MessageBreak since we don't want to ignore unknown
+ \MessageBreak options from within package or class file.}%
+ },
+ {.execute options+,.executeoptions+,.execute options in all families}={
+ \dirkeys@executeoptions{+}{#1}
+ },
+ % 1. All <.process options> handlers will filter out ignored keys.
+ % 2. <.process options*> will copy class options.
+ {.process options,.processoptions,.process options in one family}={
+ \dirkeys@processoptions{}{}
+ },
+ {.process options*,.processoptions*,
+ .copy class options and process options,
+ .copy class options and process options in one family}={
+ \dirkeys@processoptions{*}{}
+ },
+ {.process options+,.processoptions+,.process options in all families}={
+ \dirkeys@processoptions{}{+}
+ },
+ {.process options*+,.processoptions*+,
+ .copy class options and process options in all families}={
+ \dirkeys@processoptions{*}{+}
+ },
+ % The handler <.mega process options> will:
+ % 1. Search all families in its key <paths>.
+ % 2. Not filter ignored paths and keys; in fact, it will not
+ % use active paths and keys.
+ % 3. The handler '.mega process options' has the keys <ignore options>,
+ % <options prefix>, <options families>, and <copy class options>.
+ % These keys have aliases.
+ % See an example later in this file.
+ {.mega process options,.megaprocessoptions}={
+ \dirkeys@megaprocessoptions{#1}
+ },
+ {.mega process options*,.megaprocessoptions*}={
+ \dirkeys@megaprocessoptions{#1,copy class options}
+ },
+ },
+ .handler let={
+ {.action for unknown option,.every unknown option}=
+ .action for unknown options,
+ },
+}
+
+% Loading a package while in options section is illegal. The command
+% \skvafterprocessoptions can be used to defer the loading of packages
+% till after the options section:
+\skvrobustdef*\skvafterprocessoptions{%
+ \expandafter\skvgappendtomacro
+ \csname skv@\@currname.\@currext @afterprocess@hook\endcsname
+}
+\skvnewlet\skvifpackageloadedTF\@ifpackageloaded
+
+\skvnewdef*\skv@visiteduseoptions{01}
+\skvrobustdef*\skv@removeoption#1{%
+ \ifx\@unusedoptionlist\@empty\else
+ \if\skv@visiteduseoptions\else
+ \skvcsvnormalize\@unusedoptionlist
+ \def\skv@visiteduseoptions{00}%
+ \fi
+ \begingroup
+ \skv@g@tkeyname#1=\skv@getname@nil\skv@tempb
+ \@onelevel@sanitize\skv@tempb
+ \def\skv@tempa{}%
+ \skvcommaloop*\@unusedoptionlist\skv@prova{%
+ \expandafter\skv@g@tkeyname\skv@prova=\skv@getname@nil\skv@provb
+ \@onelevel@sanitize\skv@provb
+ \ifx\skv@provb\skv@tempb\else
+ \edef\skv@tempa{\skvaddlist,\skv@tempa\skvexpandonce\skv@prova}%
+ \fi
+ }%
+ \let\@unusedoptionlist\skv@tempa
+ \skvaftergroupdef\@unusedoptionlist\endgroup
+ \fi
+}
+\skvonlypreamble{%
+ \skvdeclareoption,\skvexecuteoptions,\skvprocessoptions,\skv@removeoption,
+ \skveveryunknownoption,\dirkeys@declareoptions,
+ \dirkeys@megaprocessoptions,\dirkeys@processoptions,\dirkeys@executeoptions,
+ \skvprocessoptionswithclassoptions,\skvprocessoptionswithoutclassoptions
+}
+
+%+++++++++++++++++ This package's options section ++++++++++++++++++%
+
+\skvrobustdef*\setupskeyval{\skvsetkeys[SKV]{skeyval}}
+\skv@inoptionsectrue
+\directkeys*{%
+ .every unknown option={
+ \@onelevel@sanitize\CurrentOption
+ \PackageWarning{skeyval}{Unknown option '\CurrentOption' ignored}%
+ },
+ .path=SKV/skeyval,
+ .holder prefix=skv@,
+ .new options={
+ .bool/{verbose,tracingkeys}/true,
+ .ord/{keyparser,key parser}/{,}/
+ \def\skv@keyparser{#1}%
+ \skvstripouterbraces{2}\skv@keyparser,
+ .bool/compatibility/true/
+ \ifskv@compatibility
+ \skvafterprocessoptions{%
+ \skvifpackageloadedTF{skeyval-bc}{}{%
+ \RequirePackage{skeyval-bc}%
+ }
+ }%
+ \fi
+ ,
+ },
+ .execute options={
+ tracingkeys=false,keyparser,verbose=false
+ },
+ .mega process options={
+ .options prefix=SKV,
+ .options families={skeyval,definekeys},
+ .ignore options={},
+ .copy class options,
+ },
+}
+\skv@inoptionsecfalse
+
+\skv@restorecodes
+\endinput