\documentclass[a4paper,10pt,final,language=UKenglish,fancysec,fancyfnote]{amltxdoc}
\makeatletter
\let\sectionbreak\medbreak

\begin{document}

\begin{frontmatter}
\suptitle{}
\title{The \texttt{\color{blue}skeyval} Package\titleref{t1,t2}}
\titlenote[t1]{The \pkgm{skeyval} was formerly called the \pkgm{keyreader} until
version~0.5. The \asty{keyreader} is now obsolete and no longer supported.}
\iftogon{pdf}{%
  \titlenote[t2]{The package is available at \url{\@titleurl}.}%
}{%
  \titlenote[t2]{The package is available at \url{\@shorttitleurl}.}%
}
\subtitle{Version 0.71}
\titleurl{http://www.ctan.org/tex-archive/macros/latex/contrib/skeyval/}
\shorttitleurl{http://www.ctan.org/}
\author{Ahmed Musa\Email{a.musa@rocketmail.com}\\Preston, Lancashire, UK}

\NewLet\abstname\abstractname
\redef*\abstractname{\vspace{-\baselineskip}}
\begin{abstract}
\frameshade[width=\hsize,fillcolor=yellow!20,framesep=2pt,framerule=2pt,
  framecolor=brown]{%
  \frameshade[fillcolor=white,width=2.5cm,framecolor=red,framerule=2pt]%
  {\centering\abstname}\small
  This package supplements the \pkgm{xkeyval}. It introduces toggle keys and complementary (bipolar and unipolar) native-boolean and toggle-boolean keys. It also provides mechanisms for reserving, unreserving, suspending, restoring, and removing keys. Furthermore, it introduces a set of commands for key definition which bar the developer or user from inadvertently redefining existing keys of the same family and prefix. Commands are provided for checking the statuses of keys across multiple key prefixes and families. Also, the package provides a scheme for defining multiple keys of different genres using only one command, thereby making it possible to considerably economize on tokens when defining keys. The package introduces the notion of ``user-value keys'' and provides facilities for managing those keys. The pointer mechanisms of the \asty{xkeyval}, which were only available at key setting time, are now invocable at key definition. Some other general-purpose developer macros and hooks are provided by the package.
}
\end{abstract}

\NewLet\licname\licensename
\redef*\licensename{\vspace{-\baselineskip}}
\begin{license}
\frameshade[width=\hsize,fillcolor=white,framesep=2pt,framerule=2pt,
  framecolor=brown]{\small
  \vspace{1ex}\centerline{\licname}\endgraf
  This work (\ie, all the files in the \asty{skeyval} bundle) may be distributed and/or modified under the conditions of the \lppl (LPPL), either version~1.3 of this license or any later version.
  \endgraf
  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.
  \endgraf
  The package is now at open beta stage and package distributors are advised to wait for at least a stable version~1.0 before embarking on distribution. Bug reports and suggestions to improve the package are particularly welcome. Correspondents should use the file \asty{skeyval-bugreport.tex}, provided as part of the bundle, to report bugs.
  \endgraf\centerline{\makered{\CopyrightYear}}%
}
\end{license}
\end{frontmatter}

\newpage

\frameshade[fillcolor=yellow!20,framecolor=brown,framerule=2pt,framesep=2pt,
  width=1.1\hsize]{\tableofcontents}

\section{Motivation}
\label{sec:motivation}

\lletter{T}oggle booleans were introduced by the \pkgm{etoolbox} and have proved attractive mainly for two reasons: unlike the legacy/native \tex switches which require three commands per switch, toggles require only one command per switch, and toggles occupy their own separate namespace, thereby avoiding clashes with other macros. So we can effectively have both the following sets in the same file:
\begin{example}
|comm(Knuth/native switch:)
\newif\ifmyboolean    |tto  3 separate commands:
                          \ifmyboolean \mybooleantrue
                          \mybooleanfalse

|comm(Toggle switch:)
\newtog{myboolean}    |tto  only 1 command and no clash with
                          commands in other namespaces
\end{example}

\Note A toggle is also a boolean or switch. We refer to it here as \emph{toggle} or \emph{toggle switch} or \emph{toggle boolean}. The term \emph{Knuth/native switch} is reserved here for \tex's legacy boolean or switch.

The \pkg{xkeyval} can't be used to define and set toggle keys. The present package provides facilities for defining and setting toggle keys.

Secondly, the \pkg{xkeyval} can't be used to define and set complementary (bipolar and unipolar) keys, which can be handy in the case of native boolean and toggle keys. Complementary bipolar keys are mutually exclusive keys, \ie, they never assume the same state of a two-valued logic, and they switch states automatically, depending on the state of any one of them. So whenever one of them assumes one of the two states of a two-valued logic, the other one automatically switches its state from whatever state it was previously, such that the two are never in the same state. Simple examples of complementary bipolar keys would be the options \acmd{draft} and \acmd{final} in a document; they are mutually exclusive. Complementary bipolar keys carry equal charge, \ie, each one can equally toggle the other with identical propensity, but the one that represents the default state of a two-valued logic is usually considered the primary, while the other is secondary. In many document classes, for instance, \acmd{final} is considered a default document option and \acmd{draft} would have to be explicitly selected by the user to toggle \acmd{final} to false.

Complementary unipolar keys, on the other hand, are mutually inclusive, \ie, both are always in the same state of a two-valued logic: when one is switched to a particular state, the complement too is automatically toggled to the same state. An example of complementary unipolar keys would be the options \fx{hyperref} and \fx{microtype} in a package or class file. When \pkgm{hyperref} is loaded, we may want \pkgm{microtype} loaded as well, and vice versa. Complementary unipolar keys, like bipolar keys, also carry equal charge, \ie, one can toggle the other with equal propensity, but to the same state for the two keys. For a pair of unipolar keys, the primary key is the one that is associated with the default state.

The present package introduces these concepts of bipolar and unipolar keys and additionally permits the submission of individual/different custom key macros to complementary (bipolar and unipolar) native boolean and toggle keys. Biunipolar keys, which combines the two concepts of bipolar and unipolar keys, are introduced as well.

The third motivation for this package relates to economy of tokens in style files. The \pkg{xkeyval} provides \acmd{\define@cmdkeys} and \acmd{\define@boolkeys} for defining and setting multiple command keys and boolean keys, but in each category the keys must have the same default value and no key macro/function. This package seeks to lift these restrictions, so that multiple keys of all categories (ordinary keys, command keys, boolean keys, tog keys, and choice/menu keys) can be defined in one go (using only one command) and those keys can have different default values and functions. This greatly minimizes tokens, as hundreds of keys can, in principle, be issued simultaneously by one command.

Fourthly, macros are introduced for defining all key types without the fear of inadvertently redefining existing keys in the same family and with the same key prefix. This has a philosophy akin to the \acmd{\newcommand} concept in \LaTeX.

The package also provides facilities for disabling, suspending, restoring and removing keys across multiple families of keys. The pointer system of the \pkg{xkeyval} is also extended by the \pkg{skeyval}, and the notion of ``user-value'' keys is introduced and operationalized.

Normally when setting keys, the \pkg{xkeyval} terminates with an error message if any key in the list of keys to be set is currently undefined or unknown. This means that if you have a set of keys to set simultaneously and you misspell a few of them, you would have to make several passes to get all the keys right. The \pkg{skeyval} takes a different approach. For each call to \acmd{\setkeys},  it saves the names of undefined keys (and their associated families and prefixes) in a macro and issues an error message (together with the contents of that macro) if at the end of the call that macro is non-empty. Such undefined keys are not set in the pass. In this way, you can correct all wrongly entered keys in one go, rather than repeat the pass for each of them.

The new macros can be used together with the machinery from the \pkg{xkeyval} for efficient and versatile key management.

\section{Brace stripping by the \texttt{xkeyval} package}

The \pkg{xkeyval} strips off up to three levels of braces in the value part of the \acmd{key-value} pair: one by using the \pkgm{keyval}'s leading and trailing space removal command and two in internal parsings (at some known commands). The \asty{keyval} strips off only two levels of braces: one in using its space removal routine and one in internal parsings. The \pkgm{kvsetkeys} strips off only one level of braces. The matter of these differences has not yet been shown to have serious implications for existing or new packages, although it is apparently of concern to the \pkgm{keycommand}.

The \pkg{skeyval} internally uses a space removal scheme that doesn't strip off braces from its arguments, but since the present package relies, to a good extent, on the engine of the \pkg{xkeyval}, the brace stripping effect has remained. We have had to redefine a significant number of the internal macros of the \pkg{xkeyval}, but getting rid of the brace-stripping issue would require even more substantial revision of the internal macros of the \pkg{xkeyval}. It can easily be solved but there is currently no sufficient reason to do so. If, odd enough, you want at least one level of braces to persist in the value part of the \acmd{key-value} pair throughout parsing, you simply surround the value with four levels of braces in the \acmd{\setkeys} command. If the users of this, or the \pkg{xkeyval}, feel that this issue is of significant concern, then it can be addressed in the future.

\section{The \texttt{skeyval} package options}
\label{sec:loading-package}

The package can be loaded in style and class files by
\begin{example}
\RequirePackage[options]{skeyval}
\end{example}
and in document files via
\begin{example}
\usepackage[options]{skeyval}
\end{example}
where the user options and their default values are
\begin{macro}
keyparser=;, macroprefix=mp@, keyprefix=KV, keyfamily=fam,
verbose=false
\end{macro}
\acmdm*{keyparser,macroprefix,keyprefix,keyfamily,verbose}

The \ang{keyparser} is the separator between the keys in the key list to be defined in one go (see \cref{sec:multkeys-examples}). The \ang{macroprefix}, \ang{keyprefix}, and \ang{keyfamily} are, respectively, the macro prefix, key prefix and key family for all the keys to be defined upon the declaration of these options. All these options can be set or changed  dynamically by using the \acmdm{\skvoptions} macro:
\begin{macro}
\skvoptions{keyparser=;, macroprefix=mp@, keyprefix=KV,
  keyfamily=fam}
\end{macro}

These options are explained in more detail in subsequent sections.

If, as unlikely as it may seem, a clash arises between package and/or user macros as a result of the use of the defaults for \ang{macroprefix}, \ang{keyprefix} and \ang{keyfamily}, then the user will have to make his own choices for these defaults so as to avoid clashes.

The \pkg{skeyval} issues a fatal error if it is loaded before (or run without) \acmd{\documentclass}.

\section[Complementary native boolean keys]{Complementary native-boolean keys}
\label{sec:comp-boolkeys}

\subsection{Bipolar native-boolean keys}
\label{sec:biboolkeys}

As mentioned in \cref{sec:motivation}, complementary bipolar keys are keys that depend inversely on each other: when one of them is in a particular state of a two-valued logic, the other one automatically assumes the opposite or complementary state. For each pair of bipolar keys, one is normally assumed to be the primary key and the other the secondary. The primary boolean key will usually represent the default state of a two-valued logic. Whenever one bipolar key (primary or secondary) is true, its complement is automatically set false; and vice versa: when one bipolar key (primary or secondary) is false, its complement is automatically set true. Generally, the transition of the state of a key from negative (false) to positive (true) is associated with the execution of the key's macro.

The syntax for creating bipolar native-boolean keys is
\begin{macro}
\define@biboolkeys[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
  {|vang(primary boolean)}[|vang(default value for primary boolean)]
  {|vang(secondary boolean)}{|vang(func for primary boolean)}
  {|vang(func for secondary boolean)}
\end{macro}
\acmdm*{\define@biboolkeys}
This command is robust and can be used in expansion contexts, but expandable commands may need to be protected. When the user doesn't supply the \ang{keyprefix} and/or \ang{macroprefix}, the package will use \ang{KV} and \ang{mp@}, respectively. When the default value for the primary boolean is not supplied, the package will use \acmd{true}. Infinite loops, which are possible in back-linked key settings, are avoided in the \pkg{skeyval}. The machinery of the \pkg{xkeyval}, such as \acmd{\setkeys}, \acmd{\presetkeys}, \acmd{\savekeys}, \acmd{\savevalue}, \acmd{\usevalue}, \etc, are all applicable to all complementary keys.

As an example, we define below two bipolar native-boolean keys \ang{draft} and \ang{final} with different key macros:
\begin{example}
\define@biboolkeys[KV]{fam}[mp@]{draft}[true]{final}%
{%
  \ifmp@draft
    \def\noneofone##1{}%
  \else
    \def\oneofone##1{##1}%
  \fi
}{%
  \ifmp@final
    \def\noneoftwo##1##2{}%
  \else
    \def\oneoftwo##1##2{##1}%
  \fi
}
\end{example}
The key prefix (default \fx{KV}), macro prefix (default \fx{mp@}), key macros (no default), and the default value of the primary boolean (\fx{true}) can all be empty:
\begin{example}
\define@biboolkeys{fam}{draft}{final}{}{}.
\end{example}

The defined complementary bipolar keys \ang{draft} and \ang{final} can now be set separately as follows:
\begin{example}
\setkeys[KV]{fam}{draft=true |makered(or) on}

\setkeys[KV]{fam}{final=true |makered(or) on}
\end{example}
The second statement above reverses the boolean \ang{draft} to \ang{false}, which had been set in the first statement to \ang{true}. There is no apparent meaning to the following:
\begin{example}
\setkeys[KV]{fam}{draft=true,final=true}.
\end{example}

\Note
In the \pkg{skeyval}, the acceptable values for native-boolean and toggle-boolean keys are \fx{true}, \fx{on}, \fx{false}, and \fx{off}. Toggle-booleans (\cref{sec:toggle-booleans}) and switches (\cref{sec:switches}) also accept these values. The value \fx{on} is synonymous with \fx{true}, whilst \fx{off} is an alias for \fx{false}. Being merely aliases, both \fx{on} and \fx{off} don't increase the number of commands per switch: the number remains three.

The \pkg{skeyval} has the \acmdm{\NewIfs} macro which defines five commands per switch:
\begin{macro}
\NewIfs[|vang(optional prefix)]{|vang(boolean list)}[|vang(optional state)]
\end{macro}
\acmdm*{\NewIfs}
This provides, for each member of the comma-separated list \ang{boolean list}, a new native-boolean register if the register didn't already exist, otherwise an error is flagged. Each member of \ang{boolean list} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}; the default is \fx{false}. The state \fx{on} is synonymous with \fx{true}, whilst \fx{off} is equivalent to \fx{false}. After declaring
\begin{example}
\NewIfs[bool]{a,b}[true]
\end{example}
you can say \fx{\ifboola}, \fx{\boolaon} and \fx{\boolaoff}, just like you would normally do \fx{\boolatrue} and \fx{\boolafalse}. The disadvantage of \fx{\NewIfs} is that it defines five commands per switch; it should therefore be employed only in special circumstances.

\subsection{Unipolar native-boolean keys}

Unipolar boolean keys are two keys that are always in the same state: when one is true (or false), the other one is also true (or false). In this regard, the key macro is always executed when a key transits to the ``true'' state. The syntax for creating unipolar native-boolean keys is exactly as that for defining bipolar native-boolean keys:
\begin{macro}
\define@uniboolkeys[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
  {|vang(primary boolean)}[|vang(default value for primary boolean)]
  {|vang(secondary boolean)}{|vang(func for primary boolean)}
  {|vang(func for secondary boolean)}
\end{macro}
\acmdm*{\define@uniboolkeys}
This command is robust and can be used in expansion contexts, but expandable commands may need to be protected. Again, if the user doesn't supply the \ang{keyprefix} and/or \ang{macroprefix}, the package will use \ang{KV} and \ang{mp@}, respectively. When the default value for the primary boolean is not supplied, the package will assume it to be \fx{true}.

The following example constructs two unipolar native-boolean keys:
\begin{example}
\NewToks[temptoks]{a,b}

\define@uniboolkeys[KV]{fam}[mp@]{pdfmode}[true]{microtype}%
{%
  \ifmp@pdfmode
    \temptoksa{Yes, in `pdfmode'}%
  \else
    \temptoksa{No, not in `pdfmode'}%
  \fi
}{%
  \ifmp@microtype
    \temptoksb{Yes, `microtype' loaded}%
  \else
    \temptoksb{No, `microtype' not loaded}%
  \fi
}
\end{example}

\subsection{Biunipolar native-boolean keys}
\label{sec:biuni-boolean}

Biunipolar keys are the generalized forms of bipolar and unipolar boolean keys, with one important restriction: unlike bipolar and unipolar keys, biunipolar keys have no symmetrical relationships. That is to say that the relationship between a pair of biunipolar keys is entirely determined by the primary key. A pair of biunipolar boolean keys possess only one of the following four types of relationship:
\begin{enum}
\item Unipolar property: When the primary key is \fx{false}, it sets the secondary key to \fx{false} (\RedStar\RedPlus-form of biunipolar keys). The secondary key macro isn't executed.
\item Bipolar property: When the primary key is \fx{false}, it sets the secondary key to \fx{true} (\RedStar-form). The secondary key macro is executed.
\item Bipolar property: When the primary key is \fx{true}, it sets the secondary key to \fx{false} (\RedPlus-form). The secondary key macro isn't executed.
\item Unipolar property: When the primary key is \fx{true}, it sets the secondary key to \fx{true} (unsigned form). The secondary key macro is executed.
\end{enum}
Of course, the primary key can be true only after it has been set.

The syntax for establishing biuni boolean keys is exactly like that for creating other complementary boolean keys, except for the optional \RedStar and \RedPlus signs:
\begin{macro}
\define@biuniboolkeys|redstar|redplus[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
  {|vang(primary boolean)}[|vang(default value for primary boolean)]
  {|vang(secondary boolean)}{|vang(macro for primary boolean)}
  {|vang(macro for secondary boolean)}
\end{macro}
\acmdm*{\define@biuniboolkeys,\define@biuniboolkeys*,\define@biuniboolkeys*+}

As an example, consider the arbitrary package or class options \fx{review} and \fx{preprint}. The option \fx{preprint} can automatically toggle \fx{review} to true, but possibly not vice versa: not every \fx{preprint} is a manuscript for \fx{review}. This is depicted below:
\begin{example}
\define@biuniboolkeys[KV]{fam}[mp@]{preprint}[true]{review}{%
  |comm(No key macro for preprint; otherwise, it would)
  |comm(have come in here.)
}{%
  \ifmp@review
    \SKV@BeforeDocumentStart{%
      \linespread{1.5}\selectfont
      \def\banner{\fbox{\textit{This is a review document}}}%
    }%
  \else
    \SKV@BeforeDocumentStart{\let\banner\@empty}%
  \fi
}
\end{example}
\acmd*{\SKV@BeforeDocumentStart}

As another example, consider the following biuni keys, each with its own macro:
\begin{example}
\define@biuniboolkeys|redstar|redplus[KV]{fam}[mp@]{brother}[true]{sister}{%
  \ifmp@brother
    \def\mybrother{Hamilton}%
  \fi
}{%
  \ifmp@sister
    \SKV@AfterDocumentStart{\def\mysister{Kate}}%
  \else
    \SKV@AfterDocumentStart{\let\mysister\@gobble}%
  \fi
}

\setkeys[KV]{fam}{brother=true}
\end{example}
\acmd*{\SKV@AfterDocumentStart}

\section{Toggle booleans and toggle keys}
\label{sec:toggles}

In the following \crefrange{sec:toggle-booleans}{sec:toggle-keys} we define toggle booleans/switches and use them to introduce toggle-boolean keys.

\subsection{Toggle booleans}
\label{sec:toggle-booleans}

The following toggle switches are defined in the \pkg{skeyval}. They largely mimic those in the \pkg{etoolbox}, except for the commands \acmdm{\deftog} and \acmd{\requiretog}. The internal control sequences and user interfaces of the two packages are, however, different, thus avoiding clashes.

All the commands in this section are robust and can be used in expansion or moving contexts without fear of premature expansion, but fragile arguments would need to be protected in those settings.

\begin{macro}
\deftog[|vang(optional prefix)]{|vang(toggle)}[|vang(optional state)]
\end{macro}
This defines a new \ang{toggle}, prefixed with \ang{prefix} upon definition, whether or not \ang{toggle} (with its prefix) is already defined. If \ang{toggle} is already defined, a warning message is logged in the transcript file (if the package option \acmd{verbose} is selected) and the new definition is effected. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}.

\begin{macro}
\newtog[|vang(optional prefix)]{|vang(toggle)}[|vang(optional state)]
\end{macro}
\acmdm*{\newtog}
This defines a new \ang{toggle}, prefixed with \ang{prefix} upon definition, if \ang{toggle} (with its prefix) is not already defined; otherwise the package issues a fatal error. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}.

You can define a set of toggles by the following command:
\begin{macro}
\NewTogs[|vang(optional prefix)]{|vang(toggles)}[|vang(optional state)],
\end{macro}
\acmdm*{\NewTogs}
where \ang{toggles} is a comma-separated list. Each member of \ang{toggles} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}. For example, we may define new toggles \fx{togx}, \fx{togy}, \fx{togz} by the following:
\begin{example}
\NewTogs[tog]{x,y,z}[true]
\end{example}

\begin{macro}
\providetog{|vang(toggle)}
\end{macro}
\acmdm*{\providetog}
This defines a new \ang{toggle} if \ang{toggle} is not already defined. If \ang{toggle} is already defined, the command does nothing. Please note that there are no tog prefix here, and that the default state is \fx{false}.

\begin{macro}
\requiretog{|vang(toggle)}
\end{macro}
\acmdm{\requiretog} takes arguments like \fx{\newtog} and behaves like \fx{\providetog} with the difference: if the toggle is already defined, the command \fx{\requiretog} calls \LaTeX's \acmdm{\CheckCommand} to make sure that the new and existing definitions are identical, whereas \fx{\providetog} assumes that if the toggle is already defined, the existing definition should persist. \fx{\requiretog} assures that a toggle will have the given definition, but (if the package option \fx{verbose} is selected) \fx{\requiretog} also warns the user if there was a previous and different existing definition. For example, if the toggle \ang{toga} is currently \ang{true}, then since all new toggles start out as \ang{false}, a call \fx{\requiretog{toga}} will, if the package option \fx{verbose} is selected, issue a warning in the log file that the new and old definitions of \ang{toga} don't agree and the new definition, therefore, can't go ahead. Note that there are no tog prefix here, and that the default state is \fx{false}.

The \pkg{skeyval} also provides the command \acmd{\requirecmd}, which has the same logic as \fx{\requiretog} but can be used for general \latex commands, including those with optional arguments (see \cref{sec:misce-commands}).

\begin{macro}
\settog{|vang(toggle)}{|vang(true |amdvert false |amdvert on |amdvert off)}
\end{macro}
\acmdm*{\settog}
This command sets \ang{toggle} to \ang{value}, where \ang{value} may be either \fx{true}, \fx{false}, \fx{on} or \fx{off}. This statement will issue an error if \ang{toggle} wasn't previously defined.

\begin{macro}
\togon{|vang(toggle)}
\togtrue{|vang(toggle)}
\end{macro}
\acmdm*{\togon, \togtrue}
These set \ang{toggle} to \ang{true} or \fx{on}. They will issue an error if \ang{toggle} wasn't previously defined.

\begin{macro}
\togoff{|vang(toggle)}
\togfalse{|vang(toggle)}
\end{macro}
\acmdm*{\togoff, \togfalse}
These set \ang{toggle} to \ang{false} or \fx{off}. They will issue an error if \ang{toggle} wasn't previously defined.

\begin{macro}
\iftogon{|vang(toggle)}{|vang(true)}{|vang(false)}
\iftogtrue{|vang(toggle)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\iftogon, \iftogtrue}
These yield the \ang{true} statement if the boolean \ang{toggle} is currently \ang{true}, and \ang{false} otherwise. They will issue an error if \ang{toggle} wasn't previously defined.

\begin{macro}
\iftogoff{|vang(toggle)}{|vang(not true)}{|vang(not false)}
\iftogfalse{|vang(toggle)}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\iftogoff, \iftogfalse}
These behave like \fx{\iftogon} and \fx{\iftogtrue} but reverse the logic of the test. They will issue an error if \ang{toggle} wasn't previously defined.

\subsection{Toggle-boolean keys}
\label{sec:toggle-keys}

The user interfaces for defining toggle-boolean keys is exactly like those for native-boolean keys in the \pkg{xkeyval}. This allows all the machinery of the \pkg{xkeyval} (including \acmd{\setkeys}, \acmd{\presetkeys}, \acmd{\savekeys}, \acmd{\savevalue}, \acmd{\usevalue}, etc) to be applicable to toggle-boolean keys.

As mentioned earlier, toggles have their own separate namespace. However, the \acmd{\setkeys} command (and friends) of the \pkg{xkeyval} is unaware of this. This can cause problems when the user uses the same name for native-boolean and toggle keys (or indeed any key type) in the same family and with the same key prefix, believing rightly that toggle keys have their own separate namespace. If this is a source of significant concern to any user, he will be well advised to instead use the commands \acmd{\newboolkey}, \acmd{\newboolkeys}, \acmd{\newtogkey}, \acmd{\newtogkeys}, \etc, of \cref{sec:redef-keys}. In those commands a mechanism is included to bar keys from having the same name as other keys in the same family and with the same prefix. Toggle keys can still share the same names with keys across families and key prefixes. Since it is not always certain which of the keys the user may want to first define (before its definition is possibly repeated), the fear of interference has necessitated new syntaxes for defining all key types, which completely avoid interference (see \cref{sec:redef-keys}).

The user interfaces for defining toggle keys are
\begin{macro}
\define@togkey[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
  {|vang(function)}

\define@togkey|redplus[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
  {|vang(function1)}{|vang(function2)}
\end{macro}
\acmdm*{\define@togkey,\define@togkey+}

If the macro prefix \ang{mp} is not specified, these create a toggle of the form \fnn{prefix}{family}{key}{} using \acmd{\deftog} (which initializes the toggle switch to \fx{false}) and a key macro of the form \bs\fnn{prefix}{family}{key}{} which first checks the validity of the user input. If the value is valid, it uses it to set the toggle and then executes \ang{function}. If the user input wasn't valid (\ie, neither \fx{true} nor \fx{false}), then the toggle will not be set and the package will generate a fatal error to this effect.

If \ang{mp} is specified, then the key definition process will create a toggle of the form \fnm{mp}{key}{}{} and a key macro of the form \bs\fnm{mp}{key}{}{}. The value \ang{default} will be used by the key macro when the user sets the key without a value.

If the plus (\RedPlus) version of the macro is used, the user can specify two key macros \ang{function1} and \ang{function2}. If user input is valid, the macro will set the toggle and executes \ang{function1}; otherwise, it will not set the boolean but will execute \ang{function2}.

As an example, consider the following:
\begin{example}
\define@togkey{fam}[my@]{frame}{%
  \iftogon{my@frame}{%
    \PackageInfo{mypack}{Turning frames on}%
  }{%
    \PackageInfo{mypack}{Turning frames off}%
  }%
}

\define@togkey|redplus{fam}{shadow}{%
  \iftogon{KV@fam@shadow}{%
    \PackageInfo{mypack}{Turning shadows on}%
  }{%
    \PackageInfo{mypack}{Turning shadows off}%
  }%
}{%
    \PackageWarning{mypack}{Erroneous input `#1' ignored}%
}
\end{example}

The first example creates the toggle \ang{my@frame} and defines the key macro
\fx{\KV@fam@frame} to set the boolean (if the input is valid). The second key intimates
the user of changed settings, or produces a warning when input was incorrect.

It is also possible to define multiple toggle keys with a single command:
\begin{macro}
\define@togkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(keys)}[|vang(default)]
\end{macro}
\acmdm*{\define@togkeys}
This creates a toggle key for every entry in the comma-separated list \ang{keys}. As is the case with the commands \acmd{\define@cmdkeys} and \acmd{\define@boolkeys} from the \pkg{xkeyval}, the individual keys in this case can't have a custom function. See \cref{sec:def-multiple-keys} for how to define multiple keys with custom functions.

As an example of defining multiple toggle keys, consider
\begin{example}
\define@togkeys{fam}[my@]{toga,togb,togc}
\end{example}

This is an abbreviation for
\begin{example}
\define@togkey{fam}[my@]{toga}{}
\define@togkey{fam}[my@]{togb}{}
\define@togkey{fam}[my@]{togc}{}
\end{example}

Now we can do
\begin{example}
\define@togkey{fam}[my@]{book}{%
  \iftogon{my@book}{\setkeys[KV]{fam}{togc=true}}{}%
}
\setkeys[KV]{fam}{book=true}
\end{example}
\acmd*{\define@togkey,\setkeys}
Toggle keys can be set in the same way that other key types are set.

The status of toggles can be examined by doing
\begin{example}
\show\SKV@toggle@|vang(mp)|vang(key)
\end{example}
when the \ang{mp} is present. When the user has specified no \ang{mp} in defining the key, he has to issue
\begin{example}
\show\SKV@toggle@|vang(prefix)@|vang(family)@|vang(key).
\end{example}

\section{Complementary toggle keys}
\label{sec:comptogkeys}

\subsection{Bipolar toggle-boolean keys}

Similar to complementary native-boolean keys of \cref{sec:comp-boolkeys}, the \pkg{skeyval} introduces facilities for creating complementary (bipolar, unipolar and biunipolar) toggle keys. The syntax for defining bipolar toggle keys is identical to that for defining bipolar native-boolean keys:
\begin{macro}
\define@bitogkeys[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
  {|vang(primary toggle)}[|vang(default value for primary toggle)]
  {|vang(secondary toggle)}{|vang(func for primary toggle)}
  {|vang(func for secondary toggle)}.
\end{macro}
\acmdm*{\define@bitogkeys}
This command is robust and can be used in expansion contexts, but non-robust commands have to be protected. When the user doesn't supply the \ang{keyprefix} and/or \ang{macroprefix}, the package will use \ang{KV} and \ang{mp@}, respectively. When the default value for the primary toggle-boolean is not supplied, the package will use \fx{true}. When one of the bipolar toggle keys (primary or secondary) is true, the other is automatically set false; and vice versa: when one toggle key (primary or secondary) is false, the other is automatically set true.

As an example, we define below two bipolar toggle keys \ang{xdraft} and \ang{xfinal} with different key macros:
\begin{example}
\define@bitogkeys[KV]{fam}[mp@]{xdraft}[true]{xfinal}%
{\def\gobble##1{}}{\def\firstofone##1{##1}}
\end{example}
The key prefix (default \fx{KV}), macro prefix (default \fx{mp@}), key macros (no default), and the default value of the primary boolean (default \fx{true}) can all be empty:
\begin{example}
\define@bitogkeys{fam}{xdraft}{xfinal}{}{}.
\end{example}

The defined bipolar toggle keys \ang{xdraft} and \ang{xfinal} can now be set as follows:
\begin{example}
\setkeys[KV]{fam}{xdraft=true}

\setkeys[KV]{fam}{xfinal=true}
\end{example}
\acmd*{\setkeys}
The second statement above reverses the toggle \ang{xdraft} to \ang{false}, which had been set in the first statement to \ang{true}.

\Note
Toggle keys may easily be confused with the conventional boolean keys, especially at the time of key setting. It is, therefore, always safer to use the syntaxes in \cref{sec:redef-keys} for defining keys; they avoid interference between new and existing keys.

If we were to use the key names \acmd{draft} and \acmd{final} as toggle keys above, instead of \fx{xdraft} and \fx{xfinal}, there would have been a clash with the keys \acmd{draft} and \acmd{final} defined as (complementary) native-boolean keys in \cref{sec:comp-boolkeys}---because they share the same family \ang{fam} and prefix \ang{KV}. The names \acmd{draft} and \acmd{final} could safely be used as toggles only if the family \ang{fam} or prefix \ang{KV} is changed. See \cref{sec:avoiding-redef} for further details.

\subsection{Unipolar toggle-boolean keys}

The syntax for defining unipolar toggle keys is exactly the same as that for defining bipolar toggle keys:
\begin{macro}
\define@unitogkeys[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
  {|vang(primary toggle)}[|vang(default value for primary toggle)]
  {|vang(secondary toggle)}{|vang(func for primary toggle)}
  {|vang(func for secondary toggle)}.
\end{macro}
\acmdm*{\define@unitogkeys}
Here too, if the user doesn't supply the \ang{keyprefix} and/or \ang{macroprefix}, the package will use \ang{KV} and \ang{mp@}, respectively. When the default value for the primary toggle key is not supplied, the package will use \acmd{true}.
\begin{example}
\define@unitogkeys[KV]{fam}[mp@]{draft}[true]{final}%
  {\def\x##1{}}{\def\y##1{##1}}
\setkeys[KV]{fam}{draft=true}|comm(``final'' becomes ``true'' here.)
\end{example}
\acmd*{\setkeys}

\subsection{Biunipolar toggle-boolean keys}

The interface for creating biuni toggle keys is exactly like that for creating other complementary boolean keys, except for the optional \RedStar and \RedPlus signs. The interface is as follows (the meaning of the optional \RedStar and \RedPlus is given in \cref{sec:biuni-boolean}):
\begin{macro}
\define@biunitogkeys|redstar|redplus[|vang(keyprefix)]{|vang(family)}[|vang(macroprefix)]
  {|vang(primary boolean)}[|vang(default value for primary boolean)]
  {|vang(secondary boolean)}{|vang(macro for primary boolean)}
  {|vang(macro for secondary boolean)}
\end{macro}
\acmdm*{\define@biunitogkeys,\define@biunitogkeys*,\define@biunitogkeys*+}

\begin{example}
\define@biunitogkeys|redplus[KV]{fam}[mp@]{preprint}[true]{review}{%
  \iftogon{mp@preprint}{%
    \def\banner{\fbox{\textsf{This is a preprint copy}}}%
  }{}%
}{%
  \iftogon{mp@review}{%
    \SKV@AtDocumentStart{\linespread{1.5}\selectfont}%
    \def\banner{\fbox{\textit{This is a review article}}}%
  }{%
    \let\banner\@empty
  }%
}
\setkeys[KV]{fam}{preprint=false |orr true}
\end{example}
\acmd*{\setkeys,\SKV@AtDocumentStart}

\section[Defining multiple keys by one command]
  {Defining multiple keys of all genres by one command}
\label{sec:def-multiple-keys}

The user interface for defining multiple keys of all kinds in one go is the command \acmdm{\define@keylist}, whose syntax is
\begin{macro}
\define@keylist{|vang(key type/id), |vang(key), |vang(key default value),
  |vang(key macro/function); |vang(another set of key specifiers); etc}
\end{macro}

Here, there are five key types: 1~(ordinary key), 2~(command key), 3~(native-boolean key),
4~(toggle-boolean key), and 5~(choice/menu key). The key types can be indicated either in numeral format (\fx{1}~to~\fx{5}) or in alphabetic format (\fx{ord}, \fx{cmd}, \fx{bool}, \fx{tog}, \fx{choice}, \fx{menu}). ``Choice'' and ``menu'' keys imply the same thing (key type~5): the user can pick the name he prefers. The key and its attributes are separated by commas; they constitute one ``object'' or ``instance''. The objects are separated by the \ang{keyparser}, which is the semicolon in the above example. The \ang{keyparser} is a package option and can be changed dynamically.

If the key list is available in a macro, say,
\begin{example}
\def\keylist{|vang(key type/id), |vang(key), |vang(key default value),
  |vang(key macro/function); |vang(another set of key specifiers); etc},
\end{example}
then the keys can be defined by the starred form of \fx{\define@keylist}:
\begin{example}
\define@keylist|redstar\keylist.
\end{example}
\fx{\define@keylist}\redstar\ takes a macro as argument, while \fx{\define@keylist} accepts a key list.
\acmdm*{\define@keylist*}

The \fx{\define@keylist} macro uses the following commands in the background:
\begin{example}
\define@key, \define@cmdkey, \define@boolkey,
\define@choicekey, \define@togkey.
\end{example}
\acmdm*{\define@cmdkey,\define@boolkey,\define@choicekey,\define@togkey}
\acmd*{\define@key}
Therefore, it assumes that it is safe to redefine a previously defined key. If this assumption is unwarranted, then the user should consider using the machinery of \cref{sec:redef-keys}. The machinery of \cref{sec:redef-keys} can be utilized to safely define new keys without the fear of inadvertently redefining an existing key within the same family and with the same key prefix.

Keys defined by the tools in this section are amenable to management by pointers of \cref{sec:pointer-mech}.

\subsection{Choice key values}
\label{sec:choice-key-values}

The \acmdm{\choicekeyvalues} macro is provided for defining choice keys; it lists the alternate
admissible values for a choice key and thus can't be empty when a choice key
is being defined via \fx{\define@keylist}. Its syntax is
\begin{macro}
\choicekeyvalues|redstar[|vang(prefix)][|vang(family)]{|vang(key)}{|vang(list)},
\end{macro}
where \ang{list} is a comma-separated list of admissible key values. Unless the key prefix or family changes, the unstarred variant of \fx{\choicekeyvalues} wouldn't allow you to set two \fx{\choicekeyvalues} for the same choice key. The starred variant \fx{\choicekeyvalues}\unskip\redstar, on the other hand, allows you to overwrite admissible choice values for a key within a specified family and with the given key prefix. The arguments \ang{prefix} and \ang{family} are optional, provided the key prefix and family have been specified before calling \fx{\choicekeyvalues}, using \fx{\skvoptions}. If \ang{prefix} and \ang{family} are not given, the prevailing key prefix and key family are used internally by \fx{\choicekeyvalues} to build distinct alternate values list for the choice key.  Therefore, any number of choice keys are allowed to appear in one \acmd{\define@keylist} or \acmd{\define@keylist}\unskip\redstar\ statement, if their lists of alternate/admissible values have been set by \fx{\choicekeyvalues}.
It doesn't matter which choice key first gets a \fx{\choicekeyvalues}.

To further save tokens, the macro \fx{\choicekeyvalues} may be abbreviated by \acmdm{\CKVS}. It has to be provided for each choice key that is being defined.

For example, if we want to define two choice keys \fx{align} and \fx{shootingmodes}, then before the call to \acmd{\define@keylist}, we have to set
\begin{example}
\CKVS{align}{center,right,left,justified}
\CKVS{shootingmodes}{portrait,indoor,foliage,underwater}
\end{example}

As mentioned earlier, the key family and other package options can be changed dynamically via
\begin{example}
\skvoptions{keyparser=value,macroprefix=value,keyprefix=value,
  keyfamily=value}.
\end{example}
\acmd*{\skvoptions}

In line with the philosophy of the \pkg{xkeyval}, all the choice keys to be defined using the \pkg{skeyval} require a menu: choice keys, by definition, have pre-ordained or expected values.

\subsection{Some examples}
\label{sec:multkeys-examples}

In this section we provide a glimpse of the potential applications of the tools provided by the \pkg{skeyval} in the context of defining multiple keys by one command.

Suppose that the key family and other attributes have been set as
\begin{example}
\skvoptions{keyparser=;,macroprefix=mp@,keyprefix=KV,
  keyfamily=fam}
\end{example}
\acmd*{\skvoptions}
Further, suppose we wish to define a set of keys \fx{{color,angle,scale,align}}. The key \fx{color} will be defined as ordinary key, the keys \fx{angle} and \fx{scale} will de defined as command keys, while the key \fx{align} will be defined as a choice key. Assume that the \fx{align} key can only assume one of the values \leftbrace\fx{center} \amdvert\ \fx{right} \amdvert\ \fx{left} \amdvert\ \fx{justified}\rightbrace, where the first three values would further imply \fx{\centering}, \fx{\flushright}, and \fx{\flushleft}, respectively. Moreover, we assume that the key \fx{scale} will be associated with a macro called \fx{\mydo}, which depends on a previously defined macro \fx{\do}. Together with \fx{align}, we would also like to define another choice key: \fx{weather}. The key \fx{color} isn't associated with any macro. Then we can do:
\begin{example}
|comm(We use space freely in these examples for the sake)
|comm(of illustration:)
\def\someweather{windy}
\CKVS{align}{center,right,left,justified}
\CKVS{weather}{sunny,cloudy,lightrain,heavyrain,snow,
  sleet,\someweather}

\def\funcforalign{%
  \ifcase\nr\relax
    \def\mp@align{\centering}%
  \or\def\mp@align{\flushright}%
  \or\def\mp@align{\flushleft}%
  \or\let\mp@align\relax
  \fi
}
|comm(Keys `color' and `mybool' have no macro.)
|comm(Submitted value of key `angle' is ##1 |tto \mp@angle.)
\define@keylist{%
  ord,color,gray!25,;
  cmd,angle,45,\def\anglevalue{##1};
  cmd,scale,1,\def\mydo####1{\do ####1};
  choice,align,center,\funcforalign;
  |makered(\listbreak);|label(mac:listbreak)
  bool,mybool,true,;
  choice,weather,sunny,\edef\Weather{\val}%
}
\setkeys[KV]{fam}{angle=45,scale=1cm,weather=cloudy}
\end{example}
\acmd*{\CKVS}

Note the number of parameter characters in the definition of \fx{\mydo}. We will return to this matter in \cref{sec:macros-in-keymacros}. The \acmdm{\nr} and \acmdm{\val} macros are bin parameters for choice keys, as defined by the \pkg{xkeyval}. \fx{\val} contains the user input for the current key and \fx{\nr} contains the numeral corresponding to the numerical order of the user input in the \acmd{\CKVS} list, starting from~0 (zero). For example, in the \fx{\CKVS{align}} list, the \fx{\nr} values are \fx{center}~(0), \fx{right}~(1), \fx{left}~(2), and \fx{justified}~(3). These parameters thus refresh with the choice key and its user-supplied value.

Instead of defining the macro \fx{\funcforalign} before hand, we can submit its replacement text directly to the macro \acmd{\define@keylist}, but, because \fx{\funcforalign} contains a conditional, some care is needed in doing so (see \cref{sec:condit-in-keys}). Once the key \fx{align} has been defined, the macro \fx{\funcforalign} can't be reused before the key \fx{align} is set. This is because it is at key setting time that the function \fx{\funcforalign} would be called. This is uneconomical: it is thus desirable to submit the key macro directly to \acmd{\define@keylist} irrespective of the presence of conditionals.

Please note the \makered{\texttt{\string\listbreak}} token inserted on \macref{mac:listbreak} above. Because of it, the keys \fx{mybool} and \fx{weather} will not be read and defined; all the keys before \acmdm{\listbreak} (\ie, \fx{color}, \fx{angle}, \fx{scale} and \fx{align}) will be read and defined. All the entries for \fx{mybool} and \fx{weather} will instead be saved in the macro \acmdm{\SKV@remainder}, possibly for some other uses.

Hundreds of keys can be defined efficiently in this way, using very few tokens. As another example, we consider the following keys:
\acmd*{\CKVS,\define@keylist,\AtBeginDocument}
\begin{example}
\CKVS|redstar{align}{center,right,left,justified}
\CKVS{election}{state,federal,congress,senate}

\def\funcfortextwidth{\AtBeginDocument{\wlog{`textwidth' %
  is `\mp@textwidth'}}}

\def\funcfortextheight{%
  \ifx\@empty\mp@textheight
    \wlog{`textheight' value empty}%
  \else
    \wlog{`textheight' value not empty}%
  \fi
}

\def\funcforpaperwidth{\wlog{`paperwidth' was defined as %
  ordinary key.}}

\def\funcforalign{%
  \ifcase\nr\relax
    \def\mp@align{\centering}%
  \or\def\mp@align{\flushright}%
  \or\def\mp@align{\flushleft}%
  \or\let\mp@align\relax
  \fi
}
|comm(`boolvar', `paperheight' and `evensidemargin' have no)
|comm(key macros:)
\define@keylist{%
  bool,boolvar,true,;
  ord,paperheight,\paperheight,;
  ord,paperwidth,\paperwidth,\funcforpaperwidth;
  cmd,textheight,\textheight,\funcfortextheight;
  cmd,textwidth,\textwidth,\funcfortextwidth;
  ord,evensidemargin,\evensidemargin,;
  tog,togvar,true,\iftogon{mp@togvar}{\def\catch####1{####1}}%
    {\def\gobble####1{}};
  choice,align,center,\funcforalign;
  choice,election,congress,\def\electiontype{##1};
  cmd,testdim,2cm,\long\def\funcfortestdim####1{%
    A test dimension ####1 \endgraf\bigskip}%
}

\setkeys[KV]{fam}{togvar=true,testdim=1cm,election=senate}
\end{example}
The macro \fx{\electiontype} corresponds to \fx{\val} for choice key \fx{election}.
Again, the intermediate/utility key macros can be reused only after their associated keys have been set.

The same set of keys can be defined via the starred form of \acmd{\define@keylist}, as shown below:
\begin{example}
\def\keylistvector{%
  bool,boolvar,true,;
  ord,paperheight,\paperheight,;
  ord,paperwidth,\paperwidth,\funcforpaperwidth;
  cmd,textheight,\textheight,\funcfortextheight;
  cmd,textwidth,\textwidth,\funcfortextwidth;
  ord,evensidemargin,\evensidemargin,;
  tog,togvar,true,\iftogon{mp@togvar}{\def\catch####1{####1}}%
    {\def\gobble####1{}};
  choice,align,center,\funcforalign;
  choice,election,congress,\def\electiontype{##1};
  cmd,testdim,2cm,\long\def\funcfortestdim####1{%
    A test dimension ####1 \endgraf\bigskip}%
}
\define@keylist|redstar\keylistvector
\end{example}
\acmd*{\define@keylist*}

Since the keys have been defined, they can now be set. In the following, we set only two of the keys:
\begin{example}
\setkeys[KV]{fam}{align=right,testdim=3cm}
\end{example}
\acmd*{\setkeys}

The macro \fx{\mp@align} holds the value \fx{\flushright}, while \fx{\KV@fam@testdim} holds the macros:
\begin{example}
\def\mp@testdim{#1}
\long\def\funcfortestdim##1{A test dimension ##1},
\end{example}
where \angledhash{1} is the value (3cm) submitted for the key \fx{testdim}. The number of parameter characters normally increases in the macro \fx{\define@keylist} (see \cref{sec:macros-in-keymacros}). After setting the keys, you can do \fx{\show\mp@align} and  \fx{\show\KV@fam@testdim} to confirm the above assertions.

The rest of the defined keys can now be set as follows:
\begin{example}
\setkeys[KV]{fam}{boolvar=true,paperheight,paperwidth,
  textheight,textwidth=6cm}
\end{example}
\acmd*{\setkeys}
Try \fx{\show\ifmp@boolvar} to confirm that \fx{boolvar} is now \ang{true}; it was originally set as \ang{false}. The macro \fx{\KV@fam@paperwidth} holds the function \fx{\funcforpaperwidth}, while \fx{\mp@textheight} holds the value submitted to key \fx{textheight} at any instance of \acmd{\setkeys}. By the above \acmd{\setkeys}, only the default values of \fx{paperheight}, \fx{paperwidth}, and \fx{textheight} are presently available.

Instead of using macros to pass key macros and functions, it is also possible to use token list registers. Some examples are provided below:
\begin{example}
\NewToks[temptoks]{a,b}
|comm(See page |pageref(page:newtoks) for definition of \NewToks and related commands.)

\temptoksa{\ifmp@boola\def\do#1{%
  \def#1##1##2{\expandafter\expandafter\expandafter\in@
  \expandafter\expandafter\expandafter{\expandafter##1%
  \expandafter}\expandafter{##2}}}\fi}

\temptoksb{\iftogon{mp@toga}{\def\order#1{Use `#1' now!}}%
  {\def\altorder#1{Don't use `#1' now!}}}

\define@keylist{3,boola,true,\the\temptoksa;
  4,toga,true,\the\temptoksb}

\setkeys[KV]{fam}{boola=true,toga=true}
\end{example}
\acmd*{\define@keylist}
The advantage of using token list registers is that the parameter characters need not be doubled in the token list registers, unlike when using macros. The token list register \fx{\temptoksa} can be reused as soon as the key \fx{boola} has been set. See \cref{sec:condit-in-macros} for more information on using macros and token list registers to parse key functions.

\subsubsection{Parameterized macros in key macros}
\label{sec:macros-in-keymacros}

The examples in \cref{sec:multkeys-examples} would have provided some glimpse of the rules guiding the use of parameter characters in key macros. The general rules are as follows:
\begin{enum}
\item When key macros are parsed through token list registers, the parameter characters shouldn't be doubled.
\item When key macros are parsed via intermediate macros, the parameter characters should be doubled but only once.
\item In all other cases (\ie, when using \fx{\define@keylist} and its starred variant) the parameter characters should be doubled twice.
\end{enum}
\tex will flag a fatal error when any of these rules is breached. The following examples illustrate the use of these rules. The commands \fx{\skif}, \fx{\skifx}, \fx{\skelse} and  \fx{\skfi} are described in \cref{sec:pseudo-primitives}.
\begin{example}
\define@keylist{%
  tog,toga,true,\iftogon{mp@toga}{%
    \def\swear####1{Repeat after me: `####1'!}%
  }{%
    \let\swear\@gobble
  }%
}
\setkeys[KV]{fam}{toga=true}

\NewToks[temptoks]{a}

\temptoksa={\long\def\funcforproclaim#1%
  {A proclaimed statement: #1}}
\define@keylist{%
  bool,boola,true,\skif{mp@boola}\def\yes####1%
    {Accept `####1'!}\skelse\def\no####1{Reject `####1'!}\skfi;
  cmd,proclaim,Statement,\the\temptoksa
}
\setkeys[KV]{fam}{boola=true,proclaim=nature}

\CKVS{align}{left,right,center}

\define@keylist{choice,align,center,
  \skifcase\nr
    \def\hold####1{\def####1########1{===########1===}}%
  \skor
    \def\hold####1{\def####1########1{+++########1+++}}%
  \skfi
}
\setkeys[KV]{fam}{align=right}

\CKVS{focus}{left,right,center}
\def\keylistvector{%
  choice,focus,center,\def\hold####1%
  {\def####1########1{===########1===}}%
}
\define@keylist*\keylistvector
\setkeys[KV]{fam}{focus=right}

\def\keylistvector{cmd,keya,xxx,\def\hold####1%
  {\def####1########1{===########1===}}}
\define@keylist*\keylistvector
\setkeys[KV]{fam}{keya=yyy}

\def\funcforkeyb{\def\hold##1{\def##1####1{===####1===}}}
\define@keylist{cmd,keyb,xxx,\funcforkeyb}
\setkeys[KV]{fam}{keyb=yyy}

\define@cmdkey[KV]{fam}[mp@]{keyc}[xxx]{\def\hold##1{##1}}
\setkeys[KV]{fam}{keyc=yyy}

\def\keylistvector{%
  ord,keyda,aaa,\def\hold####1%
    {\def####1########1{===########1===}};
  cmd,keydb,bbb,\def\althold####1%
    {\def####1########1{***########1***}}%
}
\define@keylist*\keylistvector
\setkeys[KV]{fam}{keyda=xxx,keydb=yyy}

|comm(The next one fails. Why?)
\define@keylist{ord,keye,unknown,\def\hold##1%
  {\def##1####1{####1}}}

\define@keylist{%
  ord,keyfa,xxx,
  \skifx\x\y
    \def\hold####1{\def####1########1{===########1===}}%
  \skelse
    \def\hold####1{\def####1########1{***########1***}}%
  \skfi;
  cmd,keyfb,yyy,
  \SKV@ifx\x\y{%
    \def\nosupergobble####1{\def####1########1{########1}}%
  }{%
    \def\supergobble####1{\def####1########1{}}%
  }%
}
\setkeys[KV]{fam}{keyfa=value,keyfb=value}

\def\funcforboolb{\ifmp@boolba\def\do##1{%
  \def##1####1####2{\expandafter\expandafter\expandafter\in@
  \expandafter\expandafter\expandafter{\expandafter####1%
  \expandafter}\expandafter{####2}}}\fi}

\define@keylist{3,boolba,true,\funcforboolb;3,boolbb,true,;}
\setkeys[KV]{fam}{boolba=true}

\NewToks[temptoks]{a,b}

\temptoksa{\ifmp@boolc\def\do#1{%
  \def#1##1##2{\expandafter\expandafter\expandafter\in@
  \expandafter\expandafter\expandafter{\expandafter##1%
  \expandafter}\expandafter{##2}}}\fi}
\temptoksb{\iftogon{mp@togb}{\def\tempa#1{Use #1}}%
  {\def\tempb#1{Don't use #1}}}
\define@keylist{3,boolc,true,\the\temptoksa;
  4,togb,true,\the\temptoksb}

\setkeys[KV]{fam}{boolc=true,togb=true}
\do\x \def\y{x} \def\z{xxx} \x\y\z

\def\keylistvector{bool,boold,true,
  \ifswitchon{mp@boold}{%
    \def\hold####1{\def####1########1{***########1***}}%
  }{%
    \def\hold####1{\def####1########1{===########1===}}%
  }%
}
\define@keylist*\keylistvector
\setkeys[KV]{fam}{boold=true}
\end{example}

\subsection{Input error}
\label{sec:input-error}

Native-boolean, toggle-boolean and choice keys issue error messages if the key value is not valid, \ie, not in the list of admissible values. The admissible values of native-boolean and toggle keys are \fx{true} and \fx{false}. The valid values of choice keys are set by the user via \acmd{\CKVS}. The default input error is defined by the macro \fx{\SKV@inputerr}. It takes two arguments (\ie, value and key) and can be customized by the user.

\subsection{Conditionals in key macros}
\label{sec:condit-in-keys}

\index{TeXBook=The \TeX Book}
The \tex conditional primitives \fx{\if}, \fx{\ifx}, \fx{\else} and \fx{\fi} cannot appear in the key macro when \acmd{\define@keylist} is being invoked. The reason can be traced to the discussion on page~211 of the \TeX Book and the loops used in the \pkg{skeyval} to define keys by means of \acmd{\define@keylist}. There are many possible approaches to resolving this problem, but only four appear to be attractive (see \crefrange{sec:condit-in-macros}{sec:using-toggles}).

\subsubsection[Using macros or token list registers]
  {Burying conditionals in intermediate macros or token list registers}
\label{sec:condit-in-macros}

Key macros/functions involving conditional operations such as
\begin{example}
\ifmp@bool \do \else \donot \fi
\end{example}
can be submitted to \acmd{\define@keylist} via intermediate macros, as seen above (in \cref{sec:multkeys-examples}), but the approach isn't economical and thus not advisable. Nevertheless, we give more examples of deploying intermediate macros below. Let the key macro prefix be \fx{mp@}, the key prefix be \fx{KV}, and the key family be \fx{fam}.

Suppose we want to submit the following:
\begin{example}
\define@keylist{3,bool,true,\ifmp@bool \do \else \donot \fi}.
\end{example}
\acmd*{\define@keylist}
The presence of \fx{\if} and \fx{\fi} in the argument will trigger an error when \tex is  scanning and skipping tokens, and, secondly, because of the loops and conditionals used by the \pkg{skeyval} in defining keys via \acmd{\define@keylist}. Neither \fx{\protect} nor \fx{\noexpand} is helpful here. One solution is to first define
\begin{example}
\def\funcforbool{\ifmp@bool \do \else \donot \fi}
\end{example}
and then do
\begin{example}
\define@keylist{3,bool,true,\funcforbool},
\end{example}
\acmd*{\define@keylist}
which will execute \fx{\funcforbool} when the key \fx{bool} is set. One significant drawback of this approach is that once the key \fx{bool} has been defined by the above statement, the function \fx{\funcforbool} may not be redefined and reused before the key \fx{bool} is set. This is wasteful and not advisable. This approach is included here only for demonstration purposes. The schemes in \crefrange{sec:pseudo-primitives}{sec:switches} are preferable.

As another example, we may do
\begin{example}
\def\funcforboola{\ifmp@boola\def\do##1{%
  \def##1####1####2{\expandafter\expandafter\expandafter\in@
  \expandafter\expandafter\expandafter{\expandafter####1%
  \expandafter}\expandafter{####2}}}\fi}

\define@keylist{3,boola,true,\funcforboola}

\setkeys[KV]{fam}{boola=true}

\def\y{x} \def\z{xxx} \do\x \x\y\z
\end{example}

Token list registers can be used here economically instead of macros. Below we define one native-boolean key and one toggle-boolean key:
\begin{example}
\NewToks[temptoks]{a,b}

\temptoksa{\ifmp@boola\def\do#1{%
  \def#1##1##2{\expandafter\expandafter\expandafter\in@
  \expandafter\expandafter\expandafter{\expandafter##1%
  \expandafter}\expandafter{##2}}}\fi}

\temptoksb{\iftogon{mp@toga}{\def\order#1{Use `#1' now!}}{}}

\define@keylist{3,boola,true,\the\temptoksa;
  4,toga,true,\the\temptoksb}

\setkeys[KV]{fam}{boola=true,toga=true}
\end{example}
\acmd*{\define@keylist,\setkeys,\NewToks}
You can see the significant reduction in the number of parameter characters when using token list registers. The utility token list registers \fx{\temptoksa} and \fx{\temptoksb} can be reused to define many other keys as soon as the keys \fx{boola} and \fx{toga} have been set. However, as noted earlier, the approach of using intermediate macros and token list registers to parse arguments to \fx{\define@keylist} is not attractive because of the overheads in the number of macros and token list registers.

\subsubsection[Using pseudo-primitives]
  {Using pseudo-primitives to submit the conditionals}
\label{sec:pseudo-primitives}

There are two downsides to the above approach of hiding conditionals in macros: the macros have to be defined and, although they can be redefined and reused (after the associated key has been set), they tend to defeat the initial aim of the package, which is to economize on tokens.

Suppose we want to define a native-boolean key \fx{mybool} with the following key macro:
\begin{example}
\ifmp@mybool
  \def\hold##1{\def##1####1{***####1***}}%
\else
  \def\hold##1{\def##1####1{===####1===}}%
\fi
\end{example}
where the key prefix \fx{KV}, key family \fx{fam}, and the macro prefix \fx{mp@} are assumed to have been defined previously. Then, instead of hiding the conditional in an intermediate macro, we may adopt the following:
\begin{example}
\define@keylist{3,mybool,true,
  |makered(\skif{|mcolor(mp@mybool)})\def\hold##1{\def##1####1{***####1***}}%
  |makered(\skelse)\def\hold##1{\def##1####1{===####1===}}|makered(\skfi)
}

\setkeys[KV]{fam}{mybool=true |makered(or) false}
\hold\x
\end{example}
\acmdm*{\skif,\skifx,\skelse,\skfi}
\acmd*{\skifcase,\skor,\define@keylist}
Here we have used the pseudo-primitives \fx{\skif{mp@mybool}}, \fx{\skifx}, \fx{\skelse} and \fx{\skfi} for the commands \fx{\ifmp@mybool}, \fx{\ifx}, \fx{\else} and \fx{\fi}, respectively, to hide the latter four from \TeX's scanning and skipping mechanism. It should be noted that \fx{\skif{mp@mybool}} requires that the argument \ang{mp@mybool} be enclosed in braces. Something like \fx{\skifmp@mybool} will be interpreted by \tex as an undefined control sequence when the key \fx{mybool} is being set. Defining the command \fx{\skif{mp@mybool}} to be \fx{\ifmp@mybool} before hand would have failed because \tex's scanner would then get the hint of the assignment.

\Note We haven't found any package that has defined \fx{\skif}, \fx{\skifx}, \fx{\skelse}, \fx{\skfi}, \fx{\skifcase} or \fx{\skor}. The \pkgm{xifthen}, for example, uses \fx{\OR}, not \fx{\skor}. If the situation changes in the future (\ie, if a package is observed to have defined any of these commands), they will be appropriately modified in the \pkg{skeyval}. Information and feedback from package users is solicited in this regard.

We have redefined the \fx{\setkeys} command of the \pkg{xkeyval} to recognize that \fx{\skif{boolean}}, \fx{\skifx}, \fx{\skelse}, \fx{\skfi}, \fx{\skifcase} and \fx{\skor} stand for \fx{\ifboolean}, \fx{\ifx}, \fx{\else}, \fx{\fi}, \fx{\ifcase} and \fx{\or}, respectively. The redefined \fx{\setkeys} command has the same syntaxes as as in \pkg{xkeyval}:
\begin{macro}
\setkeys[|vang(prefix)]{|vang(families)}[|vang(na)]{|vang(keys=values)}
\setkeys|redstar[|vang(prefix)]{|vang(families)}[|vang(na)]{|vang(keys=values)}
\setkeys|redplus[|vang(prefix)]{|vang(families)}[|vang(na)]{|vang(keys=values)}
\setkeys|redstar|redplus[|vang(prefix)]{|vang(families)}[|vang(na)]{|vang(keys=values)}.
\end{macro}
\acmdm*{\setkeys,\setkeys*,\setkeys*+}
No errors are produced if any of the sets \ang{prefix}, \ang{families}, \ang{na}, and \ang{keys=values} is empty. In fact, an instruction such as \fx{\setkeys[]{}[]{}} is completely benign, and so is \fx{\setkeys{}{}}.

\paragraph{Conditionals involving \textcolor{xmagenta1}{\@bs ifcase}:}

The case of conditionals involving \fx{\ifcase} can be handled in the same way as those involving \fx{\if}:
\begin{example}
\CKVS{focus}{center,left,right,justified}

\temptoksa{\ifcase\nr\relax
  \def\mp@focus{\centering}\or\def\mp@focus{\flushright}
  \or\def\mp@focus{\flushleft}\or\let\mp@focus\relax\fi}

\define@keylist{5,focus,center,\the\temptoksa}
\end{example}
\acmd*{\CKVS,\define@keylist}

This can be written more compactly as follows, which obviates the need for intermediate macros and list registers:
\begin{example}
\define@keylist{menu,focus,center,|makered(\skifcase)\nr\relax
  \def\mp@focus{\centering}|makered(\skor)\def\mp@focus{\flushright}
  |makered(\skor)\def\mp@focus{\flushleft}|makered(\skor)\let\mp@focus\relax|makered(\skfi)}
\end{example}
\acmdm*{\skifcase,\skor}
Here, the \pkg{skeyval} uses \fx{\skifcase}, \fx{\skor}, and \acmd{\skfi} for \fx{\ifcase}, \fx{\or} and \fx{\fi}, respectively; otherwise, \tex would be grumpy.

The key \fx{focus} can now be readily set: \fx{\setkeys[KV]{fam}{focus=left}}.

\subsubsection[Using switches]{Using switches to submit the conditionals}
\label{sec:switches}

The approaches of \cref{sec:pseudo-primitives} provide a familiar \tex-like syntax for submitting conditionals to \fx{\define@keylist}. There is yet another approach that we developed. It is related to the native \tex boolean conditional. By \emph{switches} we mean the usual \tex's \fx{\iftrue} and \fx{\iffalse} booleans, but expressed in different syntax and semantics.

A new switch can be introduced by using the following command:

\begin{macro}
\newswitch[|vang(optional prefix)]{|vang(boolean)}[|vang(optional state)]
\end{macro}
\acmdm*{\newswitch}
This provides a new native-boolean register \fx{\if}\unskip\ang{prefix}\unskip\ang{boolean} if the register didn't already exist; if the register already existed, an error is flagged. The optional \ang{state} can be either \fx{true} (or \fx{on}) or \fx{false} (or \fx{off}); the switch will be initialized to that state. With this definition, you can issue \fx{\if}\unskip\ang{switch}, \bs\ang{switch}\unskip\fx{true}, and \bs\ang{switch}\unskip\fx{false}. One advantage of \fx{\newswitch} is that a switch can start off as either \fx{true} (or \fx{on}) or \fx{false} (or \fx{off}), unlike the classical \tex's case in which all booleans start off as \fx{false}. Also, switches can be used where primitive \tex conditionals may prove impossible. For example, we know that you can't do \fx{\let\ifabc\iftrue} within the body of a conditional text without hiding the assignment from \tex's scanning mechanism.

\begin{example}
\newswitch{boola}  |tto  \newif\ifboola

\newswitch[bool]{b}[true]   |tto  \newif\ifboolb \boolbtrue

\newswitch[bool]{c}[on]   |tto  \newif\ifboolc \boolctrue

\newswitch[bool]{d}[off]   |tto  \newif\ifboold \booldfalse
\end{example}

You can define many switches in a row by the following command:
\begin{macro}
\NewSwitches[|vang(optional prefix)]{|vang(switches)}[|vang(optional state)]
\end{macro}
\acmdm*{\NewSwitches}
Each member of \ang{switches} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true} (or \fx{on}) or \fx{false} (or \fx{off}).

Here are some examples:

\begin{example}
\NewSwitches{x,y,z}[off]
    |tto    \newswitch{x}{false} \newswitch{y}{false}
          \newswitch{z}{false}

\NewSwitches[skv@]{u,w}[true]
    |tto    \newswitch{skv@u}{true} \newswitch{skv@w}{true}
\end{example}

Switches may be set and tested using the following commands:
\begin{macro}
\setswitch{|vang(switch)}{|vang(value/state)}

\switchon{|vang(switch)}      |tto    \|vang(switch)true

\switchtrue{|vang(switch)}    |tto    \|vang(switch)true

\switchoff{|vang(switch)}     |tto    \|vang(switch)false

\switchfalse{|vang(switch)}   |tto    \|vang(switch)false

\ifswitchon{|vang(switch)}{|vang(true text)}{|vang(false text)}

\ifswitchtrue{|vang(switch)}{|vang(true text)}{|vang(false text)}

\ifswitchoff{|vang(switch)}{|vang(not true)}{|vang(not false)}

\ifswitchfalse{|vang(switch)}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\newswitch,\setswitch,\switchon,\switchoff,\ifswitchon,
\ifswitchoff,\switchtrue,\switchfalse,\ifswitchtrue,
\ifswitchfalse}

\begin{example}
\NewSwitches{w,x,y,z}

\setswitch{w}{true}   |tto    \setswitch{w}{on}
\setswitch{x}{on}     |tto    \setswitch{x}{true}
\setswitch{y}{false}  |tto    \setswitch{y}{off}
\setswitch{z}{off}    |tto    \setswitch{z}{false}

\ifswitchon{x}{\def\xx{On}}{\def\xx{Off}}

\ifswitchoff{y}{\def\yy{Off}}{\def\yy{On}}
\end{example}

\begin{macro}
\defswitch[|vang(optional prefix)]{|vang(boolean)}[|vang(optional state)]
\end{macro}
\acmdm*{\defswitch}
This is similar to \fx{\newswitch} but raises no errors even if the register \ang{boolean} already exists.

Now how do we use switches in \fx{\define@keylist}? Suppose the key prefix is \fx{KV}, the key family is \fx{fam}, and the key macro is \fx{mp@}. Then the following works:
\begin{example}
\define@keylist{3,swa,true,
  |makered(\ifswitchon){mp@swa}{\def\say{Swtich `a' is true}}
    {\def\say{Swtich `a' is false}}}

\setkeys[KV]{fam}{swa=true |makered(or) false |makered(or) on |makered(or) off}
\end{example}
\acmd*{\define@keylist}

\Note Please note that ``switch keys'' are actually native-boolean keys (\fx{bool} or type~\fx{3} key). When setting native-boolean and toggle-boolean keys you can supply either \fx{true}, \fx{false}, \fx{on} or \fx{off} as values. We have modified the relevant internal macros of the \pkg{xkeyval} to make this possible for the native-boolean keys as well.

\subsubsection[Using toggles]{Using toggles to submit the conditionals}
\label{sec:using-toggles}

Toggle booleans, described in \cref{sec:toggles}, can also be used to circumvent the problem of matching \fx{\if} and \fx{\fi} in difficult circumstances, since toggles aren't \tex primitives, and, as noted in \cref{sec:toggles}, toggles are very economical. For example, the following works:
\begin{example}
\define@keylist{4,toga,true,
  |makered(\iftogon){mp@toga}{\def\say{Toggle `a' is true}}%
    {\def\say{Toggle `a' is false}}}

\setkeys[KV]{fam}{toga= true |makered(or) false}
\end{example}
\acmd*{\define@keylist,\iftogon}
where the key prefix, key family, and macro prefix are still assumed to be \fx{KV}, \fx{fam}, \fx{mp@}, respectively. Recall that toggle keys are type~4 keys.

\section{Key command and key environment}
\label{sec:keycommand}

The \fx{\define@keylist} macro of \cref{sec:def-multiple-keys}, together with the \fx{\newkeylist} macro of \cref{sec:avoiding-redef}, provides an attractive toolkit for developing a system for defining commands using keys, in the manner of the \pkgm{keycommand} but with a more compact user interface. See the \pkgm{skeycommand} for details.

\section{Checking and redefining keys}
\label{sec:check-redef-keys}

\subsection{Checking the status of a key}
\label{sec:status-keys}

Three mechanisms have been introduced in the \pkg{skeyval} to ascertain the statuses of keys. These are as follows.

\begin{macro}
\ifkeydefined[|vang(prefixes)]{|vang(families)}{|vang(key)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\ifkeydefined}
This executes \ang{true} if \ang{key} is defined, reserved, or suspended with a prefix in   \ang{prefixes} and family in \ang{families}; it returns \ang{false} otherwise. This is similar to
the \pkg{xkeyval}'s \acmdm{\key@ifundefined}, but, apart from reversing the logic of the test, \fx{\ifkeydefined} loops over prefixes (in addition to looping over families) to locate the key, and also considers reserved and suspended keys as defined. The lists \ang{prefixes} and \ang{families} may contain nil, one or more elements.

\begin{macro}
\ifkeyreserved[|vang(prefixes)]{|vang(families)}{|vang(key)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\ifkeyreserved}
This returns \ang{true} if \ang{key} is reserved with a prefix in \ang{prefixes} and family in \ang{families}; it returns \ang{false} otherwise. Reserved keys are introduced in \cref{sec:reserve-keys}.

\begin{macro}
\ifkeysuspended[|vang(prefixes)]{|vang(families)}{|vang(key)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\ifkeysuspended}
This executes \ang{true} if \ang{key} is suspended with a prefix in \ang{prefixes} and family in \ang{families}; it executes \ang{false} otherwise. Suspended keys are introduced in \cref{sec:suspend-keys}.

\subsection{Unintentional redefinition of keys}
\label{sec:redef-keys}

The \pkg{xkeyval}, by default, permits the automatic redefining of keys of the same \ang{prefix} and  \ang{family}: at the point of defining a new key, the package doesn't, by default, check whether or not the key had been previously defined with the same \ang{prefix} and  \ang{family}. In some circumstances this can be undesirable, and even dangerous, especially if the same key (of the same \ang{prefix} and  \ang{family}) is mistakenly redefined with different macros/functions in the same package or across packages. One way to solve this problem is to use \pkg{xkeyval}'s \fx{\key@ifundefined} command (or the \pkg{skeyval}'s \fx{\ifkeydefined}) to confirm the status of a key prior to its definition. However, using these commands before defining every key can be laborious.

Consider the following two scenarios:
\begin{example}
\define@key[KV]{fam}{keya}[$\star$]{\def\tempa##1{##1}}

\define@boolkey[KV]{fam}{keya}[true]{%
  \ifKV@fam@keya\def\tempb{#1}\fi}

\setkeys[KV]{fam}{keya=$\textbullet$}
\end{example}
\acmd*{\setkeys}
Obviously the two definitions of \ang{keya} are valid and will be implemented but the \acmd{\setkeys} command here will issue an unintelligible error message, like \LaTeX's ``You are in trouble here \textellipsis''. The key \ang{keya} has been defined twice and \acmd{\setkeys} has sought to use its latest definition to set its value, which is incorrect. As mentioned in \cref{sec:toggle-keys}, the \acmd{\setkeys} command (and friends) of the \pkg{xkeyval} doesn't know if a key has been redefined in the same \ang{family} and with the same \ang{prefix}. At the high level, it doesn't consider the key type: it uses the latest definition of the key to set its value using the key's macro. This is particularly worrisome in the case of toggle keys, since although toggle keys have their own separate namespace, they can easily be confusing (at least to \acmd{\setkeys}) if they have names identical to other keys within the same family and with the same prefix. In fact, the problem can manifest itself in more ways than the scenario just depicted.

If the package option \acmd{verbose} is enabled, the \pkg{skeyval} provides a warning system (by making an entry in the transcript log file) if an existing key is being redefined (within the same family and with the same prefix) by any of the following commands:
\begin{macro}
\define@key, \define@cmdkey, \define@cmdkeys,
\define@choicekey, \define@boolkey, \define@boolkeys,
\define@biboolkeys, \define@uniboolkeys, \define@biuniboolkeys,
\define@togkey, \define@togkeys, \define@bitogkeys,
\define@unitogkeys, \define@biunitogkeys
\end{macro}

The machinery of \cref{sec:avoiding-redef} can be used to avoid inadvertently redefining existing keys.

\subsubsection{Avoiding multiple definitions of same key}
\label{sec:avoiding-redef}

For the above reasons, the \pkg{skeyval} introduces the following commands, which have the same syntaxes as their counterparts from the \asty{xkeyval} and \asty{skeyval} packages but which bar the user from repeated definition of keys with identical names within the same \ang{family} and with the same \ang{prefix}:
\acmd*{\define@boolkey}
\acmdm*{\newordkey,\newcmdkey,\newboolkey,\newboolkeys,\newtogkey,\newtogkeys,
\newchoicekey,\newbiboolkeys,\newuniboolkeys,\newbiuniboolkeys,\newbitogkeys,
\newunitogkeys,\newbiunitogkeys,\define@key,\define@cmdkey,
\define@cmdkeys,\define@biboolkeys,\define@uniboolkeys,
\define@biuniboolkeys,\define@bitogkeys,\define@unitogkeys,\define@biunitogkeys}
\begin{macro}
|comm(The following defines ``ordinary'' keys |:the counterpart)
|comm(of \define@key from the xkeyval package|!:)
\newordkey[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(default)]{|vang(funtion)}

|comm(Counterpart of \define@cmdkey:)
\newcmdkey[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
  {|vang(funtion)}

|comm(Counterpart of \define@cmdkeys:)
\newcmdkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(keys)}[|vang(default)]

|comm(Counterparts of \define@boolkey:)
\newboolkey[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
  {|vang(funtion)}
\newboolkey|redplus[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
  {|vang(funtion1)}{|vang(funtion2)}

|comm(Counterpart of \define@boolkeys:)
\newboolkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(keys)}[|vang(default)]

|comm(Counterpart of \define@biboolkeys:)
\newbiboolkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
  {|vang(primary boolean)}[|vang(default value for primary boolean)]
  {|vang(secondary boolean)}{|vang(func for primary boolean)}
  {|vang(func for secondary boolean)}

|comm(Counterpart of \define@uniboolkeys:)
\newuniboolkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
  {|vang(primary boolean)}[|vang(default value for primary boolean)]
  {|vang(secondary boolean)}{|vang(func for primary boolean)}
  {|vang(func for secondary boolean)}

|comm(Counterpart of \define@biuniboolkeys:)
\newbiuniboolkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
  {|vang(primary boolean)}[|vang(default value for primary boolean)]
  {|vang(secondary boolean)}{|vang(func for primary boolean)}
  {|vang(func for secondary boolean)}

|comm(Counterparts of \define@togkey:)
\newtogkey[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
  {|vang(funtion)}
\newtogkey|redplus[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(key)}[|vang(default)]%
  {|vang(funtion1)}{|vang(funtion2)}

|comm(Counterpart of \define@togkeys:)
\newtogkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]{|vang(keys)}[|vang(default)]

|comm(Counterpart of \define@bitogkeys:)
\newbitogkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
  {|vang(primary toggle)}[|vang(default value for primary toggle)]
  {|vang(secondary toggle)}{|vang(func for primary toggle)}
  {|vang(func for secondary toggle)}

|comm(Counterpart of \define@unitogkeys:)
\newunitogkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
  {|vang(primary toggle)}[|vang(default value for primary toggle)]
  {|vang(secondary toggle)}{|vang(func for primary toggle)}
  {|vang(func for secondary toggle)}

|comm(Counterpart of \define@biunitogkeys:)
\newbiunitogkeys[|vang(prefix)]{|vang(family)}[|vang(mp)]
  {|vang(primary toggle)}[|vang(default value for primary toggle)]
  {|vang(secondary toggle)}{|vang(func for primary toggle)}
  {|vang(func for secondary toggle)}

|comm(Counterparts of \define@choicekey:)
\newchoicekey[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(bin)]{|vang(alt)}%
  [|vang(default)]{|vang(funtion)}
\newchoicekey|redstar[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(bin)]{|vang(alt)}%
  [|vang(default)]{|vang(funtion)}
\newchoicekey|redplus[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(bin)]{|vang(alt)}%
  [|vang(default)]{|vang(funtion1)}{|vang(funtion2)}
\newchoicekey|redstar|redplus[|vang(prefix)]{|vang(family)}{|vang(key)}[|vang(bin)]{|vang(alt)}%
  [|vang(default)]{|vang(funtion1)}{|vang(funtion2)}

|comm(Counterpart of \define@keylist:)
\newkeylist{|vang(key type/id), |vang(key), |vang(key default value),
  |vang(key macro/function); |vang(another set of key specifiers); etc}.
\end{macro}
\acmdm*{\define@choicekey,\newchoicekey*,\newchoicekey*+,\newkeylist,\newkeylist*}

The following aliases are defined in the \pkg{skeyval}:
\begin{macro}
\define@menukey|redstar|redplus    |tto    \define@choicekey|redstar|redplus
\newmenukey|redstar|redplus        |tto    \newchoicekey|redstar|redplus
\end{macro}
\acmdm*{\define@menukey, \define@menukey*, \newmenukey, \newmenukey*}

We could simply have redefined/modified the legacy key definition commands in the \pkg{xkeyval} to make it impossible to define keys of the same name in the same family and with the same prefix, but this approach would be unsafe since there are many packages using the \pkg{xkeyval} and those packages may well have redefined identical keys. Moreover, the legacy key definition commands from the \pkg{xkeyval} may be needed to redefine a disabled key (see \cref{sec:disable-reserv-keys}).

All the commands of the type \textnewkey are robust and may be used in expansion contexts without fear of premature expansion, although expandable tokens in the definition may need to be protected. Commands of the type \textdefinekey are originally, in the \pkg{xkeyval}, non-robust and remain so in the \pkg{skeyval}.

With the above macros, the following will flag an understandable error message, namely that the key \ang{keya} is about being redefined in the same family \ang{fam} and with the same prefix \ang{KV}:
\begin{example}
\newordkey[KV]{fam}{keya}[$\star$]{\def\tempa##1{##1}}

\newboolkey[KV]{fam}{keya}[true]{%
  \ifKV@fam@keya\def\tempb{#1}\fi}
\end{example}

\section[Disabling, reserving, suspending keys, etc.]%
  {Disabling, localizing, reserving, suspending, restoring, and removing keys}
\label{sec:disable-reserv-keys}

Besides macros for defining keys, the \pkg{skeyval} also introduces mechanisms for disabling, localizing, reserving, suspending, restoring, and completely removing existing keys.

\subsection{Disabling keys}
\label{sec:disable-keys}

The \pkg{skeyval} has modified the definition of \fx{\disable@keys} from the \pkg{xkeyval} to allow for looping over key prefixes and key families and for bespoke warnings and error messages, without engendering any potential conflict with the legacy \fx{\disable@keys}. The new command is still called \fx{\disable@keys} and has the same syntax as the native \fx{\disable@keys} of the \pkg{xkeyval}, except that the new command accepts key prefixes (instead of just one prefix) and key families (instead of just one family):
\begin{macro}
\disable@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)}.
\end{macro}
\acmdm*{\disable@keys}
Here \ang{prefixes}, \ang{families}, \ang{keys} are lists of comma-separated entries referring to the keys to be disabled. Each of the lists \ang{prefixes}, \ang{families}, \ang{keys} may contain nil, one or more elements. If any of the members in \ang{keys} can't be located in \ang{families} and with prefix in \ang{prefixes}, an informational (not error) message is logged in respect of this member, but only if the package option \fx{verbose} is selected.

The legacy version of \fx{\disable@keys} (\ie, that of the \pkg{xkeyval}) is still available via the starred variant:
\begin{macro}
\disable@keys|redstar[|vang(prefix)]{|vang(family)}{|vang(keys)}
\end{macro}
\acmdm*{\disable@keys*}
Note that this doesn't accept key prefixes and families, but only one key prefix and only one key family: the \fx{\disable@keys} command from the \pkg{xkeyval} can only be used to disable keys with the same \ang{prefix} and from the same \ang{family}, but not across prefixes and families.

Any attempt to subsequently set or use a disabled key will prompt the following error message. (The \pkg{xkeyval} issues a warning in this case.) The error message can be modified by the user, but the names of the controls \fx{\SKV@disabledkey@err} and \acmd{\SKV@disabledkey} should be retained.
\begin{macro}
\def\SKV@disabledkey@err{%
  \PackageError{skeyval}{%
    Key |vang(key) with prefix |vang(prefix) in family |vang(family)
    was disabled on input line |vang(lineno)
  }{%
    You can't set or reset |vang(key) at this
    late stage. Perhaps you're required to set it
    earlier, within a package or in the document's preamble.
  }%
}
\end{macro}
\acmdm*{\SKV@disabledkey@err}
If the user attempts to disable an undefined key, the \pkg{xkeyval} issues a fatal error; the \pkg{skeyval}, on the other hand, issues a warning in the transcript log file (if the package option \acmd{verbose} is selected), since the situation isn't fatal to the outcome of the \latex pass or the document.

Disabled keys can be redefined with commands in the \textdefinekey category but not with commands in the \textnewkey category, since a disabled key remains defined: only its macro has been replaced by an error message signifying the disabling of the key.

\textbf{Note:} Reserved and suspended keys can't be disabled, until they are unreserved or restored (see \crefrange{sec:reserve-keys}{sec:suspend-keys}).

\subsection{Localizing keys}
\label{sec:local-keys}

By localizing a key we mean disabling a key at the end of the current class or package file. This is basically the command \acmd{\disable@keys} executed on the hook \acmd{\SKV@BeforeClassEnd} or \acmd{\SKV@BeforePackageEnd}, depending on \acmd{\@currext}. The hooks \acmd{\SKV@BeforeClassEnd} and \acmd{\SKV@BeforePackageEnd} are described in \cref{sec:misce-commands} (\macrangeref{befpkgend}{befclsend}).

The syntax for localizing keys is exactly like that for disabling keys:
\begin{macro}
\localize@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)}.
\end{macro}
\acmdm*{\localize@keys}
If any of the members of the set \ang{keys} is not found in any of the members of \ang{families} and with a prefix from \ang{prefixes}, an informational message is written into the log file (if the package option \fx{verbose} is selected), but no errors are flagged.

The starred variant of \fx{\localize@keys} disables the keys listed in \ang{keys}, not at the end of the package or class file, but right before the start of document (\ie, at the boundary between the document preamble and \acmd{\AtBeginDocument}):
\begin{macro}
\localize@keys|redstar[|vang(prefixes)]{|vang(families)}{|vang(keys)}.
\end{macro}
\acmdm*{\localize@keys*}
The hook used here is \acmd{\SKV@BeforeDocumentStart}, described in \cref{sec:misce-commands}, \macref{beforedocstart}.

A key can be localized as soon as it is defined. In fact, a key can be localized even before it is defined: the actual disablement of the key will take place at the execution of the contents of \acmd{\SKV@BeforeClassEnd} or \acmd{\SKV@BeforePackageEnd} or \acmd{\SKV@BeforeDocumentStart}.

Localized keys can be redefined with commands in the \textdefinekey category, but not with commands in the \textnewkey category.

\subsection{Reserving and unreserving keys}
\label{sec:reserve-keys}

The \pkg{xkeyval} bars its users from defining new keys with \fx{XKV} as a prefix. The \pkg{skeyval} generalizes this concept via the following three developer macros:
\begin{macro}
\ReserveKeyPrefixNames{|vang(list)}
\end{macro}
\acmdm*{\ReserveKeyPrefixNames}
This allows the package developer to bar the future use of names appearing in \ang{list} as key prefixes when defining, disabling, reserving and suspending keys; but not when setting keys. The \ang{list}, whose members are comma-separated, can be populated by the package developer as required.

\begin{macro}
\ReserveMacroPrefixNames{|vang(list)}
\end{macro}
\acmdm*{\ReserveMacroPrefixNames}
This has a similar functionality to \fx{\ReserveKeyPrefixNames}, but applies to macro prefixes instead of key prefixes.

\begin{macro}
\ReserveFamilyNames{|vang(list)}
\end{macro}
\acmdm*{\ReserveFamilyNames}
This reserves family names \ang{list} and prevents further use of members of \ang{list}.

\textbf{Note:} The lists in these macros are scanned only when defining, disabling, reserving or suspending keys, and not when setting existing keys. If the lists were also to be scanned when keys are being set, then a situation could arise in which existing keys (including those defined by prior packages) couldn't be set.

These macros could be used, for instances, to secure against future use the key prefixes, macro prefixes, and key families that have used in a new style or class file. For example, we have used these facilities to bar users of the \pkg{skeyval} from using the key prefix \fx{SKV}, the family name \fx{skeyval}, and the macro prefix \fx{SKV@} to define new keys in their packages.

\begin{macro}
\ReserveKeyPrefixNames|redstar{|vang(list)}
\ReserveMacroPrefixNames|redstar{|vang(list)}
\ReserveFamilyNames|redstar{|vang(list)}
\end{macro}
%\acmd*{\ReserveKeyPrefixNames}
\acmdm*{\ReserveFamilyNames*,\ReserveKeyPrefixNames*,\ReserveMacroPrefixNames*}
These starred variants take effect at end of current package; the unstarred ones above assume immediate effect. If the developer wants to use any member of \ang{list} in his own package, it may be necessary for him to use the starred versions.

In addition to the above reservation commands, the \pkg{skeyval} also introduces the following command:
\begin{macro}
\reserve@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)},
\end{macro}
\acmdm*{\reserve@keys}
where the lists \ang{prefixes}, \ang{families}, \ang{keys} can contain nil, one or more elements. Defined, reserved and suspended keys can't be reserved.

Reserved keys have to be unreserved with the following command before they can be defined and used:
\begin{macro}
\unreserve@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)},
\end{macro}
\acmdm*{\unreserve@keys}
where, again, the lists \ang{prefixes}, \ang{families}, \ang{keys} can contain nil, one or more elements. If a key was not previously reserved, this command will simply issue an informational message in the log file (if the package option \fx{verbose} is selected) and ignore that key. Defined keys and suspended keys can also be unreserved, which is equivalent to removing the keys (see \cref{sec:remove-keys}).

\subsection{Suspending and restoring keys}
\label{sec:suspend-keys}

For some keys, it might be preferable to temporarily suspend them from a family (rather than disable or remove them) and restore them later. In this way, a key's state and macro can be frozen while the key remains defined.

The syntax for suspending keys is
\begin{macro}
\suspend@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)},
\end{macro}
\acmdm*{\suspend@keys}
where the lists \ang{prefixes}, \ang{families}, \ang{keys} can contain nil, one or more elements.
A key of particular prefix not previously defined in a family can't be suspended from that family. Similarly, a key previously suspended from a family can't be suspended again (for the second time) from the same family without being first restored in that family.

Suspended keys can be restored to their frozen states (\name{ex ante} suspension) by the following command:
\begin{macro}
\restore@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)}.
\end{macro}
\acmdm*{\restore@keys}
Only keys (with a given prefix) previously suspended from a family can be restored in that family: ``unsuspended'' keys can't be restored.

\subsection{Removing keys}
\label{sec:remove-keys}

The \pkg{skeyval} provides for removing keys completely, such that any attempt to set or use a removed key will prompt the error message that the key is undefined in the given family and with the given prefix. The command \acmd{\key@ifundefined} from the \pkg{xkeyval} and the macro \acmd{\ifkeydefined} from the \pkg{skeyval} will both identify a removed key as undefined. The syntax for removing keys is:
\begin{macro}
\remove@keys[|vang(prefixes)]{|vang(families)}{|vang(keys)}
\end{macro}
\acmdm*{\remove@keys}

Removed keys can't be restored but can be redefined with the commands in both the \textnewkey and \textdefinekey categories.

\section{User-value keys}
\label{sec:uservaluekeys}

We define these keys as those for which the user must supply values at key setting time whether or not the keys have default values. All the commands for defining new keys have a facility for providing the default value of a key, which would be used by the \acmd{\setkeys} macro if the user didn't supply a value for the key. If no default value has been specified for a key at definition time and no value is provided at key setting time, the \pkg{xkeyval} will issue a fatal error. This scenario is preserved by the \pkg{skeyval}. In addition, the \pkg{skeyval} introduces a facility for requiring a user to supply a value for a key whether or not that key had a default value at definition time. Why is this necessary or useful? You may specify default values for keys in a package or class file to aid future revisions of the package, or for other purposes, but such values may not be suitable for all users---or indeed for any user. Examples of this type of situation abound: the signatory to a letter, the module code or title in a faculty programme, \etc.

The following command can be used to require a user to supply a value for a key at key setting time, whether or not that key has a default value:
\begin{macro}
\uservaluekeys[|vang(prefix)]{|vang(family)}{|vang(keys)}
\end{macro}
\acmdm*{\uservaluekeys}
where \ang{keys} is the list of keys with \ang{prefix} and in \ang{family} for which the user must supply values at key setting time. It is obviously not logical to loop over key prefixes or families in this case. What the command \fx{\uservaluekeys} does is to populate the container \fnl{SKV}{prefix}{family}{uservalue} which is scanned for user-value key names at key setting time.

The \fx{\uservaluekeys} macro works incrementally, \ie, new inputs are added to an existing list for the family in question only if they haven't previously been included.

\begin{example}
\newcmdkey[KV]{fam}[mp@]{keya}[12pt]{\def\x{#1}}
\newboolkey[KV]{fam}[mp@]{boola}[true]%
  {\ifmp@boola\def\x{#1}\fi}

\uservaluekeys[KV]{fam}{keya,boola}

\setkeys[KV]{fam}{keya,boola=true}
        |tto  |makered(Error: no value supplied for `keya')
\end{example}
\acmd*{\newcmdkey,\newboolkey,\setkeys}
%\acmd*{\uservaluekeys}

\subsection{Using pointers to dynamically indicate user-value keys}
\label{sec:uservalue-pointers}

Instead of using the macro \fx{\uservaluekeys} to accumulate user-value keys, there is another way to dynamically specify these keys at key definition time: by using pointers. At key definition time, the pointers \acmdm{\uservalue}  and \acmdm{\guservalue} can be associated with a user-value key. In the following statements, the pointer \fx{\uservalue} specifies that the user of the affected key must supply a value at the time of using/setting the key. The pointer \fx{\uservalue} has local effect, \ie, its impact can't escape local groups; on the other hand, \fx{\guservalue} has global effect, \ie, using it within or out of a local group means that the user of the affected key must specify a value for the key at key setting time. \fx{\guservalue} ensures that the internal container \fnl{SKV}{prefix}{family}{uservalue} is defined globally so that the settings can escape local groups.

\begin{example}
\newordkey[KV]{fam}{|makered(\uservalue{|mcolor(keya)})}[12pt]{\def\x{#1}}

\define@togkey|redplus[KV]{fam}[mp@]{|makered(\guservalue{|mcolor(toga)})}[true]%
{%
  \iftogon{mp@toga}{\def\x{#1}}{}%
}{%
  \@latex@error{Value `#1' not valid}\@ehc
}
\end{example}
\acmd*{\newordkey,\define@togkey,\iftogon}

As these examples show, the newly introduced pointers (namely, \fx{\uservalue} and \fx{\guservalue}) can be used to dynamically build a list of user-value keys. See \cref{sec:pointer-mech} for more comments on pointer systems.

\section{Extensions to the pointer system of the \texttt{xkeyval} package}
\label{sec:pointer-mech}

The \pkg{xkeyval} introduced a key pointer system. This basically involves the pointers
\acmdm{\savevalue}, \acmdm{\gsavevalue}, and \acmdm{\usevalue}. However, by the mechanism of that package, these pointers could be used only within the \acmd{\setkeys} command or context. In the key definition commands, the \fx{\usevalue} pointer could also be used in default values of keys, as in
\begin{example}
\define@key{fam}{keya}{\def\keya{#1}}
\define@key{fam}{keyb}[|makered(\usevalue{|mcolor(keya)})]{\def\keyb{#1}}
\define@key{fam}{keyc}[|makered(\usevalue{|mcolor(keyb)})]{\def\keyc{#1}}

\setkeys{fam}{|makered(\savevalue{|mcolor(keya)})=test}
\setkeys{fam}{|makered(\savevalue{|mcolor(keyb)})}|comm(Yes, this also works.)
\setkeys{fam}{keyc}
\end{example}
\acmd*{\define@key,\setkeys}
The default values of keys are called (invoked) within \acmd{\setkeys}. The pointers can't, however, be used as part of key names outside default values. The following, \eg, fails:
\begin{example}
\define@key{fam}{|makered(\savevalue{|mcolor(keya)})}{\def\keya{#1}}
\end{example}
The \pkg{skeyval} has extended the pointer system to be issuable as part of key names within key definition commands in the two scenarios illustrated above (within and outside default values). Moreover, the pointers \fx{\savevalue} and \fx{\gsavevalue} can be deployed concurrently with \acmd{\uservalue} and \acmd{\guservalue} of \cref{sec:uservalue-pointers} within the same key definition command. In combining the two pointer subclasses (\ie, \fx{\savevalue} subclass and \acmd{\uservalue} subclass) in the same key definition command, it doesn't matter which subclass comes first, as the following examples show.

The pointers \fx{\savevalue} and \fx{\gsavevalue} make entries into the container \fnl{XKV}{prefix}{family}{save} that is used by the \pkg{xkeyval} to hold keys whose values should be saved at key setting time. The difference between \fx{\savevalue} and \fx{\gsavevalue} is that the former has a local effect while the latter can escape local groups (similar to the group properties of \acmd{\uservalue} and \acmd{\guservalue} of \cref{sec:uservalue-pointers}). The pointers \fx{\savevalue} and \fx{\gsavevalue} of the \pkg{skeyval} are entirely compatible with those of the \pkg{xkeyval}. One additional new feature is that the pointer \fx{\gsavevalue} prompts the global revision of the container \fnl{XKV}{prefix}{family}{save} and also makes global pointer entries\footnote{By \emph{global pointer entry} we mean an entry like \fx{\global{keya}} for \fx{keya} into the container \fnl{XKV}{prefix}{family}{save}.} of the affected keys into the container. The effects of the new feature are illustrated by the following examples. Depending on application, this new feature may be more attractive than the traditional one implemented via \acmd{\setkeys}. One obvious advantage of the new system emanates from the fact that some keys do not have default values.

\subsection{Examples}

\subsubsection{Legacy \texttt{xkeyval} pointer features}

The following provide examples of legacy pointer features of the \pkg{xkeyval} (key pointers at key setting time):
\acmdm*{\gsavekeys,\savekeys,\global\{key\}}
\begin{example}
\savekeys[KV]{fam}{keya,|makered(\global{|mcolor(keyb)})}
\gsavekeys[KV]{fam}{keyc,keyd,|makered(\global{|mcolor(keye)})}|label(mac:gsavekeys)

\setkeys[KV]{fam}{|makered(\gsavevalue{|mcolor(keyd)})=yyy,|label(mac:setkeyd)
  keye=|makered(\usevalue{|mcolor(keyd)})}
\end{example}

If we had included \fx{\global{keyb}} in \fx{\gsavekeys} of \macref{mac:gsavekeys}, its entry in \fx{\savekeys} would have been overwritten, since keys in the container \acmdm{\XKV@KV@fam@save} normally get overwritten if they have the same name. The macro \fx{\gsavekeys} ensures the global definition of \fx{\XKV@KV@fam@save} when the keys \fx{keyc}, \fx{keyd} and \fx{keye} are being included, while \fx{\global{keyb}} ensures that, when \fx{keyb} is used in a \acmd{\setkeys} command, its value will be saved globally to \fx{\KV@fam@keyb@value}. When the keys \fx{keyc} and \fx{keyd} are set, their values will be saved locally, even though the container \fx{\XKV@KV@fam@save} was defined globally when the keys \fx{keyc} and \fx{keyd} were inserted. However, when keys \fx{keyb} and \fx{keye} are set, their values will be saved globally (even though \fx{keyb} appears in \fx{\savekeys} and not in \fx{\gsavekeys}).

The pointer \fx{\gsavevalue{keyd}} of \macref{mac:setkeyd} will ensure that the value of \fx{keyd} is saved globally to \fx{\KV@fam@keyd@value} at \acmd{\setkeys}.

\subsubsection{Extensions by \texttt{skeyval} package}

The following provide examples of new pointer features enabled by the \pkg{skeyval} (key pointers at key definition time):

\begin{example}
\define@key[KV]{fam}{|makered(\savevalue{|mcolor(keya)})}[xxx]{\def\x{*#1*}}

\newordkey[KV]{fam}{|makered(\gsavevalue{|mcolor(keyb)})}[zzz]{\def\x{=#1=}}|label(mac:pointers:a)

\newtogkey|redplus[KV]{fam}[mp@]{|makered(\savevalue\uservalue{|mcolor(toga)})}[true]%
{
  \iftogon{mp@toga}{\def\x{#1}}{}%
}{%
  \@latex@error{Value `#1' not valid}\@ehc
}

\define@cmdkey[KV]{fam}[mp@]{|makered(\uservalue\savevalue{|mcolor(keyc)})}%
  [www]{\def\x{#1}}

\newboolkey|redplus[KV]{fam}[mp@]{|makered(\gsavevalue\uservalue{|mcolor(boola)})}%
[true]{%
  \ifmp@boola\def\x{#1}\fi
}{%
  \@latex@error{Value `#1' not valid}\@ehc
}

\define@cmdkey[KV]{fam}[mp@]{|makered(\guservalue\savevalue{|mcolor(keyd)})}%
  [www]{\def\x{#1}}

\newchoicekey|redstar|redplus[KV]{fam}{|makered(\guservalue\gsavevalue{|mcolor(align)})}%
[\val\nr]{center,right,left}[center]%
{%
  \ifcase\nr\relax
    \def\@align{\centering}%
  \or
    \def\@align{\flushright}%
  \or
    \def\@align{\flushleft}%
  \fi
}{%
  \@latex@error{Inadmissible value `#1' for align}\@ehc
}

\setkeys[KV]{fam}{keya=Hello World,keyb=|makered(\usevalue{|mcolor(keya)})}
\end{example}
\acmd*{\define@key,\define@cmdkey,\newchoicekey,\newordkey,
\newtogkey,\setkeys,\iftogon}

With the new mechanism of the \pkg{skeyval}, the \acmd{\gsavevalue} pointer in the command on \macref{mac:pointers:a} will ensure that \fx{\global{keyb}} (not \fx{keyb}) is inserted in the container \fx{\XKV@KV@fam@save} and that this container is updated globally after \fx{\global{keyb}} has been inserted. At \acmd{\setkeys}, in view of the entry \fx{\global{keyb}}, the value of \fx{keyb} will be saved globally. The same applies to keys \fx{boola} and \fx{align}. This thus has a double effect. Keys \fx{keyc} and \fx{keyd} will be saved locally.

\section{Setting keys: list normalization}
\label{sec:list-normal}

We have redefined the \acmd{\setkeys} command of the \pkg{xkeyval} in two respects: firstly to accommodate the use of the \acmd{\skif}, \acmd{\skifx}, \acmd{\skelse}, and \acmd{\skfi} macros of \cref{sec:pseudo-primitives}, and secondly to automatically convert double (or even multiple) commas and equality signs inadvertently submitted by the user into single comma and single equality sign. The following exaggerated example depicts the difficulties that might arise and which we wish to address:
\begin{example}
\define@key[KV]{fam}{width}[1cm]{}
\define@key[KV]{fam}{color}[black]{}
\setkeys[KV]{fam}{width= =2cm, ,,color, == = =,green}
\end{example}
\acmd*{\define@key,\setkeys}

Here, the legacy \acmd{\setkeys} will give the value nil to the key \fx{width}, and the default value of the key \fx{color}, if it was specified at key definition time, will be given to the key \fx{color}. Some of the mistakes (especially spurious values without keys) can disrupt a compilation run, while some (multiple commas and equality signs) will not be fatal to compilation but may lead to bizarre results of subsequent calculations. Mistakes of this kind can, surprisingly, be difficult to trace. The extra spaces and multiple commas aren't as serious as the multiple equality signs and values without keys, but we have taken care of all peculiar situations in the new \acmd{\setkeys}. Multiple commas, equality signs, and spaces are now detected and reduced appropriately: that is what we mean by key-value \emph{list normalization}. We have adopted the premise that ``\fx{,=}'' (comma followed by equal) and ``\fx{=,}'' (equal followed by comma) are both most likely to mean ``\fx{=}'' (equal). In the unlikely event that this premise fails, then the user may get tricky errors if he makes this type of mistake.

If, for any reason, the user needs to pass keys with ``\fx{,=}'' and/or ``\fx{=,}'', then he may separate the comma from the equality sign with \fx{{}}, \eg, as in
\begin{example}
\setkeys[KV]{fam}{width=2cm,head={},tail=not measured},
\end{example}
\acmd*{\setkeys}
which shows that the value of the key \fx{head} is \fx{\empty}, a valid and better assignment.

\section{Miscellaneous macros}
\label{sec:misce-commands}

This package is predominantly about \latex keys and their efficient creation and management, but it also contains many commands for general \tex programming, such that a package author may not need to redefine most of them or load some other packages to access those commands. Some of the available commands are described in this section. The index provides a comprehensive quick resource locator for the commands.

\macrosection{Defining new commands}

The following are provided in the \pkg{skeyval} but you're advised to use the \fx{\TestProvidedCommand} macro (described below) to test that you are really using the \fx{\newdef} of the \pkg{skeyval}:
\begin{macro}
\SKV@newdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\newdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\end{macro}
\acmdm*{\SKV@newdef,\SKV@newdef*,\newdef,\newdef*}
These commands adopt \tex's syntax and accept parameter delimiters. They are both robust. The unstarred variant produces long macros. The command \fx{\newdef} is defined in the \pkg{skeyval} only if it hasn't been defined by a previously loaded package; the command \fx{\SKV@newdef}, on the other hand, is always available. If \ang{cs} was previously defined, both \fx{\SKV@newdef} and \fx{\newdef} will issue an error.

\macrosubsection{Defining robust commands}

\begin{macro}
\SKV@robustdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\robustdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\end{macro}
\acmdm*{\SKV@robustdef,\SKV@robustdef*,\robustdef,\robustdef*}
These use \etex's \acmd{\protected} prefix to provide something resembling \latex's \acmdm{\DeclareRobustCommand} whilst conforming to \tex's \fx{\def} interface. The unstarred variants produce long macros. These commands accept parameter delimiters and are all robust. The command \fx{\robustdef} is defined in the \pkg{skeyval} only if it hasn't been defined by a previously loaded package; the command \fx{\SKV@robustdef}, on the other hand, is always available. If \ang{cs} was previously defined, both \fx{\SKV@robustdef} and \fx{\robustdef} will issue an error. You can use the above \fx{\TestProvidedCommand} to check whether or not you are using the \fx{\robustdef} of the \pkg{skeyval}.

\macrosubsection{\tex-like \@bs providecommand}

\begin{macro}
\SKV@providedef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\providedef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\SKV@providerobustdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\providerobustdef|redstar|vang(cs)|vang(parameters){|vang(replacement text)}
\end{macro}
\acmdm*{\SKV@providedef,\SKV@providerobustdef,\providerobustdef,
\SKV@providedef*,\SKV@providerobustdef*,\providerobustdef*}
\acmds*\providedef\SKV@providedef
These emulate \latex's \acmdm{\providecommand}, but they conform to \tex's \fx{\def} interface. The unstarred variants produce long macros. These commands accept parameter delimiters and are all robust. The commands \fx{\providedef} and \fx{\providerobustdef} are defined in the \pkg{skeyval} only if they haven't been defined by a previously loaded package; the commands \fx{\SKV@providedef} and \fx{\SKV@providerobustdef}, on the other hand, are always available. Macros defined by \fx{\SKV@providerobustdef} and \fx{\providerobustdef} are robust, while those defined by \fx{\SKV@providedef} and \fx{\providedef} are nonrobust. If \ang{cs} was previously defined, all these commands will simply ignore the new definition and enter a message to this effect in the log file (if the package option \fx{verbose} is selected).

\macrosubsection{\@bs requirecmd}

\begin{macro}
\requirecmd{|vang(cs)}[|vang(number of args)][|vang(default)]%
  {|vang(replacement text)}
\end{macro}
This is explained in \cref{sec:toggle-booleans}. If \ang{cs} is already defined, \acmdm{\requirecmd} checks if the new and old definitions are identical. If they aren't, a warning message is logged in the transcript file (if the package option \fx{verbose} is selected) and the new definition is aborted.

\macrosubsection{Testing \emph{provided} commands}

\begin{macro}
\TestProvidedCommand|vang(cs){|vang(true text)}{|vang(false text)}|label(mac:testprovide)
\end{macro}
This can be used to test whether or not one is using the \fx{\newdef} (or any other ``provided'' command) of the \pkg{skeyval}. Here \ang{cs} is either \fx{\newdef} or any ``provided'' command. In fact, if you define any command using the macro \fx{\SKV@providedef} or \fx{\SKV@providerobustdef} (see below), you can verify by \acmdm{\TestProvidedCommand} whether or not the new definition is the one in effect.

\begin{example}
\SKV@providerobustdef*\newcmd{\newcommand}

\TestProvidedCommand\newcmd{%
  \@latex@info{`\string\newcmd' is `\string\newcommand'}%
}{%
  \@latex@error{`\string\newcmd' isn't %
    `\string\newcommand'}\@ehd
}
\end{example}

\begin{example}
\SKV@providedef*\declarecommand{\newcommand}
\TestProvidedCommand\declarecommand{}%
  {\let\declarecommand\newcommand}
\end{example}

\macrosection{Declaring new unique variables collectively}

New definable variables can be introduced in sets by the following commands.

\begin{macro}
\NewBooleans[|vang(optional prefix)]{|vang(boolean list)}[|vang(optional state)]
\end{macro}
\acmdm*{\NewBooleans}
This provides, for each member of the comma-separated list \ang{boolean list}, a new native-boolean register if the register didn't already exist, otherwise an error is flagged. Each member of \ang{boolean list} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true}, \fx{false}, \fx{on} or \fx{off}. \fx{on} is synonymous with \fx{true}, whilst \fx{off} is equivalent to \fx{false}.
\begin{example}
\NewBooleans[bool]{a,b,c}[true]
  |tto  \newif\ifboola \newif\ifboolb \newif\ifboolc
      \boolatrue \boolbtrue \boolctrue

\NewBooleans{boold}  |tto  \newif\ifboold
\end{example}
Notice that members of the list \ang{boolean list} don't have \fx{\if} in their names.

\begin{macro}
\NewTogs[|vang(optional prefix)]{|vang(tog list)}[|vang(optional state)]
\end{macro}
\acmdm*{\NewTogs}
This provides a new toggle register for each member of the comma-separated list \ang{tog list} if the register didn't already exist, otherwise an error is flagged. Each member of \ang{tog list} is prefixed with \ang{prefix} upon definition. The optional \ang{state} can be either \fx{true},  \fx{false}, \fx{on} or \fx{off}. \fx{on} is synonymous with \fx{true}, whilst \fx{off} is equivalent to \fx{false}.
\begin{example}
\NewTogs[tog]{a,b,c}[true]
  |tto  \newtog{toga} \newtog{togb} \newtog{togc}
      \togon{toga} \togon{togb} \togon{togc}

\NewTogs{togd}  |tto  \newtog{togd}
\end{example}

\begin{macro}
\NewToks[|vang(optional prefix)]{|vang(toks list)}
\end{macro}
\acmdm*{\NewToks}\label{page:newtoks}
This provides a new token list register for each member of the comma-separated list \ang{toks list} if the register didn't already exist, otherwise an error is flagged. Each member of \ang{toks list} is prefixed with \ang{prefix} upon definition.
\begin{example}
\NewToks[toks]{a,b,c}
  |tto  \newtoks\toksa \newtoks\toksb \newtoks\toksc

\NewToks{toksd}  |tto  \newtoks\toksd
\end{example}

\begin{macro}
\NewCounts[|vang(optional prefix)]{|vang(counter list)}
\end{macro}
\acmdm*{\NewCounts}
This provides a new counter register for each member of the comma-separated list \ang{counter list} if the register didn't already exist, otherwise an error is flagged. Each member of \ang{counter list} is prefixed with \ang{prefix} upon definition.

\begin{macro}
\NewDimens[|vang(optional prefix)]{|vang(dimen list)}
\end{macro}
\acmdm*{\NewDimens}
This provides a new dimension register for each member of the comma-separated list \ang{dimen list} if the register didn't already exist, otherwise an error is flagged. Each member of \ang{dimen list} is prefixed with \ang{prefix} upon definition.

\begin{macro}
\NewBoxes[|vang(optional prefix)]{|vang(box list)}
\end{macro}
\acmdm*{\NewBoxes}
This allocates a new box register for each member of the comma-separated list \ang{box list} if the box register didn't already exist, otherwise an error is flagged. Each member of \ang{box list} is prefixed with \ang{prefix} upon definition.

\begin{example}
\NewBoxes[box]{a,b,c}
  |tto  \newbox\boxa \newbox\boxb \newbox\boxc

\NewBoxes{boxd} |tto  \newbox\boxd
\end{example}

\begin{macro}
\NewWrites[|vang(optional prefix)]{|vang(stream list)}
\end{macro}
\acmdm*{\NewWrites}
This allocates a new output stream for each member of the comma-separated list \ang{stream list} if the stream didn't already exist, otherwise an error is flagged. Each member of \ang{stream list} is prefixed with \ang{prefix} upon definition.
\begin{example}
\NewWrites[write]{a,b,c}
  |tto  \newwrite\writea \newwrite\writeb \newwrite\writec

\NewWrites{writed} |tto \newwrite\writed
\end{example}

\begin{macro}
\NewReads[|vang(optional prefix)]{|vang(stream list)}
\end{macro}
\acmdm*{\NewReads}

This allocates a new input stream for each member of the comma-separated list \ang{stream list} if the stream didn't already exist, otherwise an error is flagged. Each member of \ang{stream list} is prefixed with \ang{prefix} upon definition.

The macros \fx{\NewBooleans}, \fx{\NewToks}, \fx{\NewCounts}, \fx{\NewDimens}, \fx{\NewBoxes},  \fx{\NewWrites}, and \fx{\NewReads} are non-outer, unlike their primitive counterparts.

\macrosection{Defining new names}

\begin{macro}
\SKV@csdef|redstar|redplus{|vang(name)}{|vang(definition)}
\SKV@csgdef|redstar|redplus{|vang(name)}{|vang(definition)}
\SKV@csedef|redstar|redplus{|vang(name)}{|vang(definition)}
\SKV@csxdef|redstar|redplus{|vang(name)}{|vang(definition)}
\end{macro}
\acmdm*{\SKV@csdef,\SKV@csgdef,\SKV@csedef,\SKV@csxdef,
\SKV@csdef*,\SKV@csgdef*,\SKV@csedef*,\SKV@csxdef*,
\SKV@csdef*+,\SKV@csgdef*+,\SKV@csedef*+,\SKV@csxdef*+}

The variants of these commands without the plus (\RedPlus) sign turn \ang{name} into a control sequence in terms of \ang{definition} whether or not the control was already defined. No error or warning messages are issued. The variants with plus (\RedPlus) sign turn \ang{name} into a control sequence if it wasn't already defined; if it is already defined, an error message is flagged. The starred (\RedStar) variants give ``short'' macros, while the unstarred variants yield ``long'' definitions. These derive from a concept based on that of \acmd{\newcommand}, but (i)~\textrelaxed\ commands are considered undefined in this regard, and (ii)~these commands retain the powerful machinery of plain \tex.\footnote{The \pkg{skeyval} contains other undocumented tools for defining new commands.}

\macrosection{Name use}

\begin{macro}
\SKV@csuse{|vang(name)}
\end{macro}
\acmdm*{\SKV@csuse}
This is similar to \LaTeX's legacy \acmdm{\@nameuse} but returns \fx{\@empty} (instead of an error) if \ang{name} is undefined. This is due originally to \pkg{etoolbox}.

\macrosection{\texttt{\@bs let} assignments}

\begin{macro}
\SKV@newlet{|vang(cs1)}{|vang(cs2)}
\NewLet{|vang(cs1)}{|vang(cs2)}
\end{macro}
\acmdm*{\SKV@newlet,\NewLet}
These assign \ang{cs2} to \ang{cs1} if \ang{cs2} exists and if \ang{cs1} isn't already defined, otherwise an error is flagged. The command \fx{\NewLet} is defined in the \pkg{skeyval} only if it hasn't been defined by a previously loaded package; the command \fx{\SKV@newlet}, on the other hand, is always available. You can use \acmd{\TestProvidedCommand} (\macref{mac:testprovide}) to test whether or not you are using the \fx{\NewLet} command of the \pkg{skeyval}.

\begin{macro}
\SKV@cslet{|vang(name)}{|vang(cs)}
\SKV@letcs{|vang(cs)}{|vang(name)}
\SKV@csletcs{|vang(name)}{|vang(name)}
\end{macro}
\acmdm*{\SKV@cslet,\SKV@letcs,\SKV@csletcs}
These perform \fx{\let} assignments if the second argument is defined, otherwise an error message is flagged. The notation \ang{cs} means a control sequence, and \ang{name} means a control sequence name.

\begin{macro}
\SKV@cslet|redstar{|vang(name)}{|vang(cs)}
\SKV@letcs|redstar{|vang(cs)}{|vang(name)}
\SKV@csletcs|redstar{|vang(name)}{|vang(name)}
\end{macro}
\acmdm*{\SKV@cslet*,\SKV@letcs*,\SKV@csletcs*}
These perform \fx{\let} assignments whether or not the second argument is defined. If the second argument is undefined, the first remains undefined and the hash table is not filled.

\macrosection{Number and dimension expressions}

\begin{macro}
\SKV@numdef|redplus|redask{|vang(num)}{|vang(expression)}
\end{macro}
\acmdm{\SKV@numdef} defines \ang{num} from \ang{expression} using \etex's \acmd{\numexpr}. If \ang{num} was  previously undefined, it is first initialized with \acmd{\newcount} before the expression is built. If you do \fx{\SKV@numdef\x{1+2+3}}, you would need to prefix \fx{\x} with \fx{\the} or \acmd{\number} in expressions. Expressions defined by \fx{\SKV@numdef} can be used with \tex's operators such as \fx{\advance} or \fx{\multiply} and \etex's \acmd{\numexpr} operator.

The plus sign (\RedPlus) means that \fx{\SKV@numdef} takes a control sequence name instead of a control sequence, while the question mark (\RedAsk) implies that the macro \fx{\SKV@numdef} effects a global assignment which can thus escape local groups.

\begin{macro}
\SKV@dimdef|redplus|redask{|vang(dim)}{|vang(expression)}
\end{macro}
\acmdm{\SKV@dimdef} defines \ang{dim} from \ang{expression} using \etex's \acmd{\dimexpr}. If \ang{dim} was  previously undefined, it is first initialized with \acmd{\newdimen} before the expression is built. If you do \fx{\SKV@dimdef\x{1pt+2pt+3pt}}, you would need to prefix \fx{\x} with \fx{\the} in expressions. Expressions defined by \fx{\SKV@dimdef} can be used with \etex's \acmd{\dimexpr} operator.

The plus sign (\RedPlus) means that \fx{\SKV@dimdef} takes a control sequence name instead of a control sequence, while the question mark (\RedAsk) implies that the macro \fx{\SKV@dimdef} effects a global assignment which can thus escape local groups.

\macrosection{Verifying definability}

\begin{macro}
\SKV@ifdefinable|vang(cs){|vang(function)}
\SKV@csifdefinable|vang(cs name){|vang(function)}
\end{macro}
\acmdm*{\SKV@ifdefinable, \SKV@csifdefinable}
\latex kernel's \fx{\@ifdefinable} fills up the hash table and also considers commands that are \fx{\relax}'ed as defined. Moreover, if the command being tested (\ang{cs} in the above example) is definable, the \fx{\@ifdefinable} macro begins executing \ang{function} while still in the \fx{\if} \textellipsis \fx{\fi} conditional. You can't do \fx{\let\ifabc\iftrue} in such conditionals. The command \fx{\SKV@ifdefinable}, which is robust, seeks to avoid these problems. \fx{\SKV@csifdefinable} expects a control sequence name instead of a control sequence.

\begin{macro}
\SKV@ifdefinable@n{|vang(list)}
\end{macro}
The macro \acmdm{\SKV@ifdefinable@n} accepts a comma-separated list of control sequence \emph{names} whose definability are to be tested. It should be noted that the macro \fx{\SKV@ifdefinable@n} doesn't accept \ang{function}, unlike the above \fx{\SKV@ifdefinable}. The aim of \fx{\SKV@ifdefinable@n} is simply to test the definability of instances/members of \ang{list}.
\begin{example}
\SKV@ifdefinable@n{ax,ay,az}
\end{example}

\begin{macro}
\SKV@ifnewcmd|redstar|redplus[|vang(optional parser)]{|vang(list)}
\end{macro}
\acmdm*{\SKV@ifnewcmd,\SKV@ifnewcmd*,\SKV@ifnewcmd*+}

The macro \fx{\SKV@ifnewcmd} is similar to, but more versatile, than the command \fx{\SKV@ifdefinable@n}. The star sign (\RedStar) in \fx{\SKV@ifnewcmd} indicates that \ang{list} is available in a macro, say \fx{\mylist}; and the plus sign (\RedPlus) shows \fx{\SKV@ifnewcmd} that members of \ang{list} (or \fx{\mylist}) are control sequence names, otherwise they are control sequences (see examples below). The default value of the optional \ang{parser} is ``,'' (comma). The macro \fx{\SKV@ifnewcmd}, like \fx{\SKV@ifdefinable@n} but unlike \fx{\SKV@ifdefinable}, doesn't execute any \ang{function}. Both \fx{\SKV@ifdefinable@n} and \fx{\SKV@ifnewcmd} are robust.

\begin{example}
\def\mylist{ax,ay,az}
\SKV@ifnewcmd|redstar|redplus[,]\mylist
\SKV@ifnewcmd|redstar|redplus\mylist
\SKV@ifnewcmd|redplus{ax,ay,az}
\SKV@ifnewcmd{\ax\ay\az}
\def\my@list{\ax\ay\az}
\SKV@ifnewcmd|redstar\my@list
\def\my@@list{ax;ay;az}
\SKV@ifnewcmd|redstar|redplus[;]\my@@list
\SKV@ifnewcmd\ax |tto \SKV@ifnewcmd|redplus{ax} |tto \SKV@ifdefinable@n{ax}
\end{example}

\macrosection{Verifying the status of variables}

\begin{macro}
\SKV@ifdef|vang(cs){|vang(true)}{|vang(false)}
\SKV@ifcsdef{|vang(name)}{|vang(true)}{|vang(false)}
\SKV@ifundef|vang(cs){|vang(true)}{|vang(false)}
\SKV@ifcsundef{|vang(name)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifdef,\SKV@ifcsdef,\SKV@ifundef,\SKV@ifcsundef}
These use \etex's facilities to test the existence of the control sequence \ang{cs} or control sequence name \ang{name}. These commands aren't robust and may be used to determine the current state of the macro replacement text, if such replacement text contains these commands. \textrelaxed\ macros are considered undefined by \emph{all} these commands. To test if a macro is \textrelaxed, use the following commands:

\begin{macro}
\SKV@ifrelax|vang(cs){|vang(true)}{|vang(false)}
\SKV@ifcsrelax{|vang(name)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifrelax,\SKV@ifcsrelax}

\begin{macro}
\SKV@ifdefax|vang(cs){|vang(defined)}{|vang(relaxed)}{|vang(undefined)}
\SKV@ifcsdefax{|vang(name)}{|vang(defined)}{|vang(relaxed)}{|vang(undefined)}
\end{macro}
\acmdm*{\SKV@ifdefax,\SKV@ifcsdefax}
These test if \ang{cs} or \ang{name} is defined, relaxed, or undefined. In using these three-valued logical tests, it is often easy to forget to include the null state (\ie, \ang{undefined}) because  \tex is dominated by two-valued logical tests.

\macrosection{Undefining macros}

\begin{macro}
\SKV@Undef|redstar|redplus|redask[|vang(optional parser)]{|vang(cs)}
\end{macro}
\acmdm*{\SKV@Undef,\SKV@Undef*,\SKV@Undef*+,\SKV@Undef*+?}
This undefines the macros or control sequence names in the list \ang{cs} (of nil, one or more elements) such that \tex will subsequently consider each element undefined. The star sign (\RedStar) indicates that \ang{cs} is given as a macro whose \emph{contents} are to be individually undefined, and the plus sign (\RedPlus) shows that \ang{cs} is made up of \emph{control sequence names} instead of control sequences. The question mark (\RedAsk) directs \fx{\SKV@Undef} to \emph{globally} undefine all the control sequences or names in \ang{cs}. Control sequence names are to be separated by the parser; control sequences shouldn't be separated. The default value of the \ang{parser} is ``,'' (comma). The command \fx{\SKV@Undef} is robust (it will thus not expand in expansion contexts), but fragile arguments would need to be protected in expansion contexts.\footnote{Macros such as \acmdm{\@ifnextchar}, \acmdm{\@ifstar}, and those involving optional arguments normally can't be evaluated in expansion contexts. The same applies to the \pkg{skeyval} macros with optional arguments. The \pkgm{etextools} introduced expandable variants of these commands, but in the contexts these commands are employed in the \pkg{skeyval}, the expandable variants aren't particularly advantageous. The main reason is that some of our internal macros (\eg, looping macros) aren't amenable to full expansion anyway. Actually, the \pkg{skeyval} provides the fully expandable variants (\acmdm{\SKV@TestOpt}, \acmdm{\SKV@IfStar}, \acmdm{\SKV@IfPlus}, and \acmdm{\SKV@IfAsk}) of the non-expandable commands \acmdm{\SKV@testopt}, \acmdm{\SKV@ifstar}, \acmdm{\SKV@ifplus}, and \acmdm{\SKV@ifask}. The commands \fx{\SKV@ifask} and \fx{\SKV@IfAsk} look for an optional question mark (\RedAsk).}

\begin{example}
\def\unwanted{tempa,tempb,tempc,temp1}

\SKV@Undef|redstar|redplus|redask[,]\unwanted

\def\unwanted{t1emp,te2mp,tem3p}

\SKV@Undef|redstar|redplus|redask[,]\unwanted

\SKV@Undef|redplus|redask[;]{tempd;tempe;tempf}

\SKV@Undef\tempe

\SKV@Undef|redask{\tempea\tempeb\tempec\temped}

\SKV@Undef|redplus{tempf}

\SKV@Undef|redask\tempg

\def\notwanted{\temph\tempi\tempj}

\SKV@Undef|redstar\notwanted
\end{example}

The following non-generic variants avoid the above complications of signs, but they don't take lists:
\begin{macro}
\SKV@undef{|vang(cs)} |tto \SKV@Undef{|vang(cs)}
\SKV@gundef{|vang(cs)} |tto \SKV@Undef|redask{|vang(cs)}
\SKV@csundef{|vang(cs name)} |tto \SKV@Undef|redplus{|vang(cs)}
\SKV@csgundef{|vang(cs name)} |tto \SKV@Undef|redplus|redask{|vang(cs)}
\end{macro}
\acmdm*{\SKV@undef,\SKV@gundef,\SKV@csundef,\SKV@csgundef}

\macrosection{Expansion control}

\begin{macro}
\SKV@expox{|vang(cs)}
\end{macro}
\acmdm*{\SKV@expox}
This expands its argument \ang{cs} once and forbids further expansion.

\begin{macro}
\SKV@expcsox{|vang(name)}
\end{macro}
\acmdm*{\SKV@expcsox}
This is similar to \fx{\SKV@expox} but accepts control sequence name \ang{name} instead of control sequence.

\begin{macro}
\SKV@exptx{|vang(cs)}
\end{macro}
\acmdm*{\SKV@exptx}
This expands its argument \ang{cs} twice and forbids further expansion.

\begin{macro}
\SKV@expcstx{|vang(name)}
\end{macro}
\acmdm*{\SKV@expcstx}
This is similar to \fx{\SKV@exptx} but accepts control sequence name \ang{name} instead of control sequence.

\begin{macro}
\SKV@expargs|vang(n)|vang(function)|vang(arg1)|vang(arg2)\@nil
\end{macro}
\acmdm*{\SKV@expargs}
\LaTeX's \acmdm{\@expandtwoargs} is often used as a utility macro to expand two arguments \ang{arg1} and \ang{arg2} in order to execute \ang{function}. The command \fx{\SKV@expargs}, on the other hand, accepts up to four expansion types, signified by \ang{n}, which runs \mbox{from 0 to 3}:
\begin{enum}
\item If \ang{n} is 0, then \ang{arg2} is empty and only \ang{arg1} will be expanded before \ang{function} is executed.
\item If \ang{n} is 1, then both \ang{arg1} and \ang{arg2} are nonempty but only \ang{arg2} will be expanded before \ang{function} is executed.
\item When \ang{n} is 2, then both \ang{arg1} and \ang{arg2} are nonempty and both will be expanded before \ang{function} is executed. This is equivalent to \LaTeX's \fx{\@expandtwoargs}.
\item If \ang{n} is 3, then both \ang{arg1} and \ang{arg2} are nonempty but only \ang{arg1} is expanded before \ang{function} is executed.
\item If \ang{n} isn't in the list \fnv{0,1,2,3}, then an error message is flagged.
\end{enum}
Because \ang{arg2} is delimited, it can be empty. The command \fx{\SKV@expargs} can be used to save \fx{\expandafter}'s, but caution should be exercised in deploying it: for example, the \fx{\edef} it uses may expand too deeply in some cases. Also, precaution may be necessary when the expanded arguments (\ang{arg1} and/or \ang{arg2}) involve the \tex primitive \fx{\if}. When invoking \fx{\SKV@expargs}, the macros \fx{\SKV@expox} and \fx{\SKV@exptx} can be used to control the level of expansion.

Some trivial examples follow:
\begin{example}
\SKV@expargs{0}{\def\tempc#1#2}{\def\noexpand##1{##2}}\@nil|label(mac:expargs)
\tempc\tempa{aaa}
\tempc\tempb{abcaaabbccbca}
\SKV@expargs{2}\SKV@in@\tempa\tempb\@nil
\show\ifin@
\end{example}
\acmd*{\SKV@in@}

These expressions show how \fx{\SKV@expargs} can be used to economize on chains of \fx{\expandafter}'s. The expression on \macref{mac:expargs}, for example, isn't directly possible by \fx{\@expandtwoargs}.

\macrosection{Checking values of \texttt{choice} keys}

Choice keys should, by definition, have preordained values. This requirement can be useful even for non-choice keys, as we illustrate below.

\begin{macro}
\SKV@checkchoice{|vang(value)}{|vang(altlist)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@checkchoice}
This is an enhanced form of \pkg{xkeyval}'s \fx{\XKV@checkchoice}. It checks if the user-submitted \ang{value} of a key (say, \ang{keya}) is in the list \ang{altlist}. It executes \ang{true} if \ang{value} is found in \ang{altlist} and \ang{false} otherwise. Additionally, it returns \acmd{\val} for the expanded value of \ang{value} and \acmd{\nr} for the numerical order of \acmd{\val} in the list \ang{altlist}. If \ang{value} isn't found in \ang{altlist}, then \acmd{\nr} will return $-1$. If \ang{value} and \ang{altlist} are buried in macros, the macros are fully expanded before the search for \ang{value} in the list \ang{altlist} is effected. In that case, \acmd{\val} will hold the expanded form of \ang{value} and can be used in subsequent computations.

Choice keys do accept macros as values, but such values aren't directly suitable for matching against the contents of \ang{altlist}. For example, \ang{altlist} may be the set \fx{{left,right,center}}, but given as a macro \fx{\@altlist}, while \ang{value} is given as \fx{\def\@value{center}}. Obviously, \fx{\@value} contains one of the elements of \ang{altlist}, but choice keys won't know this without the expansion of both \fx{\@altlist} and \fx{\@value}. This is \name{raison d'\^e tre} of the \fx{\SKV@checkchoice} macro.

Moreover, \fx{\SKV@checkchoice} can be used in the definition of non-choice keys. In the following example we check the value of an \emph{ordinary} key by means of \fx{\SKV@checkchoice}:
\begin{example}
\def\@altlist{left,right,center}
\newordkey[KV]{fam}{keya}[true]{%
  \SKV@checkchoice{#1}{\@altlist}{%
    \ifcase\nr\relax
      \edef\tempa##1##2{##1===\val===##2}%
    \or
      \edef\tempa##1##2{##1***\val***##2}%
    \or
      \edef\tempa##1##2{##1+++\val+++##2}%
    \fi
  }{%
    \@latex@error{Wrong value for `keya'}\@eha
  }%
}
\def\@value{center}
\setkeys[KV]{fam}{keya=\@value}
\end{example}

The reader may wish to do \fx{\show\tempa} to see what \fx{\tempa} gets upon setting the key \fx{keya}.

\macrosection{Testing for substring}

\begin{macro}
\SKV@in@{|vang(substring)}{|vang(string)}
\end{macro}
\acmdm*{\SKV@in@}
This is similar to the \latex kernel's \fny{\in@}{substring}{string} which tests if \ang{substring} is in \ang{string}, but the present test avoids the problem of false result, which is typified by the following test:
\begin{example}
\in@{aa}{ababba}
\end{example}
This incorrectly returns \acmdm{\ifin@} as \fx{\iftrue}. The macro \fx{\SKV@in@}, on the other hand, correctly gives \fx{\ifin@} as \fx{\iffalse} in this case. The command \fx{\SKV@in@} is robust.

\begin{macro}
\SKV@in@n{|vang(substring)}{|vang(string)}{|vang(true text)}{|vang(false text)}
\end{macro}
\acmdm*{\SKV@in@n}
This is similar to \fx{\SKV@in@} but, as shown here, the returned result has a different syntax.

\begin{macro}
\SKV@in@o{|vang(substring)}{|vang(string)}{|vang(true text)}{|vang(false text)}
\end{macro}
\acmdm*{\SKV@in@o}
This expands each of its two arguments once before the test.

\begin{macro}
\SKV@in@x{|vang(substring)}{|vang(string)}{|vang(true text)}{|vang(false text)}
\end{macro}
\acmdm*{\SKV@in@x}
This expands each of its two arguments fully before the test.

\begin{macro}
\in@tog{|vang(substring)}{|vang(string)}
\end{macro}
\acmdm*{\in@tog}
In this case the returned boolean is the toggle switch \ang{in@} instead of the kernel's \ang{in@} switch which is used as \fx{\ifin@}. The toggle \ang{in@} can be used in the following way and in other manners that toggles can be employed:
\begin{example}
\iftogon{in@}{|vang(true text)}{|vang(false text)}.
\end{example}
\acmd*{\iftogon}
The command \fx{\in@tog} is robust.

\begin{macro}
\in@tok{|vang(substring)}{|vang(string)}
\end{macro}
\acmdm*{\in@tok}
Sometimes you want to use the \latex kernel's \fny{\in@}{substring}{string} to test if \ang{substring} is in \ang{string} irrespective of their catcodes. The robust command \fny{\in@tok}{substring}{string} makes this possible, and eliminates the tokens that would have been necessary if the user was required to first detokenize the two arguments. It returns the same switch \fx{\ifin@} as the kernel's \fny{\in@}{substring}{string}. Actually, it calls \fx{\SKV@in@} to avoid false returns.

\macrosection{Testing equality of strings}

\begin{macro}
\SKV@ifstrequal{|vang(string1)}{|vang(string2)}{|vang(true)}{|vang(false)}
\SKV@ifstrnotequal{|vang(string1)}{|vang(string2)}{|vang(not true)}{|vang(not false)}
\SKV@oifstrequal{|vang(string1)}{|vang(string2)}{|vang(true)}{|vang(false)}
\SKV@xifstrequal{|vang(string1)}{|vang(string2)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifstrequal,\SKV@ifstrnotequal,\SKV@oifstrequal,\SKV@xifstrequal}
In order to properly test the equality of strings, it may be necessary to remove leading and trailing spaces before the test. Such spaces may have cropped into the strings from input or from pre-processing and may invalidate the test. The macro \fx{\SKV@ifstrequal} takes care of such situations. It executes \ang{true} if \ang{string1} is equal (character code wise) to \ang{string2}, and \ang{false} otherwise. Both \ang{string1} and \ang{string2} are detokenized before the test. The macro \fx{\SKV@oifstrequal} is similar to \fx{\SKV@ifstrequal} but first expands its arguments (the two strings \ang{string1} and \ang{string2}) once before the test. The macro \fx{\SKV@xifstrequal} first expands its arguments fully before the test.

\macrosection{Testing for empty or blank}

\begin{macro}
\SKV@ifempty{|vang(token)}{|vang(true)}{|vang(false)}
\SKV@ifnotempty{|vang(token)}{|vang(not true)}{|vang(not false)}
\SKV@oifempty{|vang(token)}{|vang(true)}{|vang(false)}
\SKV@xifempty{|vang(token)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifempty,\SKV@ifnotempty,\SKV@oifempty,\SKV@xifempty}
These yield \ang{true} if \ang{token} is empty, and \ang{false} otherwise. In the command \fx{\SKV@ifempty}, \ang{token} isn't expanded before the test; in the command \fx{\SKV@oifempty}, \ang{token} is expanded once before the test; in the command \fx{\SKV@xifempty}, \ang{token} is fully expanded before the test.

\begin{macro}
\SKV@ifblank{|vang(token)}{|vang(true)}{|vang(false)}
\SKV@ifnotblank{|vang(token)}{|vang(not true)}{|vang(not false)}
\SKV@oifblank{|vang(token)}{|vang(true)}{|vang(false)}
\SKV@xifblank{|vang(token)}{|vang(true)}{|vang(false)}
\end{macro}
\acmdm*{\SKV@ifblank,\SKV@ifnotblank,\SKV@oifblank,\SKV@xifblank}

These macros test if the argument is blank or not. The first of these is from \pkgm{ifmtarg}. \fx{\SKV@oifblank} expands its argument once before the test, while \fx{\SKV@xifblank} expands its argument fully before the test.

\macrosection{Verifying \texttt{draft} and \texttt{final} options}

\begin{macro}
\SKV@ifdraft{|vang(true)}{|vang(false)}
\SKV@ifnotdraft{|vang(not true)}{|vang(not false)}
\SKV@iffinal{|vang(true)}{|vang(false)}
\SKV@ifnotfinal{|vang(not true)}{|vang(not false)}
\iftogon{draft}{|vang(true)}{|vang(false)}
\iftogoff{draft}{|vang(not true)}{|vang(not false)}
\iftogon{final}{|vang(true)}{|vang(false)}
\iftogoff{final}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\SKV@ifdraft,\SKV@ifnotdraft,\SKV@iffinal,\SKV@ifnotfinal,\iftogon\{draft\},
\iftogoff\{draft\},\iftogon\{final\},\iftogoff\{final\}}

These execute \ang{true} or \ang{false} depending on whether \fx{draft} or \fx{final} appears as \fx{true} in the options list of \acmd{\documentclass} or \fnx{\usepackage}{skeyval}.
The default is that \fx{final} is true, which implies that \fx{draft} is false by default. The keys \fx{draft} and \fx{final} are complementary native-boolean keys (see \cref{sec:comp-boolkeys}), which reduces the risk of mixing them. These commands are robust.

\begin{macro}
\ifdraft{|vang(true)}{|vang(false)}
\ifnotdraft{|vang(not true)}{|vang(not false)}
\iffinal{|vang(true)}{|vang(false)}
\ifnotfinal{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\ifdraft,\ifnotdraft,\iffinal,\ifnotfinal}
These are also defined in the \pkg{skeyval}, but because packages such as \pkgm{ifdraft} already exist, the \pkg{skeyval} defines them only if they haven't already been defined. If they existed before \pkg{skeyval} is loaded, they aren't redefined, and (if the package option \acmd{verbose} is selected) a warning is logged in the transcript file to indicate that the definition being used isn't from the \pkg{skeyval}. The warning is logged only once. I am aware of the existence of only \fx{\ifdraft} outside the \pkg{skeyval}: therefore, the definition of \fx{\ifdraft} is deferred until \acmd{\AtBeginDocument}. You can use \acmd{\TestProvidedCommand} to check the version of the \fx{\ifdraft} that you are using.

\macrosection{Verifying \texttt{dvi} and \texttt{pdf} modes}

\begin{macro}
\SKV@ifpdf{|vang(true)}{|vang(false)}
\SKV@ifnotpdf{|vang(not true)}{|vang(not false)}
\iftogon{pdf}{|vang(true)}{|vang(false)}
\iftogoff{pdf}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\SKV@ifpdf,\SKV@ifnotpdf,\iftogon\{pdf\},\iftogoff\{pdf\}}
These execute \ang{true} or \ang{false} depending on whether \fx{dvi} or \fx{pdf} output is being produced. These commands are robust and may be used in expansion contexts.

\begin{macro}
\ifpdf{|vang(true)}{|vang(false)}
\ifnotpdf{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\ifpdf,\ifnotpdf}
These are available only if they haven't been previously defined by another package. If they existed outside the \pkg{skeyval}, a warning is logged in the transcript log file (if the package option \fx{verbose} is selected), but only once, and the commands are not redefined. In particular, the above \fx{\ifpdf} is available only at \acmd{\AtBeginDocument} and is defined only if it doesn't already exist. The reason is that the popular \pkg{hyperref} loads the \pkg{ifpdf} and the \pkg{ifpdf} will abort if it detects that \fx{\ifpdf} has been defined by a package loaded earlier.

\Note The \fx{\ifpdf} command of the \pkg{ifpdf} is used in the \fx{\if} \ldots \fx{\else} \ldots \fx{\fi} conditional, while the above \fx{\ifpdf} command is used as indicated above. You can use the \acmd{\TestProvidedCommand} macro to check the version of the \fx{\ifpdf} command that you are using.

\macrosection{Tests related to package loading}

\begin{macro}
\@ifpackagecurrent{|vang(package)}{|vang(date)}{|vang(true)}{|vang(false)}
\@ifpackagenotcurrent{|vang(package)}{|vang(date)}{|vang(not true)}{|vang(not false)}
\end{macro}
\acmdm*{\@ifpackagecurrent,\@ifpackagenotcurrent}
These executes \ang{true} if the date of the current/loaded version \ang{package} is greater than or equal to \ang{date}. This is similar to \latex's \acmdm{\@ifpackagelater} but, unlike the latter, both \fx{\@ifpackagecurrent} and \fx{\@ifpackagenotcurrent} are robust. My main reason for these commands is that the nomenclature \fx{\@ifpackagelater} is subject to the wrong interpretation of being space (rather than time) related.

\begin{macro}
\@afterpackageloaded{|vang(package)}{|vang(code)}
\end{macro}
\acmdm*{\@afterpackageloaded}
This executes \ang{code} only after \ang{package} has been loaded. This has been optimized from the \pkgm{afterpackage} to avoid filling up the hash table with hooks that are \fx{relax}'ed or indeed undefined, and to warn the user if \ang{package} was not eventually loaded. If at the start of document, \ang{package} has not been loaded, a warning message is entered in the log file. Use the following \fx{\@ensurepackageloaded} macro if you really need an error message in this case.

\begin{macro}
\@ensurepackageloaded{|vang(packages)}
\end{macro}
\acmdm*{\@ensurepackageloaded}
This will issue an error at start of document if any member of the comma-separated list \ang{packages} wasn't loaded before then. This command can be used to signpost those packages that must be loaded later.

\macrosection{Commands restricted to package and preamble}

\begin{macro}
\SKV@onlypreamble{|vang(list)}
\SKV@onlypackage
\end{macro}
\acmdm*{\SKV@onlypreamble,\SKV@onlypackage}
The \latex kernel's macro \fx{\@onlypreamble} accepts only one command at a time (\ie, you can't give it a list of preamble commands in one go), and the error message \acmdm{\@notprerr} is not that precise, since it doesn't indicate the command that has been wrongly placed in the document's body. The use of \fx{\@onlypreamble} in a style or class file can be monotonous if the file has many preamble commands. The macro \fx{\SKV@onlypreamble} takes a no-comma \ang{list} of commands at once and gives precise error messages related to the incorrectly located commands. The \ang{list} may be  populated with nil, one, or more control sequences, \eg,
\begin{example}
\SKV@onlypreamble{\macroa \macrob \macroc}
\end{example}
All preamble commands can be collected together in one \fx{\SKV@onlypreamble}, preferably at the end of the style or class file.

The function \fx{\SKV@onlypackage} may be used to restrict commands to packages only. For example, the following restricts the command \fx{\x} to packages only:
\begin{example}
\def\x#1{\SKV@onlypackage\usearg{#1}}
\end{example}

\macrosection{Extended \texttt{\@bs aftergroup} and \texttt{\@bs afterassignment}}

\begin{macro}
\SKV@aftergroup{|vang(code)}
\SKV@aftergroup|redstar{|vang(code)}
\SKV@afterassignment{|vang(code)}
\SKV@afterassignment|redstar{|vang(code)}
\end{macro}
\acmdm*{\SKV@aftergroup,\SKV@aftergroup*,\SKV@afterassignment,\SKV@afterassignment*}

\tex's \fx{\aftergroup} and \fx{\afterassignment} don't accept arbitrary code. The commands \fx{\SKV@aftergroup} and \fx{\SKV@afterassignment} execute the arbitrary \ang{code} after a group or assignment. The starred variants expand \ang{code} once before the assignment or before exiting the group. These commands don't accumulate the group and assignment counters indefinitely: the counters are initialized after each group or each assignment.

Some examples follow:
\begin{example}
\let\gobblex\@firstofone
\def\protected@mydef{%
   \let\@@protect\protect
   \let\protect\@unexpandable@protect
   \SKV@afterassignment{%
    \restore@protect
    \let\gobblex\@gobble
   }%
   \edef
}

\def\aa{aaa} \def\bb{bbb} \def\xx{xxx} \def\yy{yyy}

|makered(\begin{document})
\begingroup
  \SKV@aftergroup{\par\aa***\bb}%
  \SKV@aftergroup{\par\bb***\aa}%
  \begingroup
    \SKV@aftergroup{\par\xx+++\yy}%
    \SKV@aftergroup{\par\yy+++\xx}%
  \endgroup
\endgroup
|makered(\end{document})
\end{example}
\acmd*{\begin\{document\}}

\macrosection{List processing}

\begin{macro}
\SKV@for@a{|vang(list)}|vang(cmd){|vang(function)}
\SKV@for@b|vang(listcmd)|vang(cmd){|vang(function)}
\end{macro}
\acmdm*{\SKV@for@a,\SKV@for@b}
These are fast for-loops that accept general list parsers and allow for list breaks, as well as give the remainder of the list if a break occurs within the list. Elements of \ang{list} are stored in \ang{cmd}, and \ang{function} is executed for each element of \ang{list}.  \ang{list}, which is populated by parser-separated elements, is not expanded before the iteration; \ang{listcmd}, on the other hand, is expanded once before the commencement of the loop. The list parser is dynamically declarable via
\begin{macro}
\SKV@CommandGenParser{|vang(parser)}  |orr
\skvoptions{genparser=|vang(parser)}
\end{macro}
\acmdm*{\SKV@CommandGenParser}
Also, these iteration macros use the more powerful \acmd{\SKV@ifblank} to check whether or not \ang{list} is empty or blank. The commands \fx{\SKV@for@a} and \fx{\SKV@for@b} are robust, but in expansion contexts, both \ang{cmd} and \ang{function} will need to be protected. The \ang{parser} persists in effect until it is changed by another call to \fx{\SKV@CommandGenParser} or \acmd{\skvoptions} as above.

\Note One snag with a generic list parser like \fx{\SKV@CommandGenParser} is that the user must always remember to call it and set the right parser before beginning an iteration, otherwise there might be unpleasant results, since a previous call to \fx{\SKV@CommandGenParser} might have set a parser that is no longer valid. To obviate this type of situation, the following commands are also provided in the \pkg{skeyval}:
\begin{macro}
\SKV@for[|vang(parser)]{|vang(list)}|vang(cmd){|vang(function)}
\SKV@for|redstar[|vang(parser)]|vang(listcmd)|vang(cmd){|vang(function)}
\end{macro}
\acmdm*{\SKV@for,\SKV@for*}
The \ang{parser} appears as an optional argument in these commands and its default value is ``\fx{,}'' (comma). These commands allow the user to provide the \ang{parser} with every call. The unstarred and starred versions of \fx{\SKV@for} are equivalent to \fx{\SKV@for@a} and \fx{\SKV@for@b}, respectively. Both sets (\fx{\SKV@for@a} and \fx{\SKV@for@b} \amdvert\ \fx{\SKV@for} and \fx{\SKV@for}\redstar) may be needed in different circumstances. In applications where the \ang{parser} is fixed, the commands \fx{\SKV@for@a} and \fx{\SKV@for@b} are faster than \fx{\SKV@for} and \fx{\SKV@for}\redstar\ because in the former cases the \ang{parser} would then need to be set only once: each call to \fx{\SKV@for} or \fx{\SKV@for}\redstar, whether or not the optional \ang{parser} is provided, resets the \ang{parser}.

The list parser itself is available in \acmd{\parser}, which can be used in \ang{function}. An example follows:
\begin{example}
\SKV@CommandGenParser{;}
\SKV@for@a{a;b;c;d}\cmd{\if a\cmd `\cmd'\ is `a'\parser
\else\space `\cmd'\ isn't `a'\parser\fi}.
\end{example}
This list can be broken after, say, elements ``\fx{a}'' and ``\fx{b}'', as follows:
\begin{example}
\SKV@for@a{a;b;|makered(listbreak);c;d}\cmd
{\if a\cmd `\cmd'\ is `a'\parser\else\space `\cmd'\
isn't `a'\parser\fi},
\end{example}
upon which the remainder of the list is accessible from \acmd{\SKV@remainder}.

\begin{macro}
\SKV@tfor@a{|vang(list)}|vang(cmd){|vang(function)}
\SKV@tfor@b|vang(listcmd)|vang(cmd){|vang(function)}
\end{macro}
\acmdm*{\SKV@tfor@a,\SKV@tfor@b}
The first of these (\ie, \fx{\SKV@tfor@a}) is equivalent to \latex kernel's \acmdm{\@tfor}, which loops over \ang{list} token-wise (character or control sequence token), but these two macros have been prompted by the following rationale. Note that \ang{list} is not a comma-separated list! In \fx{\SKV@tfor@b}, \ang{listcmd} is expanded once before the commencement of the loop. The two commands \fx{\SKV@tfor@a} and \fx{\SKV@tfor@b} are both robust.

The \acmdm{\@break@tfor} of the \latex kernel allows the user to break out of the \fx{\@tfor} loop but provides no mechanism for saving the remainder of the \ang{list} upon breaking the list. Secondly, I have had trouble breaking out of simple \fx{\@tfor} loops. For example, the following fails: \latex complains of ``extra \string\fi'', the reason being obvious.
\begin{example}
\def\one{One}\def\two{Two}\def\three{Three}
\@tfor\x:=\one\two|makered(\@break@tfor)\three\do{\x}
\end{example}

Thirdly, if the content of \fx{\x} above is sanitized/detokenized in the loop before being used in \ang{function} (or sanitized in the \ang{function} itself), then \fx{\@break@tfor} can't break the loop. Consider the following:
\begin{example}
\@tfor\x:=\one\two|makered(\@break@tfor)\three\do{%
  \edef\x{\detokenize\expandafter{\x}}%
}
\end{example}
Clearly, \fx{\@break@tfor} can't break this loop. The macros \fx{\SKV@tfor@a} and \fx{\SKV@tfor@b} circumvent these problems. Additionally, they
\begin{inenum}[(a)]
\item reorder the arguments such that \ang{list} comes before \ang{cmd}, and
\item remove the need for the usual delimitating tokens, thereby making their syntaxes mimic those of \acmd{\SKV@for@a} and \acmd{\SKV@for@b}.
\end{inenum}

In the following, the remainder of the list (namely, \fx{\three}) can be accessed from the macro \acmd{\SKV@remainder}:
\begin{example}
\SKV@tfor@a{\one\two|makered(\listbreak)\three}\x{%
  \edef\x{\detokenize\expandafter{\x}}%
}
\end{example}

\begin{macro}
\SKV@tfor{|vang(list)}|vang(cmd){|vang(function)}
\SKV@tfor|redstar|vang(listcmd)|vang(cmd){|vang(function)}
\end{macro}
\acmdm*{\SKV@tfor,\SKV@tfor*}
These are equivalent to \fx{\SKV@tfor@a} and \fx{\SKV@tfor@b} respectively.

\macrosection{Hook management}
\macrosubsection{Hooking to user-defined macros}

\begin{macro}
\SKV@appto|redstar|redplus|redask|vang(cs){|vang(content)}
\end{macro}
\acmdm*{\SKV@appto,\SKV@appto*,\SKV@appto*+,\SKV@appto*+?}
This appends \ang{content} to \ang{cs}. If \ang{cs} was previously undefined, it is initialized with \ang{content}. The star (\RedStar) sign directs \fx{\SKV@appto} to expand \ang{content} once before appending \ang{content} to \ang{cs}. The plus (\RedPlus) sign means that \ang{cs} is a control sequence name instead of a control sequence, while the question mark (\RedAsk) instructs \fx{\SKV@appto} to append \ang{content} to \ang{cs} globally (to escape local groups). This command is robust, but fragile arguments must be protected in expansion contexts.

Except for the initialization of undefined \ang{cs}, \fx{\SKV@appto}\redask\ is equivalent to \latex's \acmdm{\g@addto@macro}.

The following non-generic, less powerful, forms of \fx{\SKV@appto} are also available, but they don't have the starred (\RedStar) variants:
\begin{macro}
\apptomac|vang(cs){|vang(content)}
        |tto  \SKV@appto|vang(cs){|vang(content)}
\gapptomac|vang(cs){|vang(content)}
        |tto  \SKV@appto|redask|vang(cs){|vang(content)}
\csapptomac{|vang(name)}{|vang(content)}
        |tto  \SKV@appto|redplus{|vang(name)}{|vang(content)}
\csgapptomac{|vang(name)}{|vang(content)}
        |tto  \SKV@appto|redplus|redask{|vang(name)}{|vang(content)}
\end{macro}
\acmdm*{\apptomac,\gapptomac,\csapptomac,\csgapptomac}

\bigskip
\begin{macro}
\SKV@prepto|redstar|redplus|redask|vang(cs){|vang(content)}
\end{macro}
\acmdm*{\SKV@prepto,\SKV@prepto*,\SKV@prepto*+,\SKV@prepto*+?}
This prepends \ang{content} to \ang{cs}. If \ang{cs} was previously undefined, it is initialized with \ang{content}. The star (\RedStar) sign directs \fx{\SKV@prepto} to expand \ang{content} once before prepending it to \ang{cs}. The plus (\RedPlus) sign means that \ang{cs} is a control sequence name instead of a control sequence, while the question mark (\RedAsk) instructs \fx{\SKV@prepto} to prepend \ang{content} to \ang{cs} globally (to escape local groups). This command is robust, but fragile arguments must be protected in expansion contexts.

Again, the following non-generic versions of \fx{\SKV@prepto} are available, but they don't have the starred (\RedStar) variants:
\begin{macro}
\preptomac|vang(cs){|vang(content)}
        |tto \SKV@prepto|vang(cs){|vang(content)}
\gpreptomac|vang(cs){|vang(content)}
        |tto \SKV@prepto|redask|vang(cs){|vang(content)}
\cspreptomac{|vang(name)}{|vang(content)}
        |tto  \SKV@prepto|redplus{|vang(name)}{|vang(content)}
\csgpreptomac{|vang(name)}{|vang(content)}
        |tto  \SKV@prepto|redplus|redask{|vang(name)}{|vang(content)}
\end{macro}
\acmdm*{\preptomac,\gpreptomac,\cspreptomac,\csgpreptomac}

\bigskip
\begin{macro}
\SKV@addtolist|redplus|redask|redleft[|vang(parser)]|vang(csa)|vang(csb)
\end{macro}
\acmdm*{\SKV@addtolist,\SKV@addtolist+,\SKV@addtolist+?,\SKV@addtolist+?<}
This adds the contents of the macro \ang{csb} to the list in the container \ang{csa}. The plus sign~(\RedPlus) means that \ang{csa} is a control sequence name (instead of a control sequence); the question mark~(\RedAsk) directs \fx{\SKV@addtolist} to add the contents of \ang{csb} to \ang{csa} globally (to escape local groups); and the left angle (\RedLeft), if present, instructs \fx{\SKV@addtolist} to prepend the contents of \ang{csb} to the left of the contents of \ang{csa}, instead of appending to the right by default. The optional argument \ang{parser} is the list parser, ie, the separator of the instances in \ang{csa}. Its default value is ``,'' (comma).

\macrosubsection{Package and document hooks}

\begin{macro}
\SKV@AtPackageEnd{|vang(code)}
\SKV@AtClassEnd{|vang(code)}
\end{macro}
\acmdm*{\SKV@AtPackageEnd,\SKV@AtClassEnd}
These are the robust versions of the well-known \latex hooks \acmd{\AtEndOfPackage} and \acmd{\AtEndOfClass}.

\begin{macro}
\SKV@BeforePackageEnd{|vang(code)} |label(befpkgend)
\SKV@BeforeClassEnd{|vang(code)} |label(befclsend)
\SKV@AfterPackageEnd{|vang(code)}
\SKV@AfterClassEnd{|vang(code)}
\end{macro}
\acmdm*{\SKV@BeforePackageEnd,\SKV@BeforeClassEnd,\SKV@AfterPackageEnd,
\SKV@AfterClassEnd}
The first two of these hook to just before \acmd{\AtEndOfPackage} or \acmd{\AtEndOfClass}; the third and fourth hook to just after \fx{\AtEndOfPackage} or \acmd{\AtEndOfClass}. They are all robust. These commands have been necessitated by some tasks in the \pkg{skeyval}, but may be useful in some other contexts.

\begin{macro}
\SKV@AtDocumentStart{|vang(code)}
\end{macro}
\acmdm*{\SKV@AtDocumentStart}
This is the robust version of the \latex hook \acmdm{\AtBeginDocument}. It can be used in expansion contexts without protection, but fragile arguments within it must be protected.

\begin{macro}
\SKV@BeforeDocumentStart{|vang(code)}|label(beforedocstart)
\SKV@AfterDocumentStart{|vang(code)}|label(afterdocstart)
\end{macro}
\acmdm*{\SKV@BeforeDocumentStart,\SKV@AfterDocumentStart}
These provide two more document hooks. They are both robust. The command \fx{\SKV@BeforeDocumentStart} differs from \fx{\AtBeginDocument} in that the former is executed right at
the end of the preamble, before the main auxiliary file (as written on the previous \latex
run) is read and prior to the execution of any \fx{\AtBeginDocument} code. It isn't possible
to write to the auxiliary file at the point \fx{\SKV@BeforeDocumentStart} is executed.

\fx{\SKV@AfterDocumentStart} differs from \fx{\AtBeginDocument} in the sense that the former is executed at the tag end of \acmd{\begin\{document\}}, after the execution of any \fx{\AtBeginDocument} code. Commands whose scope are restricted to the document's preamble with \acmd{\@onlypreamble} or \acmd{\SKV@onlypreamble} are no longer committable when \fx{\SKV@AfterDocumentStart} is being executed.

\begin{macro}
\SKV@AtDocumentEnd{|vang(code)}
\SKV@BeforeLastPage{|vang(code)}
\SKV@AfterLastPage{|vang(code)}
\SKV@AfterDocumentEnd{|vang(code)}
\end{macro}
\acmdm*{\SKV@AtDocumentEnd,\SKV@BeforeLastPage,\SKV@AfterLastPage,
\SKV@AfterDocumentEnd}
The last three of these are wrappers developed based on the \pkgm{atveryend}, which provides a consistent mechanism for \acmd{\enddocument} methods. The macro
\fx{\SKV@AtDocumentEnd} is the robust equivalent of \acmd{\AtEndDocument}. The macro \fx{\SKV@BeforeLastPage} appends \ang{code} after the \acmd{\@enddocumenthook} but before the last \acmd{\clearpage}, and thus before the last shipout. The command \fx{\SKV@AfterLastPage} executes \ang{code} after the last \acmd{\clearpage} invoked within \acmd{\enddocument}, \ie, after the last shipout but before the main auxiliary file is closed. This is, \eg, the right instance to record the last document page in the auxiliary file.

The command \fx{\SKV@AfterDocumentEnd} appends \ang{code} to the very end of the document, after all of the end-of-document codes have been executed (\ie, after the main .aux file of the current pass has been read and all \acmd{\AtEndDocument} codes have been effected, except font and label/reference warnings).

\macrosection{Inputting files}

\begin{macro}
\InputFileOnce[|vang(path)]{|vang(file)}
\InputFileOnce|redstar[|vang(path)]{|vang(file)}
\end{macro}
\acmdm*{\InputFileOnce}
The unstarred variant of this command inputs \ang{file} on \ang{path} but only once in one \latex pass. The argument \ang{path} is optional and its default value is the current/document's environment/directory. If \ang{file} had previously been read, a warning message is entered in the transcript log file (if the package option \acmd{verbose} is selected) and the input is aborted. If \ang{file} doesn't exist on \ang{path}, as many as desired opportunities are given to the user to type in the correct filename on the screen, or enter ``no'' to continue with the \latex pass without inputting the file.

If the user wants to input \ang{file} more than once in one document, then he should use the starred (\RedStar) variant of \fx{\InputFileOnce}.

\section{References}

All the \texorlatex packages cited in this guide are available on \ctan.

\section{Version history}
\label{sec:version-hist}

The following change history highlights significant changes that affect user utilities and interfaces; mutations of technical nature are not documented in this section. The numbers on the right-hand side of the following lists are section numbers; the star sign (\RedStar) means the subject features in the package but is not reflected anywhere in this user guide.

\begin{versionhist}
  \begin{version}{0.1}{2010/01/01}
  \item First public release under the name \pkg{keyreader}\xsecref
  \item Introduced complementary native-boolean keys \secref{sec:comp-boolkeys}
  \item Provided machinery for reading multiple keys of all kinds from just one command \secref{sec:def-multiple-keys}
  \end{version}

  \begin{version}{0.2}{2010/01/10}
  \item Fixed a bug and optimized the \acmd{\define@keylist} loop \secref{sec:def-multiple-keys}
  \end{version}

  \begin{version}{0.3}{2010/01/20}
  \item Introduced toggles and toggle-boolean keys \secref{sec:toggles}
  \end{version}

  \begin{version}{0.4}{2010/02/01}
  \item Introduced complementary toggle-boolean keys \secref{sec:comptogkeys}
  \end{version}

  \begin{version}{0.5}{2010/02/23}
  \item Changed the name of the package from \pkg{keyreader} to \pkg{skeyval}\xsecref
  \item Introduced the following macros\secref{sec:status-keys}
    \begin{veritem}
    \ifkeydefined, \ifkeyreserved, \ifkeysuspended
    \end{veritem}
    \acmd*{\ifkeydefined,\ifkeyreserved,\ifkeysuspended}

  \item Provided the following facilities \secref{sec:avoiding-redef}
    \begin{veritem}
    \newordkey, \newcmdkey, \newboolkey, \newchoicekey,
    \newtogkey, \define@biboolkeys, \newbiboolkeys,
    \define@bitogkeys, \newbitogkeys, \define@uniboolkeys,
    \newuniboolkeys, \define@unitogkeys, \newunitogkeys,
    \define@biuniboolkeys, \newbiuniboolkeys,
    \define@biunitogkeys, \newbiunitogkeys
    \end{veritem}

    \acmd*{\newordkey,\newcmdkey,\newboolkey,\newchoicekey,\newtogkey,
    \define@biboolkeys,\newbiboolkeys,\define@bitogkeys,\newbitogkeys,
    \define@uniboolkeys,\newuniboolkeys,\define@unitogkeys,\newunitogkeys,
    \define@biuniboolkeys,\newbiuniboolkeys,\define@biunitogkeys,\newbiunitogkeys}

  \item Provided mechanisms for disabling, localizing, reserving, unreserving, suspending, restoring, and removing keys \secref{sec:disable-reserv-keys}

  \item Redefined a few of \pkg{xkeyval}'s internal macros \xsecref

  \item Normalization of key-value lists before parsing \secref{sec:list-normal}

  \item Included some developer macros \secref{sec:misce-commands}
  \end{version}

  \begin{version}{0.6}{2010/03/30}
  \item Modified the mechanics of the internal macros of the following \secref{sec:reserve-keys}
    \begin{veritem}
    \ReserveKeyPrefixNames, \ReserveKeyPrefixNames|redstar,
    \ReserveMacroPrefixNames, \ReserveMacroPrefixNames|redstar,
    \ReserveFamilyNames, \ReserveFamilyNames|redstar
    \end{veritem}

    \acmd*{\ReserveKeyPrefixNames,\ReserveMacroPrefixNames,\ReserveFamilyNames,
    \ReserveKeyPrefixNames*,\ReserveMacroPrefixNames*,\ReserveFamilyNames*}

  \item Introduced the following macros \secref{sec:misce-commands}

    \begin{veritem}
    \SKV@AtPackageEnd, \SKV@BeforePackageEnd,
    \SKV@AfterPackageEnd, \SKV@AtDocumentEnd,
    \SKV@BeforeLastPage, \SKV@AfterLastPage,
    \SKV@AfterDocumentEnd, \SKV@onlypreamble,
    \SKV@onlypackage, \SKV@ifdraft, \SKV@iffinal,
    \SKV@ifpdf, \@ensurepackageloaded, \InputFileOnce,
    \newswitch, \defswitch, etc.
    \end{veritem}

    \acmd*{\SKV@AtPackageEnd,\SKV@BeforePackageEnd,\SKV@AfterPackageEnd,
    \SKV@AtDocumentEnd,\SKV@BeforeLastPage,\SKV@AfterLastPage,\InputFileOnce,
    \SKV@AfterDocumentEnd,\SKV@onlypreamble,\SKV@ifdraft,\SKV@iffinal,\SKV@ifpdf,
    \@ensurepackageloaded}

  \item Alert the user if \pkg{skeyval} is loaded before \acmd{\documentclass} \secref{sec:loading-package}

  \item Introduced ``user-value'' keys \secref{sec:uservaluekeys}

  \item Extended the pointer system of the \pkg{xkeyval} \secref{sec:pointer-mech}
  \item Corrected a bug in the \pkg{xkeyval} which, if \acmd{\setkeys} is nested in a class file, gives non-empty \acmdm{\@unusedoptionlist} even if all the options of \acmd{\documentclass} have been used \xsecref
  \end{version}

  \begin{version}{0.7}{2010/05/05}
  \item Native-boolean and toggle-boolean keys now accept \fx{on} and \fx{off} as values,
  in addition to \fx{true} and \fx{false} \secref*{sec:toggle-booleans}{sec:switches}

  \item Replaced the former \acmd{\NewIfs} with \acmd{\NewBooleans} and redefined \fx{\NewIfs} \secref{sec:biboolkeys}

  \item Introduced \acmd{\DeclareKeyCommand} \xsecref

  \end{version}

  \begin{version}{0.71}{2010/05/06}
  \item Corrected a bug in one of the internal conditional tests \xsecref

  \item Removed \fx{\DeclareKeyCommand} to create a separate \pkg{skeycommand} \xsecref

  \end{version}

\end{versionhist}

\IndexPreamble{Index numbers refer to page numbers.}
\IndexPreambleFormat{\centering}
\IndexColumns\tw@
\printindex
\end{document}

%%% End of file skeyval-guide.tex %%%