diff options
Diffstat (limited to 'Master/texmf-dist/doc/latex/skeyval')
-rw-r--r-- | Master/texmf-dist/doc/latex/skeyval/README | 45 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex | 20 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdf | bin | 312704 -> 580787 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex | 2812 |
4 files changed, 2039 insertions, 838 deletions
diff --git a/Master/texmf-dist/doc/latex/skeyval/README b/Master/texmf-dist/doc/latex/skeyval/README index 5d4fc0d8070..cbe5a526453 100644 --- a/Master/texmf-dist/doc/latex/skeyval/README +++ b/Master/texmf-dist/doc/latex/skeyval/README @@ -1,18 +1,29 @@ -%++++++++++++++++++++++++++++++++++++ MOTIVATION ++++++++++++++++++++++++++++++++++++% -% % -% The elaborate and useful xkeyval package introduced \define@cmdkeys and % -% \define@boolkeys, which allow for the setting of multiple command keys and % -% boolean keys, but in each category those keys must have the same default value % -% and no key macro/function. This package seeks to remove these restrictions, % -% so that multiple keys of all categories (ordinary keys, command keys, boolean % -% keys, and choice keys) can be set at one go and those keys can have different % -% default values and functions. This greatly saves tokens, as hundreds of keys % -% can, in principle, be issued simultaneously by one command. % -% % -% Also, the xkeyval package doesn't have the notion of complementary keys, % -% which is useful in the case of boolean keys. The present package introduces % -% this concept and additionally permits the submission of individual/different % -% key macros to the complementary keys. % +%+++++++++++++++++++++++++++++++++++ INTRODUCTION +++++++++++++++++++++++++++++++++++% +% % +% This is the Readme file for the skeyval package, version 0.6. % +% April 2010 % +% % +% Copyright (c) 2010 Ahmed Musa (a.musa@rocketmail.com). % +% % +%+++++++++++++++++++++++++++++++++++++ MOTIVATION +++++++++++++++++++++++++++++++++++% +% % +% The xkeyval package introduced many concepts for key definition and % +% management. The skeyval package extends the functionality of the xkeyval % +% package in many ways, including introducing: % +% % +% 1. Toggle keys % +% 2. Complementary boolean and toggle keys % +% 3. Mechanisms for reserving, unreserving, suspending, restoring, % +% and removing keys % +% 4. Tools for defining keys such that no existing key is inadvertently % +% redefined % +% 5. List normalization when setting keys % +% 6. A mechanism for defining multiple keys of differing genres using only % +% one command % +% 7. Commands for checking the statuses of keys across multiple key prefixes % +% and families % +% 8. User-value keys and using pointers in defining keys % +% 9. Some general-purpose LaTeX programming macros and hooks % % % %+++++++++++++++++++++++++++++++++++++ LICENSE ++++++++++++++++++++++++++++++++++++++% % % @@ -28,8 +39,4 @@ % expressed or implied, including, but not limited to, the implied warranties of % % merchantability and fitness for a particular purpose. % % % -% Version 0.5 % -% % -% Copyright (c) 2010 Ahmed Musa (a.musa@rocketmail.com). % -% % %++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
\ No newline at end of file diff --git a/Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex b/Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex index b27304826df..9e1c240626a 100644 --- a/Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex +++ b/Master/texmf-dist/doc/latex/skeyval/skeyval-bugreport.tex @@ -1,31 +1,33 @@ %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% % This is file skeyval-bugreport.tex, the bug report file for the % -% skeyval package, version 0.5. % +% skeyval package, version 0.6. % % % % (c) Ahmed Musa 2010 (a.musa@rocketmail.com) % %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% % % % IMPORTANT % % % -% Fill in the details below, compile the file and email the % -% sample file, the log file, and the auxiliary file to % +% Please fill in the details below, compile the file and email % +% the sample file, the log file, and the auxiliary file to % % a.musa@rocketmail.com. % % % %+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++% + \documentclass{article} \listfiles -\usepackage[logonly]{trace} + +% Load your select packages here (the ones +% that you think are associated with your errors) + +\usepackage[logonly]{trace} % Please don't move! \traceon -% \usepackage[Put your options here]{skeyval} -% Load your select packages here: +% \usepackage[Put your skeyval options here]{skeyval} % Provide other elements of your preamble here: -\traceoff \begin{document} -\traceon -% Provide sample text here: +% Provide sample text and problematic segment of your file here: \traceoff diff --git a/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdf b/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdf Binary files differindex ac1afaa461e..1343d4eb767 100644 --- a/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdf +++ b/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.pdf diff --git a/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex b/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex index acef82c6d8a..82a59f63d18 100644 --- a/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex +++ b/Master/texmf-dist/doc/latex/skeyval/skeyval-guide.tex @@ -1,83 +1,96 @@ -\documentclass[ - final,language=UKenglish,review=false,parskip,lettrine -]{amltxdoc} +\documentclass[a4paper,10pt,final,language=UKenglish,fancysec,fancyfnote]{amltxdoc} \makeatletter -\amltxdoc{% - frontpagestyle = empty, - pretitleskip = 0cm, - afttitleskip = 1ex, - natbib = {numbers,sort&compress}, - xcolor = {dvipsnames,table,hyperref}, - lhead = {The \textcolor{\amd@specolor}{skeyval} Package}, - rhead = {Page~\thepage~of~\zpageref{LastPage}}, - cmdcolor = xmagenta1, - stycolor = ForestGreen, - specolor = teal -} + \begin{document} -\begin{titlematter} -\suptitle{} -\title{The \texttt{\color{blue}skeyval} Package} -\subtitle{Version 0.5} -\titlenote{The package was formerly called the \sty{keyreader} package until version~0.5. The \sty{keyreader} package is obsolete and no longer supported.} -\author{Ahmed Musa\Email{a.musa@rocketmail.com}\\ Preston, Lancashire, UK} -\nonumbernote{The \sty{skeyval} package is available at - \url{http://www.ctan.org/tex-archive/macros/latex/contrib/skeyval/}} -\end{titlematter} +\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.} +\iftog{pdf}{% + \titlenote[t2]{The package is available at \url{\@titleurl}.}% +}{% + \titlenote[t2]{The package is available at \url{\@shorttitleurl}.}% +} +\subtitle{Version 0.6} +\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 +\SKV@redef*\abstractname{\vspace{-\baselineskip}} +\begin{abstract} \frameshade[width=\hsize,fillcolor=yellow!20,framesep=2pt,framerule=2pt, framecolor=brown]{% - \frameshade[fillcolor=white,width=2cm,framecolor=red,framerule=2pt]% - {\centering\textsf{Abstract}}\small - \noindent This package supplements the \sty{xkeyval} package, hence the ``s'' in ``skeyval.'' It introduces toggle keys and complementary (boolean and toggle) 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. Some other general-purpose developer macros are provided within the package. + \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} -\vskip\baselineskip +\NewLet\licename\licensename +\SKV@redef*\licensename{\vspace{-\baselineskip}} +\begin{license} \frameshade[width=\hsize,fillcolor=white,framesep=2pt,framerule=2pt, framecolor=brown]{\small -\centerline{\large\scshape License} -\endgraf -This work (\ie, all the files in the \sty{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, such as makers of \miktex and \texlive, should wait for at least a stable version~1.0 before embarking on distribution. Bug reports are particularly welcome. Correspondents should use the file \sty{skeyval-bugreport.tex} provided as part of the bundle. \textcolor{red}{\CopyRightYear} + \vspace{1ex}\centerline{\licename}\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]{% - \begin{multicols}{2}% - \small\tableofcontents\normalsize - \end{multicols}% -}% + width=1.1\hsize]{\tableofcontents} \section{Motivation} +\label{sec:motivation} -\lletter{T}oggle switches or booleans were introduced by the \sty{etoolbox} package and have proved very useful mainly for two reasons: unlike the legacy \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: +\lletter{T}oggle switches or 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} -\newif\ifmyboolean -> 3 separate commands: +|comm(Knuth/native switch:) +\newif\ifmyboolean |tto 3 separate commands: \ifmyboolean \mybooleantrue \mybooleanfalse -\newtoggle{myboolean} -> only 1 command and no clash with +|comm(Toggle switch:) +\newtog{myboolean} |tto only 1 command and no clash with commands in other namespaces. \end{example} -However, the \sty{xkeyval} package can't be used to define and set toggle keys. The present package fills this gap, by providing facilities for defining and setting toggle keys. The work relies on some of the macros from the \sty{xkeyval} package. +\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. The work relies on some of the macros from the \pkg{xkeyval}. + +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 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 similar to the \acmd{\newcommand} concept in \LaTeX. -Secondly, the \sty{xkeyval} package can't be used to define and set complementary keys, which can be handy in the case of boolean and toggle keys. The present package introduces this concept and additionally permits the submission of individual/different custom key macros to complementary boolean and toggle keys. +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. -The third motivation for this package relates to economy of tokens in style files. The \sty{xkeyval} package provides \fx{\define@cmdkeys} and \fx{\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 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. +The new macros can be used together with the machinery from the \pkg{xkeyval} for efficient and versatile key management. -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 is similar to the \fx{\newcommand} concept in \LaTeX. +\section{Brace stripping by the \texttt{xkeyval} package} -The package also provides facilities for disabling, suspending, restoring and removing keys across multiple families of keys. +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 new macros can be used together with the machinery from the \sty{xkeyval} package for efficient and versatile key management. +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.\footnote{We have had to redefine some 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{Loading the \textcolor{\amd@stycolor}{skeyval} package} +\section{The \texttt{skeyval} package options} +\label{sec:loading-package} The package can be loaded in style and class files by \begin{example} @@ -87,139 +100,234 @@ and in document files via \begin{example} \usepackage[options]{skeyval} \end{example} -where the options and their default values are -\begin{macrocode} +where the user options and their default values are +\begin{macro} keyparser=;, macroprefix=mp@, keyprefix=KV, keyfamily=fam, -xchoicelist=false. -\end{macrocode} -The \fn{keyparser} is the separator between the keys in the key list to be defined in one go (see examples in \secref{sec:examples}). The \fn{macroprefix}, \fn{keyprefix}, and \fn{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 \fx{\skvoptions} macro: -\begin{macrocode} +verbose=false +\end{macro} +\acmdm*{keyparser,macroprefix,keyprefix,keyfamily,verbose} + +The \aang{keyparser} is the separator between the keys in the key list to be defined in one go (see \cref{sec:multkeys-examples}). The \aang{macroprefix}, \aang{keyprefix}, and \aang{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, xchoicelist=false}. -\end{macrocode} + 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 \aang{macroprefix}, \aang{keyprefix} and \aang{keyfamily}, then the user will have to make his own choices for these defaults so as to avoid clashes. -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 \fn{macroprefix}, \fn{keyprefix} and \fn{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 boolean keys} +\section[Complementary native boolean keys]{Complementary native-boolean keys} \label{sec:comp-boolkeys} -The syntax for creating complementary boolean keys is -\begin{macrocode} -\define@compboolkeys[|fv(keyprefix)]{|fv(family)}[|fv(macroprefix)] - {|fv(primary boolean)}[|fv(default value for primary boolean)] - {|fv(secondary boolean)}{|fv(func for primary boolean)} - {|fv(func for secondary boolean)}. -\end{macrocode} -This command is robust and can be used in expansion contexts, but expandable commands must be protected. When the user doesn't supply the \fn{keyprefix} and/or \fn{macroprefix}, the package will use \fn{KV} and \fn{mp@}, respectively. When one complementary boolean key (primary or secondary) is true, the other is automatically set false; and vice versa: when one complementary boolean key (primary or secondary) is false, the other is automatically set true. Infinite loops, which are possible in back-linked key settings, are avoided in the \sty{skeyval} package. The tools of the \sty{xkeyval} package, such as \fx{\setkeys}, \fx{\presetkeys}, \fx{\savekeys}, \fx{\savevalue}, \fx{\usevalue}, \etc, are all applicable to complementary boolean keys. +\subsection{Bipolar native-boolean keys} -As an example, we define below two complementary boolean keys \fn{draft} and \fn{final} with different key macros: +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[|cang(keyprefix)]{|cang(family)}[|cang(macroprefix)] + {|cang(primary boolean)}[|cang(default value for primary boolean)] + {|cang(secondary boolean)}{|cang(func for primary boolean)} + {|cang(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 \aang{keyprefix} and/or \aang{macroprefix}, the package will use \aang{KV} and \aang{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 complementary bipolar keys. + +As an example, we define below two bipolar native-boolean keys \aang{draft} and \aang{final} with different key macros: \begin{example} -\define@compboolkeys[KV]{fam}[mp@]{draft}[true]{final}% - {% - \def\gobble##1{}% - }{% - \def\notgobble##1{##1}% - }. +\define@biboolkeys[KV]{fam}[mp@]{draft}[true]{final}% + {\def\noneofone##1{}}{\def\oneofone##1{##1}} \end{example} -The key prefix (default \fn{KV}), macro prefix (default \fn{mp@}), and key macros (no default) can be empty: +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@compboolkeys{fam}{draft}[true]{final}{}{}. +\define@biboolkeys{fam}{draft}{final}{}{}. \end{example} -The defined complementary keys \fn{draft} and \fn{final} can now be set as follows: +The defined complementary bipolar keys \aang{draft} and \aang{final} can now be set separately as follows: \begin{example} \setkeys[KV]{fam}{draft=true} \setkeys[KV]{fam}{final=true} \end{example} -The second statement above reverses the boolean \fn{draft} to \fn{false}, which had been set in the first statement to \fn{true}. There is no apparent meaning to the following: +The second statement above reverses the boolean \aang{draft} to \aang{false}, which had been set in the first statement to \aang{true}. There is no apparent meaning to the following: \begin{example} \setkeys[KV]{fam}{draft=true,final=true}. \end{example} -Most applications of the \sty{xkeyval} package do indeed use key and macro prefixes; so it presumably makes sense here to assume that all uses of the present package will somehow involve key and macro prefixes. +\subsection{Unipolar native-boolean keys} -\section{Toggle switches and keys} -\label{sec:toggles} - -\subsection{Toggle switches} -\label{sec:toggle-switches} +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[|cang(keyprefix)]{|cang(family)}[|cang(macroprefix)] + {|cang(primary boolean)}[|cang(default value for primary boolean)] + {|cang(secondary boolean)}{|cang(func for primary boolean)} + {|cang(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 \aang{keyprefix} and/or \aang{macroprefix}, the package will use \aang{KV} and \aang{mp@}, respectively. When the default value for the primary boolean is not supplied, the package will assume it to be \fx{true}. -The following toggle switches are defined in the \sty{skeyval} package. They largely mimic those in the \sty{etoolbox} package, except for the commands \fx{\deftog} and \fx{\requiretog}. There is no fear that the commands in this package will interfere with those from the \sty{etoolbox} package, since the control sequence names used in the two packages are different. +The following example constructs two unipolar boolean keys: +\begin{example} +\define@uniboolkeys[KV]{fam}[mp@]{pdfmode}[true]{microtype}% +{\temptoks{Yes, in `pdfmode'}}{\def\temp{`microtype' loaded}} +\end{example} -All the commands in this section are robust and can be used in expansion contexts. +\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[|cang(keyprefix)]{|cang(family)}[|cang(macroprefix)] + {|cang(primary boolean)}[|cang(default value for primary boolean)] + {|cang(secondary boolean)}{|cang(macro for primary boolean)} + {|cang(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}{}{% + \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} -\begin{macrocode} -\deftog{|fv(toggle)} -\end{macrocode} -This defines a new \fn{toggle} whether or not \fn{toggle} is already defined. If \fn{toggle} is already defined, a warning message is logged in the transcript file and the new definition is effected. +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 +} -\begin{macrocode} -\newtog{|fv(toggle)} -\end{macrocode} -This defines a new \fn{toggle} if \fn{toggle} is not already defined; otherwise the package issues a fatal error. +\setkeys[KV]{fam}{brother=true} +\end{example} +\acmd*{\SKV@AfterDocumentStart} -\begin{macrocode} -\providetog{|fv(toggle)} -\end{macrocode} -This defines a new \fn{toggle} if \fn{toggle} is not already defined. If \fn{toggle} is already defined, the command does nothing. +\section{Toggle booleans and keys} +\label{sec:toggles} -\begin{macrocode} -\requiretog{|fv(toggle)} -\end{macrocode} -\fx{\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 \fx{\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 \fx{\requiretog} also warns the user if there was a previous and different existing definition. For example, if the toggle \fn{toga} is currently \fn{true}, then since all new toggles start out as \fn{false}, a call \fx{\requiretog{toga}} will issue a warning in the log file that the new and old definitions of \fn{toga} don't agree and the new definition, therefore, can't go ahead. +In the following \crefrange{sec:toggle-booleans}{sec:toggle-keys} we define toggle booleans/switches and use them to introduce toggle-boolean keys. -The \sty{skeyval} package also provides the command \fx{\requirecmd}, which has the same logic as \fx{\requiretog} but can be used for general \latex commands, including those with optional arguments (see \secref{sec:misce-commands}). +\subsection{Toggle booleans} +\label{sec:toggle-booleans} -\begin{macrocode} -\settog{|fv(toggle)}{|fv(true |amdvert false)} -\end{macrocode} -This command sets \fn{toggle} to \fn{value}, where \fn{value} may be either \fn{true} or \fn{false}. This statement will issue an error if \fn{toggle} wasn't previously defined. +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}. There is no fear that the commands in this package will interfere with those from the \pkg{etoolbox}, since the internal control sequences and user interfaces of the two packages are different. -\begin{macrocode} -\togtrue{|fv(toggle)} -\end{macrocode} -This sets \fn{toggle} to \fn{true}. It will issue an error if \fn{toggle} wasn't previously defined. +All the commands in this section are robust and can be used in expansion or moving contexts, but fragile arguments would need to be protected in those settings. -\begin{macrocode} -\togfalse{|fv(toggle)} -\end{macrocode} -This sets \fn{toggle} to \fn{false}. It will issue an error if \fn{toggle} wasn't previously defined. +\begin{macro} +\deftog{|cang(toggle)} +\end{macro} +This defines a new \aang{toggle} whether or not \aang{toggle} is already defined. If \aang{toggle} is already defined, a warning message is logged in the transcript file (if the package option \fx{verbose} is selected) and the new definition is effected. -\begin{macrocode} -\iftog{|fv(toggle)}{|fv(true)}{|fv(false)} -\end{macrocode} -This yields the \fn{true} statement if the boolean \fn{toggle} is currently \fn{true}, and \fn{false} otherwise. It will issue an error if \fn{toggle} wasn't previously defined. +\begin{macro} +\newtog{|cang(toggle)} +\end{macro} +\acmdm*{\newtog} +This defines a new \aang{toggle} if \aang{toggle} is not already defined; otherwise the package issues a fatal error. You can define a set of toggles by the following command: +\begin{macro} +\NewTogs[|cang(optional prefix)]{|cang(toggles)}[|cang(optional state)], +\end{macro} +\acmdm*{\NewTogs} +where \aang{toggles} is a comma-separated list. Each member of \aang{toggles} is prefixed with \aang{prefix} upon definition. The optional \aang{state} can be either \fx{true} or \fx{false}. For example, we may define new toggles \fx{x}, \fx{y}, \fx{z} by the following: +\begin{example} +\NewTogs[skv@]{x,y,z}[true] +\end{example} -\begin{macrocode} -\ifnottog{|fv(toggle)}{|fv(not true)}{|fv(not false)} -\end{macrocode} -This behaves like \fx{\iftog} but the logic of the test is reversed. It will issue an error if \fn{toggle} wasn't previously defined. -\subsection{Toggle keys} +\begin{macro} +\providetog{|cang(toggle)} +\end{macro} +\acmdm*{\providetog} +This defines a new \aang{toggle} if \aang{toggle} is not already defined. If \aang{toggle} is already defined, the command does nothing. + +\begin{macro} +\requiretog{|cang(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 \aang{toga} is currently \aang{true}, then since all new toggles start out as \aang{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 \aang{toga} don't agree and the new definition, therefore, can't go ahead. + +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{|cang(toggle)}{|cang(true |amdvert false)} +\end{macro} +\acmdm*{\settog} +This command sets \aang{toggle} to \aang{value}, where \aang{value} may be either \aang{true} or \aang{false}. This statement will issue an error if \aang{toggle} wasn't previously defined. + +\begin{macro} +\togtrue{|cang(toggle)} +\end{macro} +\acmdm*{\togtrue} +This sets \aang{toggle} to \aang{true}. It will issue an error if \aang{toggle} wasn't previously defined. + +\begin{macro} +\togfalse{|cang(toggle)} +\end{macro} +\acmdm*{\togfalse} +This sets \aang{toggle} to \aang{false}. It will issue an error if \aang{toggle} wasn't previously defined. + +\begin{macro} +\iftog{|cang(toggle)}{|cang(true)}{|cang(false)} +\end{macro} +\acmdm*{\iftog} +This yields the \aang{true} statement if the boolean \aang{toggle} is currently \aang{true}, and \aang{false} otherwise. It will issue an error if \aang{toggle} wasn't previously defined. + +\begin{macro} +\ifnottog{|cang(toggle)}{|cang(not true)}{|cang(not false)} +\end{macro} +\acmdm*{\ifnottog} +This behaves like \fx{\iftog} but reverses the logic of the test. It will issue an error if \aang{toggle} wasn't previously defined. + +\subsection{Toggle-boolean keys} \label{sec:toggle-keys} -The syntax for defining toggle keys is exactly like those for boolean keys in the \sty{xkeyval} package. This allows all the machinery of the \sty{xkeyval} package (including \fx{\setkeys}, \fx{\presetkeys}, \fx{\savekeys}, \fx{\savevalue}, \fx{\usevalue}, etc) to be applicable to 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 \fx{\setkeys} command (and friends) of the \sty{xkeyval} package is unaware of this. This can cause problems when the user uses the same name for 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 \fx{\newboolkey}, \fx{\newboolkeys}, \fx{\newtogkey}, \fx{\newtogkeys}, \etc, of \secref{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 \secref{sec:redef-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[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(key)}[|cang(default)]% + {|cang(function)} -\begin{macrocode} -\define@togkey[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]% - {|fv(function)} +\define@togkey|redplus[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(key)}[|cang(default)]% + {|cang(function1)}{|cang(function2)} +\end{macro} +\acmdm*{\define@togkey,\define@togkey+} -\define@togkey|redplus[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]% - {|fv(function1)}{|fv(function2)} -\end{macrocode} +If the macro prefix \aang{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 \aang{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 the macro prefix \fn{mp} is not specified, these create a toggle of the form \fnn{prefix}{family}{key}{} using \fx{\deftog} (which initializes the toggle switch to \fn{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 \fn{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 \aang{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 \aang{default} will be used by the key macro when the user sets the key without a value. -If \fn{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 \fn{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 \aang{function1} and \aang{function2}. If user input is valid, the macro will set the toggle and executes \aang{function1}; otherwise, it will not set the boolean but will execute \aang{function2}. -If the plus (\redplus) version of the macro is used, the user can specify two key macros \fn{function1} and \fn{function2}. If user input is valid, the macro will set the toggle and executes \fn{function1}; otherwise, it will not set the boolean but will execute \fn{function2}. - -As an example, consider the following (adapted from the \sty{xkeyval} package to suit toggle keys): +As an example, consider the following: \begin{example} \define@togkey{fam}[my@]{frame}{% \iftog{my@frame}{% @@ -240,15 +348,16 @@ As an example, consider the following (adapted from the \sty{xkeyval} package to } \end{example} -The first example creates the toggle \fn{my@frame} and defines the key macro +The first example creates the toggle \aang{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{macrocode} -\define@togkeys[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(keys)}[|fv(default)] -\end{macrocode} -This creates a toggle key for every entry in the comma-separated list \fn{keys}. As is the case with the commands \fx{\define@cmdkeys} and \fx{\define@boolkeys} from the \sty{xkeyval} package, the individual keys in this case can't have a custom function. See section~\ref{sec:multiplekeys} for how to define multiple keys with custom functions. +\begin{macro} +\define@togkeys[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(keys)}[|cang(default)] +\end{macro} +\acmdm*{\define@togkeys} +This creates a toggle key for every entry in the comma-separated list \aang{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:multiplekeys} for how to define multiple keys with custom functions. As an example of defining multiple toggle keys, consider \begin{example} @@ -269,200 +378,224 @@ Now we can do } \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@|fv(mp)|fv(key) +\show\SKV@toggle@|cang(mp)|cang(key) \end{example} -when the \fn{mp} is present. When the user has specified no \fn{mp} in defining the key, he has to issue +when the \aang{mp} is present. When the user has specified no \aang{mp} in defining the key, he has to issue \begin{example} -\show\SKV@toggle@|fv(prefix)@|fv(family)@|fv(key). +\show\SKV@toggle@|cang(prefix)@|cang(family)@|cang(key). \end{example} \section{Complementary toggle keys} +\label{sec:comptogkeys} + +\subsection{Bipolar toggle-boolean keys} -Similar to complementary boolean keys of \secref{sec:comp-boolkeys}, the \sty{skeyval} package introduces a facility for creating complementary toggle keys. The syntax for this is similar to that for defining complementary toggle keys: -\begin{macrocode} -\define@comptogkeys[|fv(keyprefix)]{|fv(family)}[|fv(macroprefix)] - {|fv(primary toggle)}[|fv(default value for primary toggle)] - {|fv(secondary toggle)}{|fv(func for primary toggle)} - {|fv(func for secondary toggle)}. -\end{macrocode} -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 \fn{keyprefix} and/or \fn{macroprefix}, the package will use \fn{KV} and \fn{mp@}, respectively. When one toggle key (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. +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[|cang(keyprefix)]{|cang(family)}[|cang(macroprefix)] + {|cang(primary toggle)}[|cang(default value for primary toggle)] + {|cang(secondary toggle)}{|cang(func for primary toggle)} + {|cang(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 \aang{keyprefix} and/or \aang{macroprefix}, the package will use \aang{KV} and \aang{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 complementary toggle keys \fn{xdraft} and \fn{xfinal} with different key macros: +As an example, we define below two bipolar toggle keys \aang{xdraft} and \aang{xfinal} with different key macros: \begin{example} -\define@comptogkeys[KV]{fam}[mp@]{xdraft}[true]{xfinal}% - {% - \def\gobble##1{}% - }{% - \def\notgobble##1{##1}% - }. +\define@bitogkeys[KV]{fam}[mp@]{xdraft}[true]{xfinal}% +{\def\gobble##1{}}{\def\firstofone##1{##1}} \end{example} -The key prefix (whose default is \fn{KV}), macro prefix (whose default is \fn{mp@}), and key macros (no default) can be empty: +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@comptogkeys{fam}{xdraft}[true]{xfinal}{}{}. +\define@bitogkeys{fam}{xdraft}{xfinal}{}{}. \end{example} -The defined complementary toggle keys \fn{xdraft} and \fn{xfinal} can now be set as follows: +The defined bipolar toggle keys \aang{xdraft} and \aang{xfinal} can now be set as follows: \begin{example} \setkeys[KV]{fam}{xdraft=true} \setkeys[KV]{fam}{xfinal=true} \end{example} -The second statement above reverses the toggle \fn{xdraft} to \fn{false}, which had been set in the first statement to \fn{true}. +\acmd*{\setkeys} +The second statement above reverses the toggle \aang{xdraft} to \aang{false}, which had been set in the first statement to \aang{true}. -Toggle keys may easily be confused with the conventional boolean keys, at the time of definition and setting. It is therefore always safer to use the syntaxes in \secref{sec:redef-keys} for defining keys; they avoid interference between new and existing keys. +Toggle keys may easily be confused with the conventional (native) 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. + +\Note 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 \aang{fam} and prefix \aang{KV}. The names \acmd{draft} and \acmd{final} can be used as toggles only if the family \aang{fam} or prefix \aang{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[|cang(keyprefix)]{|cang(family)}[|cang(macroprefix)] + {|cang(primary toggle)}[|cang(default value for primary toggle)] + {|cang(secondary toggle)}{|cang(func for primary toggle)} + {|cang(func for secondary toggle)}. +\end{macro} +\acmdm*{\define@unitogkeys} +Here too, if the user doesn't supply the \aang{keyprefix} and/or \aang{macroprefix}, the package will use \aang{KV} and \aang{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} -\paragraph{Note} If we were to use the key names \fx{draft} and \fx{final} as toggle keys above, instead of \fx{xdraft} and \fx{xfinal}, there would have been a clash with the keys \fx{draft} and \fx{final} defined as (complementary) boolean keys in \secref{sec:comp-boolkeys}---because they share the same family \fn{fam} and prefix \fn{KV}. The names \fx{draft} and \fx{final} can be used as toggles only if the family \fn{fam} or prefix \fn{KV} is changed. +\subsection{Biunipolar toggle-boolean keys} -\section[Defining multiple keys by one command]% +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[|cang(keyprefix)]{|cang(family)}[|cang(macroprefix)] + {|cang(primary boolean)}[|cang(default value for primary boolean)] + {|cang(secondary boolean)}{|cang(macro for primary boolean)} + {|cang(macro for secondary boolean)} +\end{macro} +\acmdm*{\define@biunitogkeys,\define@biunitogkeys*,\define@biunitogkeys*+} + +\begin{example} +\define@biunitogkeys|redplus[KV]{fam}[mp@]{preprint}[true]{review}{% + \iftog{mp@preprint}{% + \def\banner{\fbox{\textsf{This is a preprint copy}}}% + }{}% +}{% + \iftog{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:multiplekeys} -The interface for defining multiple keys of all kinds in one go is the command \fx{\define@keylist}, whose syntax is -\begin{macrocode} -\define@keylist{|fv(key type/id), |fv(key), |fv(key default value), - |fv(key macro/function); |fv(another set of key specifiers); etc} -\end{macrocode} +The interface for defining multiple keys of all kinds in one go is the command \acmdm{\define@keylist}, whose syntax is +\begin{macro} +\define@keylist{|cang(key type/id), |cang(key), |cang(key default value), + |cang(key macro/function); |cang(another set of key specifiers); etc} +\end{macro} -There are five key types: 1 (ordinary key), 2 (command key), 3 (boolean key), -4 (toggle key), and 5 (choice key). The key and its attributes are separated by commas; they constitute one \fx{object}. The objects are separated by the \fn{keyparser}, which is the semicolon in the above example. +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 (\fs{ord}, \fx{cmd}, \fx{bool}, \fx{tog}, \fx{choice}, \fx{menu}). ``Choice'' and ``menu'' key types 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 \aang{keyparser}, which is the semicolon in the above example. If the key list is available in a macro, say, \begin{example} -\def\keylist{|fv(key type/id), |fv(key), |fv(key default value), - |fv(key macro/function); |fv(another set of key specifiers); etc}, +\def\keylist{|cang(key type/id), |cang(key), |cang(key default value), + |cang(key macro/function); |cang(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}\redstarr takes a macro as argument, while \fx{\define@keylist} accepts a key list. +\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} -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 \secref{sec:redef-keys}\footnote{In fact, I now often use the machinery of \secref{sec:redef-keys} to safely define new keys without the fear of inadvertently redefining an existing key within the same family and with the same key prefix.}. +\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}.\footnote{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.} \subsection{Choice key values} +\label{sec:choice-key-values} -The \fx{\ChoiceKeyValues} macro is needed for choice keys; it lists the alternate +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. Its syntax is -\begin{macrocode} -\ChoiceKeyValues{|fv(key)}{|fv(list)}, -\end{macrocode} -where \fn{list} is a comma-separated list of admissible key values. -To further save tokens, the macro \fx{\ChoiceKeyValues} may be abbreviated by \fx{\CKVS}. It has to be defined each time a choice key is being defined. For example, if we want to define two choice keys \fx{align} and \fx{election}, then before the call to \fx{\define@keylist}, we have to set +is being defined via \fx{\define@keylist}. Its syntax is +\begin{macro} +\choicekeyvalues|redstar[|cang(prefix)][|cang(family)]{|cang(key)}{|cang(list)}, +\end{macro} +where \aang{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 \aang{prefix} and \aang{family} are optional, provided the key prefix and family have been specified before calling \fx{\choicekeyvalues}, using \fx{\skvoptions}. If \aang{prefix} and \aang{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{election}{state,federal,congress,senate}. +\CKVS{shootingmodes}{portrait,indoor,foliage,underwater} \end{example} -It doesn't matter which choice key first gets a \fx{\CKVS}. The prevailing key prefix and key family are used internally by \fx{\ChoiceKeyValues} to build distinct alternate values lists for choice keys.Unless the key family changes, you can't set two \fx{\ChoiceKeyValues} for the same choice key. This will be possible only if the package option \fx{xchoicelist} (meaning ``allow overwriting of choice list'') has been set \fn{true}, either through \fx{\documentclass}, \fx{\usepackage}, or \fx{\skvoptions}. Therefore, any number of choice keys are allowed to appear in one \fx{\define@keylist} or \fx{\define@keylist}\redstarr statement if their lists of alternate/admissible values have been set by \fx{\CKVS}. 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,xchoicelist=value}. -\end{example} - -In line with the philosophy of the \sty{xkeyval} package, all the choice keys to be defined using the \sty{skeyval} package require \fx{\ChoiceKeyValues}: choice keys, by definition, have pre-ordained or acceptable values. - -\subsection{Some internals} - -The internal equivalent of \fx{\ChoiceKeyValues} (the choice key list of alternative values) is the macro \bs\fnn{keyprefix}{keyfamily}{key}{altlist}. For example, for a key \fx{align} in the family \fx{fam}, and with prefix \fx{KV}, the internal of \fx{\CKVS} is \fx{\KV@fam@align@altlist}. - -For all keys in a family, the internal of the key macro (provided at key definition time) can be accessed via the macros -\begin{macrocode} -\|fv(keyprefix)@|fv(keyfamily)@|fv(key)@|fv(func). -\end{macrocode} -These internals are available for only the keys defined via \fx{\define@keylist} or \fx{\newkeylist}! - -It should be noted that the \sty{xkeyval} package will save and provide a key value when the value is saved (using the pointers \fx{\savevalue} or \fx{\gsavevalue}) at the time the key is set, or when the key is included in the \fx{\savekeys} (or \fx{\gsavekeys}) list. In that case, the saved value will be available in -\begin{example} -\XKV@|fv(keyprefix)@|fv(keyfamily)@|fv(key)@|fv(value), + keyfamily=value}. \end{example} -where the prefix \fx{XKV@} is usually added. The saved value can also be accessed via \fx{\usevalue}\unskip\sv{key} but only within \fx{\setkeys} command. Since the \sty{skeyval} package uses the machinery of the \sty{\xkeyval} in the background, all these pointers can still be utilized for the keys defined via all the new key definition mechanisms introduced by the \sty{skeyval} package (\eg, the commands \fx{\define@togkey}, \fx{\define@keylist}, \fx{\newkeylist}, \etc). +\acmd*{\skvoptions} -The macro \bs\fnn{keyprefix}{keyfamily}{key}{func} is undefined if \fn{key} has not been defined or if it has been removed; and the macro -\begin{example} -\XKV@|fv(keyprefix)@|fv(keyfamily)@|fv(key)@|fv(value) -\end{example} -is undefined whenever \fn{key} has no value specified, or has not been set. So it is advisable to always test for the existence of these macros before they are used. +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:examples} +\label{sec:multkeys-examples} -In this section we provide a glimpse of the potential applications of the tools provided by the \sty{skeyval} package in the context of defining multiple keys by one command. +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,xchoicelist=false}. + keyfamily=fam} \end{example} -Further, suppose we wish to define a set of keys \fn{color,angle,scale,align}. The keys \fx{color}, \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 $\langle$\unskip\fx{center} \amdvert\ \fx{right} \amdvert\ \fx{left} \amdvert\ \fx{justified}\unskip$\rangle$, 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 keys \fx{color} and \fx{angle} aren't associated with macros. Then we can do: +\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: +\acmd*{\CKVS} \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,windy,\someweather} - % |color(gray) We assume that \someweather is defined - % |color(gray) somewhere and holds an admissible value - % |color(gray) for the key ``weather'' at any level.|color(verbcolor) -\def\f@align{% + 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 + \or\def\mp@align{\flushright}% + \or\def\mp@align{\flushleft}% + \or\let\mp@align\relax \fi } - -\define@keylist{2,color,gray!25,;2,angle,45,; - 2,scale,1,\def\mydo##1{\do ##1};5,align,center,\f@align; - |color(red)\stopread|color(verbcolor);3,mybool,true,; - 5,weather,sunny,\protected@edef\VWeather{\val}}. +|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} -The \fx{\nr} and \fx{\val} macros are bin parameters for choice keys, as defined by the \sty{xkeyval} package. \fx{\val} contains the user input for the current key and \fx{\nr} contains the numeral corresponding to the user input in the \fx{\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{\f@align} before hand, we can submit its replacement text directly to the macro \fx{\define@keylist}, but, because \fx{\f@align} contains a conditional, some care is needed in doing so (see section~\ref{sec:conditionals}). Once the key \fx{align} has been defined, the macro \fx{\f@align} can be reused---perhaps to define other keys---even before the key \fx{align} is set. This is because it isn't \fx{\f@align} that is used in defining the key \fx{align} but its internal counterpart (\ie, a prefix and family-dependent internal of \fx{\f@align}, which is \fx{\KV@fam@align@func}). In this way, the user can economize on tokens. The same applies to all the macros that may be used in defining keys via \fx{\define@keylist}. +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. -Note the \fx{\stopread} command inserted above. Because of it, the key \fx{mybool} will not be read and defined; the rest (\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 \fx{\SKV@remainder}, possibly for some other uses. +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. -Hundreds of keys can be defined efficiently in this way, using very few tokens. +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. -As another example, we consider the following keys: +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{align}{center,right,left,justified} +\CKVS|redstar{align}{center,right,left,justified} \CKVS{election}{state,federal,congress,senate} -% |color(gray)\CKVS needs to be defined only once for each key in a family.|normalcolor -\define@keylist{% - 3,boolvar,true,;1,paperheight,\paperheight,; - 1,paperwidth,\paperwidth,\f@paperwidth; - 2,textheight,\textheight,\f@textheight; - 2,textwidth,\textwidth,\f@textwidth; - 1,evensidemargin,\evensidemargin,; - 5,align,center,\f@align; - 5,election,congress,; - 2,testdim,2cm,\long\def\f@testdim##1{A test dimension ##1 - \par\bigskip}% - % |color(gray) Note the number of parameter characters - % |color(gray) in the definition of \f@testdim. -} -\end{example} -which have the following trivial key macros: -\begin{example} -\def\f@textwidth{\AtBeginDocument{\wlog{`textwidth' % - is \mp@textwidth}}} +\def\funcfortextwidth{\AtBeginDocument{\wlog{`textwidth' % + is `\mp@textwidth'}}} -\def\f@textheight{% +\def\funcfortextheight{% \ifx\@empty\mp@textheight \wlog{`textheight' value empty}% \else @@ -470,356 +603,765 @@ which have the following trivial key macros: \fi } -\def\f@paperwidth{\wlog{`paperwidth' was defined as % +\def\funcforpaperwidth{\wlog{`paperwidth' was defined as % ordinary key.}} -\newcommand\f@align{% + +\def\funcforalign{% \ifcase\nr\relax \def\mp@align{\centering}% - \or - \def\mp@align{\flushright}% - \or - \def\mp@align{\flushleft}% - \or - \let\mp@align\relax + \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,\iftog{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} -Again, once the keys have been defined, these macros can be reused. - -The same set of keys can be defined via the starred form of \fx{\define@keylist}: -\begin{example} -\def\keylist{% - 3,boolvar,true,;1,paperheight,\paperheight,; - 1,paperwidth,\paperwidth,\f@paperwidth; - 2,textheight,\textheight,\f@textheight; - 2,textwidth,\textwidth,\f@textwidth; - 1,evensidemargin,\evensidemargin,; - 4,mytoggle,true,\let\settoggle\settog; - 5,align,center,\f@align; - 5,election,congress,; - 2,testdim,2cm,\long\def\f@testdim##1% - {Do something with ##1}% +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,\iftog{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\keylist. +\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 -\begin{example} -\KV@fam@testdim -\end{example} -holds the macros: +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\f@testdim##1{A test dimension##1\par\bigskip}, +\long\def\funcfortestdim##1{A test dimension ##1}, \end{example} -where \WithHash{1} is the value submitted for the key \fx{testdim}. -Try \fx{\show\mp@align}, \fx{\show\KV@fam@testdim}, and \fx{\show\f@testdim} to confirm the above assertions. +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} -Try \fx{\show\ifmp@boolvar} to confirm that \fx{boolvar} is now \fn{true}; it was originally set as \fn{false}. The macro \fx{\KV@fam@paperwidth} holds the function \fx{\f@paperwidth}; \fx{\mp@textheight} holds the value submitted to key \fx{textheight} at any instance of \fx{\setkeys}. By the above \fx{\setkeys}, only the default values of \fx{paperheight}, \fx{paperwidth}, and \fx{textheight} are presently available. +\acmd*{\setkeys} +Try \fx{\show\ifmp@boolvar} to confirm that \fx{boolvar} is now \aang{true}; it was originally set as \aang{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) +|comm(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{\iftog{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,\iftog{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{\iftog{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{The keycommand interface} +\label{sec:keycommand} +\acmdm*{keycommand} + +The \fx{\define@keylist} macro provides an interface for defining commands in the manner of the \pkg{keycommand}. We haven't developed this interface well enough but the following example shows what is currently obtainable and the possibilities for future enhancements. It is hoped that further work in this direction will be undertaken in the future. I do foresee that the user interface will be made lighter in the future. For now, the \fx{\skvoptions} command needs be reissued only when the key family changes, and in that case we simply have to do \fx{\skvoptions{keyfamily=name}}. Any future enhancement should seek to hide the \fx{\setkeys} command from the user. -Instead of using macros to pass key macros and functions, it is also possible to use token registers. An example is provided below: \begin{example} -\toks0={\long\def\f@testdim#1{A test dimension #1\par\bigskip}} -\define@keylist{3,boolvar,true,;2,testdim,2cm,\the\toks0}. +\skvoptions{keyparser=;,macroprefix=mp,keyprefix=KV, + keyfamily=rule} +\define@keylist{cmd,raise,.5ex,;cmd,width,1em,; + cmd,thick,.4pt,;bool,proclaim,true,} +\setkeys[KV]{rule}{raise,width,thick,proclaim=false} +\newcommand*\Rule[2][Hello]{% + \setkeys[KV]{rule}{#2}% + \rule[\mpraise]{\mpwidth}{\mpthick}% + #1% + \rule[\mpraise]{\mpwidth}{\mpthick}\hspace*{1em}% + \ifmpproclaim \color{red}\fi\textdaggerdbl +} +|makered(\begin{document}) +\parindent\z@ +\begin{tabular*}\textwidth{rr} +\verb+\Rule[width=2em]{hello}+:|ampersand + \Rule[Hello World]{width=2em,proclaim}\cr +\verb+\Rule[thick=1pt,width=2em]{hello}+:|ampersand + \Rule{thick=2pt,width=2em}\cr +\verb+\Rule{hello}+:|ampersand + \Rule[Hello World]{proclaim}\cr +\verb+\Rule[thick=1pt,raise=1ex]{hello}+:|ampersand + \Rule[Hello World]{thick=1pt,raise=1ex} +\end{tabular*} +|makered(\end{document}) \end{example} -The advantage of using token registers is that the parameter characters need not be doubled in the token registers, unlike when using macros. The token register \fx{\toks0} can be reused as soon as the key \fx{testdim} is defined. See \secref{sec:condit-in-macros} for more information on using macros and token registers to pass key functions. -\section{Input error} +\subsection{Input error} +\label{sec:input-error} -Boolean, toggle 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 boolean and toggle keys are \fn{true} and \fn{false}. The valid values of choice keys are set by the user via \fx{\VKVS}. The default input error is defined by \fx{\SKV@inputerr} macro to be -\begin{macrocode} -\SKV@err{Erroneous value `#1' for key `#2'}{% - Please use the correct value for key `#2'.}. -\end{macrocode} -\fx{\SKV@inputerr} can be redefined by the user. It takes two arguments (\ie, value and key). +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. -\section{Conditionals in key macros} -\label{sec:conditionals} +\subsection{Conditionals in key macros} +\label{sec:condit-in-keys} -The \tex conditional primitives \fx{\if} and \fx{\fi} cannot appear in the key macro when \fx{\define@keylist} is being invoked. The reason can be traced to the discussion on page~211 of the \TeX Book and the loop used in the \sty{skeyval} package to define keys. There are three approaches to resolving this problem, and the user can choose anyone he/she prefers. +\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}). -\subsection[Using macros or token registers]% - {Burying conditionals in macros or token registers} +\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 \fi +\ifmp@bool \do \else \donot \fi \end{example} -can be submitted to \fx{\define@keylist} via macros, as seen above. We give more examples below. +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 \fi}. +\define@keylist{3,bool,true,\ifmp@bool \do \else \donot \fi}. \end{example} -The presence of \fx{\if} and \fx{\fi} in the argument will trigger an error when \tex is scanning or skipping tokens, and, secondly, because of the loop and conditional used by the \sty{skeyval} package in defining keys. Neither \fx{\protect} nor \fx{\noexpand} is helpful here. One solution is to first define +\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\f@bool{\ifmp@bool \do \fi} +\def\funcforbool{\ifmp@bool \do \else \donot \fi} \end{example} and then do \begin{example} -\define@keylist{3,bool,true,\f@bool}, +\define@keylist{3,bool,true,\funcforbool}, \end{example} -which will execute \fx{\f@bool} when the key \fx{bool} is set. Once the key \fx{bool} has been defined by the above statement, the function \fx{\f@bool} may be redefined and reused many times, any time, even before the setting of the key \fx{bool}. It isn't the function \fx{\f@bool} that is used in defining the key \fx{bool}, but an internal or meaning of \fx{\f@bool}, depending on the contents of \fx{\f@bool}. +\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\f@abool{\ifmp@abool\def\do####1{% - \def####1########1{\expandafter\expandafter\expandafter\in@ - \expandafter\expandafter\expandafter{\expandafter####1 - \expandafter}\expandafter{########1}}}\fi} +\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,abool,true,\f@abool}. +\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 registers (including scratch token registers) can be used here economically instead of macros: +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} -\toks0{\ifmp@abool\def\do#1{% - \def#1##1{\expandafter\expandafter\expandafter\in@ - \expandafter\expandafter\expandafter{\expandafter#1 - \expandafter}\expandafter{##1}}}\fi} +\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} -\toks1{\iftog{toggleone}{def\tempa#1{Use #1}}{}} +\temptoksb{\iftog{mp@toga}{\def\order#1{Use `#1' now!}}{}} -\define@keylist{3,abool,true,\the\toks0; - 4,toggleone,true,\the\toks1} +\define@keylist{3,boola,true,\the\temptoksa; + 4,toga,true,\the\temptoksb} -\setkeys[KV]{fam}{abool=true,toggleone=true}. +\setkeys[KV]{fam}{boola=true,toga=true} \end{example} -You can see the significant reduction in the number of parameter characters when using token registers. The token registers \fx{\toks0} and \fx{\toks1} can be reused to define many other keys as soon as the keys \fn{abool} and \fn{toggleone} have been defined, even before they are set. +\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. -\subsection{Using a trick to submit the conditionals} -\label{sec:dirty-trick} +\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: -\begin{enumerate} -\item The macros have to be defined and, although they can be redefined and reused, they tend to defeat the initial aim of the package, which is to economize on tokens. -\item If the conditionals involve macro definitions as in the above example, the parameter characters have to be doubled in each instance, except when using token registers. -\end{enumerate} +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 boolean key \fx{mybool} with the following key macro: +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}}\fi, +\ifmp@mybool + \def\hold##1{\def##1####1{***####1***}}% +\else + \def\hold##1{\def##1####1{===####1===}}% +\fi \end{example} -where the macro prefix is \fx{mp@} and the key family has been defined previously. Then, instead of hiding the conditional in a macro, we can go +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, - \fif{mp@mybool}\def\hold##1{\def##1####1{####1}}\ffi}. + |makered(\skif{|makemac(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} -Here we have used \fx{\fif{mp@mybool}} and \fx{\ffi} for \fx{\ifmp@mybool} and \fx{\fi}, respectively, to hide the latter two from \TeX's scanning and skipping mechanism. Please note that \fx{\fif{mp@mybool}} requires that the argument \fn{mp@mybool} be enclosed in braces. Something like \fx{\fifmp@mybool} will be interpreted by \tex as undefined control sequence when the key \fx{mybool} is being set. +\acmdm*{\skif,\skifx,\skelse,\skfi} +\acmd*{\skifcase,\skor,\define@keylist} +Here we have used \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 \aang{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. -We have redefined the \fx{\setkeys} of the \sty{xkeyval} package to understand that \fx{\fif} and \fx{\ffi} stand for \fx{\if} and \fx{\fi}, respectively. The redefined \fx{\setkeys} command has the same syntax as as in \sty{xkeyval} package: -\begin{macrocode} -\setkeys[|fv(prefix)]{|fv(families)}[|fv(na)]{|fv(keys=values)} -\setkeys|redstar[|fv(prefix)]{|fv(families)}[|fv(na)]{|fv(keys=values)} -\setkeys|redplus[|fv(prefix)]{|fv(families)}[|fv(na)]{|fv(keys=values)} -\setkeys|redstar|redplus[|fv(prefix)]{|fv(families)}[|fv(na)]{|fv(keys=values)}. -\end{macrocode} -The reader who is unfamiliar with the meaning of star and plus signs in the \fx{\setkeys} command should consult the documentation for the \sty{xkeyval} package. No errors are produced if any of the sets \fn{prefix}, \fn{families}, \fn{na}, and \fn{keys=values} is empty. In fact, an instruction such as \fx{\setkeys[]{}[]{}} is completely benign, and so is \fx{\setkeys{}{}}. +\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} 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. -In the case of conditionals starting with \fx{\ifcase}, a \fx{\noexpand} before the \fx{\ifcase} solves the problem: +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 syntax as as in \pkg{xkeyval}: +\begin{macro} +\setkeys[|cang(prefix)]{|cang(families)}[|cang(na)]{|cang(keys=values)} +\setkeys|redstar[|cang(prefix)]{|cang(families)}[|cang(na)]{|cang(keys=values)} +\setkeys|redplus[|cang(prefix)]{|cang(families)}[|cang(na)]{|cang(keys=values)} +\setkeys|redstar|redplus[|cang(prefix)]{|cang(families)}[|cang(na)]{|cang(keys=values)}. +\end{macro} +\acmdm*{\setkeys,\setkeys*,\setkeys*+} +No errors are produced if any of the sets \aang{prefix}, \aang{families}, \aang{na}, and \aang{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} -\define@keylist{5,focus,center,|color(red)\noexpand|color(verbcolor)\ifcase\nr\relax +\temptoksa{\ifcase\nr\relax \def\mp@focus{\centering}\or\def\mp@focus{\flushright} - \or\def\mp@focus{\flushleft}\or\let\mp@focus\relax\fi -} + \or\def\mp@focus{\flushleft}\or\let\mp@focus\relax\fi} + +\define@keylist{5,focus,center,\the\temptoksa} \end{example} -However, such conditionals may also be buried in macros or token registers. +\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 a different semantics. + +A new switch can be introduced by using the following command: +\begin{macro} +\newswitch{|cang(switch)}{|cang(value/state)} +\end{macro} +There should be no \fx{\if} in \aang{switch} when using \fx{\newswitch}. Valid values/states of switches are `true' (or `on') and `false' (or `off'). With this definition you can issue \fx{\if}\unskip\aang{switch}, \bs\aang{switch}\unskip\fx{true}, and \bs\aang{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. -\subsection{Using toggles} +You can define many switches in a row by the following command: +\begin{macro} +\NewSwitches[|cang(optional prefix)]{|cang(switches)}[|cang(optional state)] +\end{macro} +Each member of \aang{switches} is prefixed with \aang{prefix} upon definition. The optional \aang{state} can be either \fx{true} or \fx{false}. + +Here are some examples: -Toggle switches, described in \secref{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. For example, the following works: \begin{example} -\define@keylist{4,toggleone,true, - \iftog{toggleone}{\def\temp{This is defined by a toggle}}{}}. +\NewSwitches{x,y,z} + |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} -And, as noted in \secref{sec:toggles}, toggles are very economical. -\section{Checking and redefining keys} -\label{sec:redef-keys} +Switches may be set and tested using the following commands: +\begin{macro} +\setswitch{|cang(switch)}{|cang(value/state)} -\subsection{Checking the status of a key} +\switchon{|cang(switch)} |tto \|cang(switch)true + +\switchtrue{|cang(switch)} |tto \|cang(switch)true + +\switchoff{|cang(switch)} |tto \|cang(switch)false + +\switchfalse{|cang(switch)} |tto \|cang(switch)false + +\ifswitchon{|cang(switch)}{|cang(true text)}{|cang(false text)} + +\ifswitchtrue{|cang(switch)}{|cang(true text)}{|cang(false text)} + +\ifswitchoff{|cang(switch)}{|cang(not true)}{|cang(not false)} -Three mechanism have been introduced in the \sty{skeyval} package to ascertain the statuses of keys. These are as follows. +\ifswitchfalse{|cang(switch)}{|cang(not true)}{|cang(not false)} +\end{macro} +\acmdm*{\newswitch,\NewSwitches,\setswitch,\switchon,\switchoff,\ifswitchon, +\ifswitchoff,\switchtrue,\switchfalse,\ifswitchtrue, +\ifswitchfalse} -\begin{macrocode} -\ifkeydefined[|fv(prefixes)]{|fv(families)}{|fv(key)}{|fv(true)}{|fv(false)}. -\end{macrocode} -This executes \fn{true} if \fn{key} is defined, reserved, or suspended with a prefix in \fn{prefixes} and family in \fn{families}; it returns \fn{false} otherwise. This is similar to -the \sty{xkeyval} package's \fx{\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 \fn{prefixes} and \fn{families} may contain nil, one or more elements. +\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} + +Suppose the key prefix is \fx{KV}, the key family is \fx{fam}, and the key macro is \fx{mp@}. The the following works: +\begin{example} +\define@keylist{3,switcha,true, + |makered(\ifswitchon){mp@switcha}{\def\say{Swtich `a' is true}} + {\def\say{Swtich `a' is false}}} + +\setkeys[KV]{fam}{switcha=true |makered(or) false} +\end{example} + +\Note Please note that switch keys are boolean keys (type~`3' key). As yet, when setting switch keys you must supply either \fx{true} or \fx{false}, not \fx{on} or \fx{off}. + +\subsubsection[Using toggles]{Using toggles to submit the conditionals} +\label{sec:using-toggles} -\begin{macrocode} -\ifkeyreserved[|fv(prefixes)]{|fv(families)}{|fv(key)}{|fv(true)}{|fv(false)} -\end{macrocode} -This returns \fn{true} if \fn{key} is reserved with a prefix in \fn{prefixes} and family in \fn{families}; it returns \fn{false} otherwise. Reserved keys are introduced in \secref{sec:reserve-keys}. +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(\iftog){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,\iftog} +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. -\begin{macrocode} -\ifkeysuspended[|fv(prefixes)]{|fv(families)}{|fv(key)}{|fv(true)}{|fv(false)} -\end{macrocode} -This executes \fn{true} if \fn{key} is suspended with a prefix in \fn{prefixes} and family in \fn{families}; it executes \fn{false} otherwise. Suspended keys are introduced in \secref{sec:suspend-keys}. +\section{Checking and redefining keys} +\label{sec:check-redef-keys} -\subsection[Redefining keys]{Unintentional redefinition of 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[|cang(prefixes)]{|cang(families)}{|cang(key)}{|cang(true)}{|cang(false)} +\end{macro} +\acmdm*{\ifkeydefined} +This executes \aang{true} if \aang{key} is defined, reserved, or suspended with a prefix in \aang{prefixes} and family in \aang{families}; it returns \aang{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 \aang{prefixes} and \aang{families} may contain nil, one or more elements. + +\begin{macro} +\ifkeyreserved[|cang(prefixes)]{|cang(families)}{|cang(key)}{|cang(true)}{|cang(false)} +\end{macro} +\acmdm*{\ifkeyreserved} +This returns \aang{true} if \aang{key} is reserved with a prefix in \aang{prefixes} and family in \aang{families}; it returns \aang{false} otherwise. Reserved keys are introduced in \cref{sec:reserve-keys}. + +\begin{macro} +\ifkeysuspended[|cang(prefixes)]{|cang(families)}{|cang(key)}{|cang(true)}{|cang(false)} +\end{macro} +\acmdm*{\ifkeysuspended} +This executes \aang{true} if \aang{key} is suspended with a prefix in \aang{prefixes} and family in \aang{families}; it executes \aang{false} otherwise. Suspended keys are introduced in \cref{sec:suspend-keys}. + +\subsection{Unintentional redefinition of keys} +\label{sec:redef-keys} -The \sty{xkeyval} package, by default, permits the automatic redefining of keys of the same \fn{prefix} and \fn{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 \fn{prefix} and \fn{family}. In some circumstances this can be undesirable, and even dangerous, especially if the same key (of the same \fn{prefix} and \fn{family}) is mistakenly redefined with different macros/functions in the same package or across packages. One way to solve this problem is to use \sty{xkeyval} package's \fx{\key@ifundefined} command (or the \sty{skeyval} package's \fx{\ifkeydefined}) to confirm the status of a key prior to its definition. However, using this command before defining every key can be laborious. +The \pkg{xkeyval}, by default, permits the automatic redefining of keys of the same \aang{prefix} and \aang{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 \aang{prefix} and \aang{family}. In some circumstances this can be undesirable, and even dangerous, especially if the same key (of the same \aang{prefix} and \aang{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} -Obviously the two definitions of \fn{keya} are valid and will be implemented but the \fx{\setkeys} command will issue an unintelligible error message, like \LaTeX's ``You are in trouble here \textellipsis''. The key \fn{keya} has been defined twice and \fx{\setkeys} has sought to use its latest definition to set its value, which is incorrect. As mentioned in \secref{sec:toggle-keys}, the \fx{\setkeys} command (and friends) of the \sty{xkeyval} package doesn't know if a key has been redefined in the same \fn{family} and with the same \fn{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 \fx{\setkeys}) if they have names identical to other keys within the same family and with the same prefix. +\acmd*{\setkeys} +Obviously the two definitions of \aang{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 \aang{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 \aang{family} and with the same \aang{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. -\subsubsection{Avoiding multiple definitions of same key} +If the package option \fx{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. -For the above reasons, the \sty{skeyval} package introduces the following commands, which have the same syntaxes as their counterparts from the \sty{xkeyval} and \sty{skeyval} packages but which bar the user from repeated definition of keys with identical names within the same \fn{family} and with the same \fn{prefix}: -\begin{macrocode} -% |color(brown) The following defines ``ordinary'' keys [the counterpart -% |color(brown) of \define@key from the xkeyval package]:|color(verbcolor) -\newordkey[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(default)]{|fv(funtion)} - -% |color(brown) Counterpart of \define@cmdkey:|color(verbcolor) -\newcmdkey[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]% - {|fv(funtion)} - -% |color(brown) Counterpart of \define@cmdkeys:|color(verbcolor) -\newcmdkeys[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(keys)}[|fv(default)] - -% |color(brown) Counterparts of \define@boolkey:|color(verbcolor) -\newboolkey[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]% - {|fv(funtion)} -\newboolkey|redplus[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]% - {|fv(funtion1)}{|fv(funtion2)} - -% |color(brown) Counterpart of \define@compboolkeys:|color(verbcolor) -\newcompboolkeys[|fv(prefix)]{|fv(family)}[|fv(mp)] - {|fv(primary boolean)}[|fv(default value for primary boolean)] - {|fv(secondary boolean)}{|fv(func for primary boolean)} - {|fv(func for secondary boolean)} - -% |color(brown) Counterparts of \define@togkey:|color(verbcolor) -\newtogkey[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]% - {|fv(funtion)} -\newtogkey|redplus[|fv(prefix)]{|fv(family)}[|fv(mp)]{|fv(key)}[|fv(default)]% - {|fv(funtion1)}{|fv(funtion2)} - -% |color(brown) Counterpart of \define@comptogkeys:|color(verbcolor) -\newcomptogkeys[|fv(prefix)]{|fv(family)}[|fv(mp)] - {|fv(primary toggle)}[|fv(default value for primary toggle)] - {|fv(secondary toggle)}{|fv(func for primary toggle)} - {|fv(func for secondary toggle)} - -% |color(brown) Counterparts of \define@choicekey:|color(verbcolor) -\newchoicekey[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(bin)]{|fv(alt)}% - [|fv(default)]{|fv(funtion)} -\newchoicekey|redstar[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(bin)]{|fv(alt)}% - [|fv(default)]{|fv(funtion)} -\newchoicekey|redplus[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(bin)]{|fv(alt)}% - [|fv(default)]{|fv(funtion1)}{|fv(funtion2)} -\newchoicekey|redstar|redplus[|fv(prefix)]{|fv(family)}{|fv(key)}[|fv(bin)]{|fv(alt)}% - [|fv(default)]{|fv(funtion1)}{|fv(funtion2)} - -% |color(brown) Counterpart of \define@keylist:|color(verbcolor) -\newkeylist{|fv(key type/id), |fv(key), |fv(key default value), - |fv(key macro/function); |fv(another set of key specifiers); etc}. -\end{macrocode} - -We could simply have redefined/modified the legacy key definition commands in the \sty{xkeyval} package 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 \sty{xkeyval} package and those packages may well have redefined identical keys. Moreover, the legacy key definition commands from the \sty{xkeyval} package may be needed to redefine a disabled key (see \secref{sec:disabling-keys}). - -All the commands of the type \fx{\new}\unskip xxx\fx{key} are robust and may be used in expansion contexts without fear of premature expansion, although expandable tokens in the definition must be protected.\footnote{We shall refer to keys of the type \fx{\new}\unskip xxx\fx{key} as those of category \fy{\newkey}, and keys of the type \fx{\define@}\unskip xxx\fx{key} as those of category \fy{\definekey}.} - -With the above macros, the following will flag an understandable error message, namely that the key \fn{keya} is about being redefined in the same family \fn{fam} and with the same prefix \fn{KV}: +\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 \aang{family} and with the same \aang{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 |LParen:the counterpart) +|comm(of \define@key from the xkeyval package|RParen::) +\newordkey[|cang(prefix)]{|cang(family)}{|cang(key)}[|cang(default)]{|cang(funtion)} + +|comm(Counterpart of \define@cmdkey:) +\newcmdkey[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(key)}[|cang(default)]% + {|cang(funtion)} + +|comm(Counterpart of \define@cmdkeys:) +\newcmdkeys[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(keys)}[|cang(default)] + +|comm(Counterparts of \define@boolkey:) +\newboolkey[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(key)}[|cang(default)]% + {|cang(funtion)} +\newboolkey|redplus[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(key)}[|cang(default)]% + {|cang(funtion1)}{|cang(funtion2)} + +|comm(Counterpart of \define@boolkeys:) +\newboolkeys[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(keys)}[|cang(default)] + +|comm(Counterpart of \define@biboolkeys:) +\newbiboolkeys[|cang(prefix)]{|cang(family)}[|cang(mp)] + {|cang(primary boolean)}[|cang(default value for primary boolean)] + {|cang(secondary boolean)}{|cang(func for primary boolean)} + {|cang(func for secondary boolean)} + +|comm(Counterpart of \define@uniboolkeys:) +\newuniboolkeys[|cang(prefix)]{|cang(family)}[|cang(mp)] + {|cang(primary boolean)}[|cang(default value for primary boolean)] + {|cang(secondary boolean)}{|cang(func for primary boolean)} + {|cang(func for secondary boolean)} + +|comm(Counterpart of \define@biuniboolkeys:) +\newbiuniboolkeys[|cang(prefix)]{|cang(family)}[|cang(mp)] + {|cang(primary boolean)}[|cang(default value for primary boolean)] + {|cang(secondary boolean)}{|cang(func for primary boolean)} + {|cang(func for secondary boolean)} + +|comm(Counterparts of \define@togkey:) +\newtogkey[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(key)}[|cang(default)]% + {|cang(funtion)} +\newtogkey|redplus[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(key)}[|cang(default)]% + {|cang(funtion1)}{|cang(funtion2)} + +|comm(Counterpart of \define@togkeys:) +\newtogkeys[|cang(prefix)]{|cang(family)}[|cang(mp)]{|cang(keys)}[|cang(default)] + +|comm(Counterpart of \define@bitogkeys:) +\newbitogkeys[|cang(prefix)]{|cang(family)}[|cang(mp)] + {|cang(primary toggle)}[|cang(default value for primary toggle)] + {|cang(secondary toggle)}{|cang(func for primary toggle)} + {|cang(func for secondary toggle)} + +|comm(Counterpart of \define@unitogkeys:) +\newunitogkeys[|cang(prefix)]{|cang(family)}[|cang(mp)] + {|cang(primary toggle)}[|cang(default value for primary toggle)] + {|cang(secondary toggle)}{|cang(func for primary toggle)} + {|cang(func for secondary toggle)} + +|comm(Counterpart of \define@biunitogkeys:) +\newbiunitogkeys[|cang(prefix)]{|cang(family)}[|cang(mp)] + {|cang(primary toggle)}[|cang(default value for primary toggle)] + {|cang(secondary toggle)}{|cang(func for primary toggle)} + {|cang(func for secondary toggle)} + +|comm(Counterparts of \define@choicekey:) +\newchoicekey[|cang(prefix)]{|cang(family)}{|cang(key)}[|cang(bin)]{|cang(alt)}% + [|cang(default)]{|cang(funtion)} +\newchoicekey|redstar[|cang(prefix)]{|cang(family)}{|cang(key)}[|cang(bin)]{|cang(alt)}% + [|cang(default)]{|cang(funtion)} +\newchoicekey|redplus[|cang(prefix)]{|cang(family)}{|cang(key)}[|cang(bin)]{|cang(alt)}% + [|cang(default)]{|cang(funtion1)}{|cang(funtion2)} +\newchoicekey|redstar|redplus[|cang(prefix)]{|cang(family)}{|cang(key)}[|cang(bin)]{|cang(alt)}% + [|cang(default)]{|cang(funtion1)}{|cang(funtion2)} + +|comm(Counterpart of \define@keylist:) +\newkeylist{|cang(key type/id), |cang(key), |cang(key default value), + |cang(key macro/function); |cang(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 \NewKey\footnote{We shall refer to keys of the type \NewKey as those of category \ccmdm{\newkey}, and keys of the type \DefineKey as those of category \ccmdm{\definekey}.} 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. + +With the above macros, the following will flag an understandable error message, namely that the key \aang{keya} is about being redefined in the same family \aang{fam} and with the same prefix \aang{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, reserving, suspending, restoring, and removing keys} -\label{sec:disabling-keys} + {Disabling, localizing, reserving, suspending, restoring, and removing keys} +\label{sec:disable-reserv-keys} -Besides macros for defining keys, the \sty{skeyval} package also introduces mechanisms for disabling, reserving, suspending, restoring, and completely removing existing 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} - -The \sty{skeyval} package has modified the definition of \fx{\disable@keys} from the \sty{xkeyval} package 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 \sty{xkeyval}package, except that the new command accepts key prefixes (instead of just one prefix) and key families (instead of just one family): -\begin{macrocode} -\disable@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}. -\end{macrocode} -Here \fn{prefixes}, \fn{families}, \fn{keys} are lists of comma-separated entries referring to the keys to be disabled. Each of the lists \fn{prefixes}, \fn{families}, \fn{keys} may contain nil, one or more elements. If any of the members in \fn{keys} can't be located in \fn{families} and within \fn{prefixes}, an informational (not error) message is logged in respect of this member. - -The legacy version of \fx{\disable@keys} (\ie, that of the \sty{xkeyval} package) is still available via the starred version: -\begin{macrocode} -\disable@keys|redstar[|fv(prefix)]{|fv(family)}{|fv(keys)}. -\end{macrocode} -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 \sty{xkeyval} package can only be used to disable keys with the same \fn{prefix} and from the same \fn{family}, but not across prefixes and families. - -Any attempt to subsequently set or use a disabled key will prompt the following error message. (The \sty{xkeyval} package 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 \fx{\SKV@disabledkey} should be retained. -\begin{macrocode} +\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[|cang(prefixes)]{|cang(families)}{|cang(keys)}. +\end{macro} +\acmdm*{\disable@keys} +Here \aang{prefixes}, \aang{families}, \aang{keys} are lists of comma-separated entries referring to the keys to be disabled. Each of the lists \aang{prefixes}, \aang{families}, \aang{keys} may contain nil, one or more elements. If any of the members in \aang{keys} can't be located in \aang{families} and with prefix in \aang{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[|cang(prefix)]{|cang(family)}{|cang(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 \aang{prefix} and from the same \aang{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{% - \@latex@error{% - Key |fv(key) with prefix |fv(prefix) in family |fv(family) - was disabled on input line |fv(lineno) + \PackageError{skeyval}{% + Key |cang(key) with prefix |cang(prefix) in family |cang(family) + was disabled on input line |cang(lineno) }{% - You can't set or reset |fv(key) at this + You can't set or reset |cang(key) at this late stage. Perhaps you're required to set it - earlier, in the document's preamble. + earlier, within a package or in the document's preamble. }% } -\end{macrocode} -If the user attempts to disable an undefined key, the \sty{xkeyval} package issues a fatal error; the \sty{skeyval} package, on the other hand, issues a warning in the transcript .log file, since the situation isn't fatal to the outcome. +\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 \fx{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 \ccmd{\definekey} category but not with commands in the \ccmd{\newkey} 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} -Disabled keys can be redefined with commands in the \fy{\definekey} category but not with commands in the \fy{\newkey} category, since a disabled key remains defined: only its macro has been replaced by an error message signifying the disabling of the key. +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}). -\textbf{Note:} Reserved and suspended keys can't be disabled, until they are unreserved or restored (see Sections~\ref{sec:reserve-keys} and~\ref{sec:suspend-keys}). +The syntax for localizing keys is exactly like that for disabling keys: +\begin{macro} +\localize@keys[|cang(prefixes)]{|cang(families)}{|cang(keys)}. +\end{macro} +\acmdm*{\localize@keys} +If any of the members of the set \aang{keys} is not found in any of the members of \aang{families} and with a prefix from \aang{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 \aang{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[|cang(prefixes)]{|cang(families)}{|cang(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 \ccmd{\definekey} category, but not with commands in the \ccmd{\newkey} category. \subsection{Reserving and unreserving keys} \label{sec:reserve-keys} -The \sty{xkeyval} package bars its users from defining new keys with \fx{XKV} as a prefix. The \sty{skeyval} package generalizes this concept via the following three developer macros: -\begin{macrocode} -\ReserveKeyPrefixNames{|fv(list)} -\end{macrocode} -This allows the package developer to bar the future use of names appearing in \fn{list} as key prefixes. The \fn{list}, whose members are comma-separated, can be populated by the package developer as required. - -\begin{macrocode} -\ReserveMacroPrefixNames{|fv(list)} -\end{macrocode} +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{|cang(list)} +\end{macro} +\acmdm*{\ReserveKeyPrefixNames} +This allows the package developer to bar the future use of names appearing in \aang{list} as key prefixes when defining, disabling, reserving and suspending keys; but not when setting keys. The \aang{list}, whose members are comma-separated, can be populated by the package developer as required. + +\begin{macro} +\ReserveMacroPrefixNames{|cang(list)} +\end{macro} +\acmdm*{\ReserveMacroPrefixNames} This has a similar functionality to \fx{\ReserveKeyPrefixNames}, but applies to macro prefixes instead of key prefixes. -\begin{macrocode} -\ReserveFamilyNames{|fv(list)} -\end{macrocode} -This applies to family names. +\begin{macro} +\ReserveFamilyNames{|cang(list)} +\end{macro} +\acmdm*{\ReserveFamilyNames} +This reserves family names \aang{list} and prevents further use of members of \aang{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. -\textbf{Note:} One potential difficulty with the use of these macros is the fact that keys already defined by packages the developer would want to use can't appear in these lists since the lists are scanned both when defining and setting keys. +\begin{macro} +\ReserveKeyPrefixNames|redstar{|cang(list)} +\ReserveMacroPrefixNames|redstar{|cang(list)} +\ReserveFamilyNames|redstar{|cang(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 \aang{list} in his own package, it may be necessary for him to use the starred versions. -In addition to the above three commands, the \sty{skeyval} package also introduces the following command: -\begin{macrocode} -\reserve@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}, -\end{macrocode} -where the lists \fn{prefixes}, \fn{families}, \fn{keys} can contain nil, one or more elements. Defined, reserved and suspended keys can't be reserved. +In addition to the above reservation commands, the \pkg{skeyval} also introduces the following command: +\begin{macro} +\reserve@keys[|cang(prefixes)]{|cang(families)}{|cang(keys)}, +\end{macro} +\acmdm*{\reserve@keys} +where the lists \aang{prefixes}, \aang{families}, \aang{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{macrocode} -\unreserve@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}, -\end{macrocode} -where, again, the lists \fn{prefixes}, \fn{families}, \fn{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 and ignore that key. Incidentally, defined keys and suspended keys can also be unreserved, which is equivalent to removing the keys (see \secref{sec:remove-keys}). +\begin{macro} +\unreserve@keys[|cang(prefixes)]{|cang(families)}{|cang(keys)}, +\end{macro} +\acmdm*{\unreserve@keys} +where, again, the lists \aang{prefixes}, \aang{families}, \aang{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} @@ -827,106 +1369,563 @@ where, again, the lists \fn{prefixes}, \fn{families}, \fn{keys} can contain nil, 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{macrocode} -\suspend@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}, -\end{macrocode} -where the lists \fn{prefixes}, \fn{families}, \fn{keys} can contain nil, one or more elements. +\begin{macro} +\suspend@keys[|cang(prefixes)]{|cang(families)}{|cang(keys)}, +\end{macro} +\acmdm*{\suspend@keys} +where the lists \aang{prefixes}, \aang{families}, \aang{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{macrocode} -\restore@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}. -\end{macrocode} +\begin{macro} +\restore@keys[|cang(prefixes)]{|cang(families)}{|cang(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 \sty{skeyval} package 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 \fx{\key@ifundefined} from the \sty{xkeyval} package and the macro \fx{\ifkeydefined} from the \sty{skeyval} package will both identify a removed key as undefined. The syntax for removing keys is: -\begin{macrocode} -\remove@keys[|fv(prefixes)]{|fv(families)}{|fv(keys)}. -\end{macrocode} +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[|cang(prefixes)]{|cang(families)}{|cang(keys)} +\end{macro} +\acmdm*{\remove@keys} + +Removed keys can't be restored but can be redefined with the commands in both the \ccmd{\newkey} and \ccmd{\definekey} 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[|cang(prefix)]{|cang(family)}{|cang(keys)} +\end{macro} +\acmdm*{\uservaluekeys} +where \aang{keys} is the list of keys with \aang{prefix} and in \aang{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 |LParen:no value supplied for `keya'|RParen:) +\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{|makemac(keya)})}[12pt]{\def\x{#1}} + +\define@togkey|redplus[KV]{fam}[mp@]{|makered(\guservalue{|makemac(toga)})}[true]% +{% + \iftog{mp@toga}{\def\x{#1}}{}% +}{% + \@latex@error{Value `#1' not valid}\@ehc +} +\end{example} +\acmd*{\newordkey,\define@togkey,\iftog} + +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{|makemac(keya)})]{\def\keyb{#1}} +\define@key{fam}{keyc}[|makered(\usevalue{|makemac(keyb)})]{\def\keyc{#1}} + +\setkeys{fam}{|makered(\savevalue{|makemac(keya)})=test} +\setkeys{fam}{|makered(\savevalue{|makemac(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{|makemac(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{|makemac(keyb)})} +\gsavekeys[KV]{fam}{keyc,keyd,|makered(\global{|makemac(keye)})}|label(mac:gsavekeys) + +\setkeys[KV]{fam}{|makered(\gsavevalue{|makemac(keyd)})=yyy,|label(mac:setkeyd) + keye=|makered(\usevalue{|makemac(keyd)})} +\end{example} -Removed keys can't be restored but can be redefined with the commands in both the \fy{\newkey} and \fy{\definekey} categories. +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{|makemac(keya)})}[xxx]{\def\x{*#1*}} + +\newordkey[KV]{fam}{|makered(\gsavevalue{|makemac(keyb)})}[zzz]{\def\x{=#1=}}|label(mac:pointers:a) + +\newtogkey|redplus[KV]{fam}[mp@]{|makered(\savevalue\uservalue{|makemac(toga)})}[true]% +{ + \iftog{mp@toga}{\def\x{#1}}{}% +}{% + \@latex@error{Value '#1' not valid}\@ehc +} + +\define@cmdkey[KV]{fam}[mp@]{|makered(\uservalue\savevalue{|makemac(keyc)})}% + [www]{\def\x{#1}} + +\newboolkey|redplus[KV]{fam}[mp@]{|makered(\gsavevalue\uservalue{|makemac(boola)})}% +[true]{% + \ifmp@boola\def\x{#1}\fi +}{% + \@latex@error{Value '#1' not valid}\@ehc +} + +\define@cmdkey[KV]{fam}[mp@]{|makered(\guservalue\savevalue{|makemac(keyd)})}% + [www]{\def\x{#1}} + +\newchoicekey|redstar|redplus[KV]{fam}{|makered(\guservalue\gsavevalue{|makemac(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{|makemac(keya)})} +\end{example} +\acmd*{\define@key,\define@cmdkey,\newchoicekey,\newordkey, +\newtogkey,\setkeys,\iftog} + +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 \fx{\setkeys} command of the \sty{xkeyval} package in two respects: firstly to accommodate the use of the \fx{\fif} and \fx{\ffi} macros of \secref{sec:dirty-trick}, 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: +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} -Here, the legacy \fx{\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 \fx{\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: there is perhaps no silver bullet in this regard! +\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 management, but it also -contains many commands for general use, 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. +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|cang(cs)|cang(parameters){|cang(replacement text)} +\newdef|redstar|cang(cs)|cang(parameters){|cang(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 \bang{cs} was previously defined, both \fx{\SKV@newdef} and \fx{\newdef} will issue an error. + +\macrosubsection{Defining robust commands} + +\begin{macro} +\SKV@robustdef|redstar|cang(cs)|cang(parameters){|cang(replacement text)} +\robustdef|redstar|cang(cs)|cang(parameters){|cang(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 \bang{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|cang(cs)|cang(parameters){|cang(replacement text)} +\providedef|redstar|cang(cs)|cang(parameters){|cang(replacement text)} +\SKV@providerobustdef|redstar|cang(cs)|cang(parameters){|cang(replacement text)} +\providerobustdef|redstar|cang(cs)|cang(parameters){|cang(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 \aang{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{|cang(cs)}[|cang(number of args)][|cang(default)]% + {|cang(replacement text)} +\end{macro} +This is explained in \cref{sec:toggle-booleans}. If \aang{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 ``provided'' commands} + +\begin{macro} +\TestProvidedCommand|cang(cs){|cang(true text)}{|cang(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 \aang{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 \fx{\TestProvidedCommand} whether or not the new definition is the one in effect. -\begin{macrocode} -\in@tog{|fv(subtoken)}{|fv(token)} -\end{macrocode} -This is similar to the \latex kernel's \sz{\in@}{subtoken}{token} which tests if \fn{subtoken} is in \fn{token}, but this time the returned boolean is the toggle switch \fn{in@} instead of the kernel's \fn{in@} switch which is used as \fx{\ifin@}. The toggle \fn{in@} can be used in the following way and in other manners that toggles can be employed: \begin{example} -\iftog{in@}{|fv(true)}{|fv(false)}. +\SKV@providerobustdef*\newcmd{\newcommand} + +\TestProvidedCommand\newcmd{% + \@latex@info{`\string\newcmd' is `\string\newcommand'}% +}{% + \@latex@error{`\string\newcmd' isn't % + `\string\newcommand'}\@ehd +} +\end{example} + +\macrosection{Declaring new unique variables collectively} + +New definable variables can be introduced in sets by the following commands. + +\begin{macro} +\NewIfs[|cang(optional prefix)]{|cang(boolean list)}[|cang(optional state)] +\end{macro} +\acmdm*{\NewIfs} +This provides, for each member of the comma-separated list \bang{boolean list}, a new native-boolean register if the register didn't already exist, otherwise an error is flagged. Each member of \bang{boolean list} is prefixed with \aang{prefix} upon definition. The optional \aang{state} can be either \fx{true} or \fx{false}. +\begin{example} +\NewIfs[bool]{a,b,c}[true] + |tto \newif\ifboola \newif\ifboolb \newif\ifboolc + \boolatrue \boolbtrue \boolctrue + +\NewIfs{boold} |tto \newif\ifboold +\end{example} +Notice that members of the list \bang{boolean list} don't have \fx{\if} in their names. + +\begin{macro} +\NewTogs[|cang(optional prefix)]{|cang(tog list)}[|cang(optional state)] +\end{macro} +\acmdm*{\NewTogs} +This provides a new toggle register for each member of the comma-separated list \bang{tog list} if the register didn't already exist, otherwise an error is flagged. Each member of \bang{tog list} is prefixed with \aang{prefix} upon definition. The optional \aang{state} can be either \fx{true} or \fx{false}. +\begin{example} +\NewTogs[tog]{a,b,c}[true] + |tto \newtog{toga} \newtog{togb} \newtog{togc} + \togtrue{toga} \togtrue{togb} \togtrue{togc} + +\NewTogs{togd} |tto \newtog{togd} +\end{example} + +\begin{macro} +\NewToks[|cang(optional prefix)]{|cang(toks list)} +\end{macro} +\acmdm*{\NewToks}\label{page:newtoks} +This provides a new token list register for each member of the comma-separated list \bang{toks list} if the register didn't already exist, otherwise an error is flagged. Each member of \bang{toks list} is prefixed with \aang{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[|cang(optional prefix)]{|cang(counter list)} +\end{macro} +\acmdm*{\NewCounts} +This provides a new counter register for each member of the comma-separated list \bang{counter list} if the register didn't already exist, otherwise an error is flagged. Each member of \bang{counter list} is prefixed with \aang{prefix} upon definition. + +\begin{macro} +\NewDimens[|cang(optional prefix)]{|cang(dimen list)} +\end{macro} +\acmdm*{\NewDimens} +This provides a new dimension register for each member of the comma-separated list \bang{dimen list} if the register didn't already exist, otherwise an error is flagged. Each member of \bang{dimen list} is prefixed with \aang{prefix} upon definition. + +\begin{macro} +\NewBoxes[|cang(optional prefix)]{|cang(box list)} +\end{macro} +\acmdm*{\NewBoxes} +This allocates a new box register for each member of the comma-separated list \bang{box list} if the box register didn't already exist, otherwise an error is flagged. Each member of \bang{box list} is prefixed with \aang{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[|cang(optional prefix)]{|cang(stream list)} +\end{macro} +\acmdm*{\NewWrites} +This allocates a new output stream for each member of the comma-separated list \bang{stream list} if the stream didn't already exist, otherwise an error is flagged. Each member of \bang{stream list} is prefixed with \aang{prefix} upon definition. +\begin{example} +\NewWrites[write]{a,b,c} + |tto \newwrite\writea \newwrite\writeb \newwrite\writec + +\NewWrites{writed} |tto \newwrite\writed +\end{example} + +All the macros \fx{\NewIfs}, \fx{\NewToks}, \fx{\NewCounts}, \fx{\NewDimens}, \fx{\NewBoxes}, and \fx{\NewWrites} are non-outer, unlike their primitive counterparts. + +\macrosection{Defining new names} + +\begin{macro} +\SKV@csdef|redplus{|cang(name)}{|cang(definition)} +\SKV@csgdef|redplus{|cang(name)}{|cang(definition)} +\SKV@csedef|redplus{|cang(name)}{|cang(definition)} +\SKV@csxdef|redplus{|cang(name)}{|cang(definition)} +\end{macro} +\acmdm*{\SKV@csdef,\SKV@csgdef,\SKV@csedef,\SKV@csxdef} +The unsigned variants of these turn \aang{name} into a control sequence in terms of \aang{definition} whether or not the control was already defined. No error or warning messages are issued. The plus (\RedPlus) variants turn \aang{name} into a control sequence if it wasn't already defined; if it is already defined, an error message is flagged. These derive from a concept based on that of \acmd{\newcommand}, but (i)~\relaxed\ commands are considered undefined in this regard, and (ii)~these commands retain the powerful machinery of plain \tex. + +\Note The \pkg{skeyval} contains other undocumented tools for defining new commands. + +\macrosection{Name use} + +\begin{macro} +\SKV@csuse{|cang(name)} +\end{macro} +\acmdm*{\SKV@csuse} +This is similar to \LaTeX's legacy \acmdm{\@nameuse} but returns \fx{\@empty} (instead of an error) if \aang{name} is undefined. This is due originally to \pkg{etoolbox}. + +\macrosection{\texttt{\@bs let} assignments} + +\begin{macro} +\SKV@newlet{|cang(cs1)}{|cang(cs2)} +\NewLet{|cang(cs1)}{|cang(cs2)} +\end{macro} +\acmdm*{\SKV@newlet,\NewLet} +These assign \aang{cs2} to \aang{cs1} if \aang{cs2} exists and if \aang{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{|cang(name)}{|cang(cs)} +\SKV@letcs{|cang(cs)}{|cang(name)} +\SKV@csletcs{|cang(name)}{|cang(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 \aang{cs} means a control sequence, and \aang{name} means a control sequence name. + +\begin{macro} +\SKV@cslet|redstar{|cang(name)}{|cang(cs)} +\SKV@letcs|redstar{|cang(cs)}{|cang(name)} +\SKV@csletcs|redstar{|cang(name)}{|cang(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{|cang(num)}{|cang(expression)} +\end{macro} +\acmdm{\SKV@numdef} defines \aang{num} from \aang{expression} using \etex's \acmd{\numexpr}. If \aang{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{|cang(dim)}{|cang(expression)} +\end{macro} +\acmdm{\SKV@dimdef} defines \aang{dim} from \aang{expression} using \etex's \acmd{\dimexpr}. If \aang{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|cang(cs){|cang(function)} +\end{macro} +\acmdm*{\SKV@ifdefinable} +\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 (\aang{cs} in the above example) is definable, the \fx{\@ifdefinable} macro begins executing \aang{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. + +\begin{macro} +\SKV@ifdefinable@n{|cang(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 \aang{function}, unlike the above \fx{\SKV@ifdefinable}. The aim of \fx{\SKV@ifdefinable@n} is simply to test the definability of instances/members of \aang{list}. +\begin{example} +\SKV@ifdefinable@n{ax,ay,az} \end{example} -The command \fx{\in@tog} is robust. -\begin{macrocode} -\in@tok{|fv(subtoken)}{|fv(token)} -\end{macrocode} -Sometimes you want to use the \latex kernel's \sz{\in@}{subtoken}{token} to test if \fn{subtoken} is in \fn{token} irrespective of their catcodes. The robust command \sz{\in@tok}{subtoken}{token} 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 \sz{\in@}{subtoken}{token}. - -\begin{macrocode} -\SKV@ifdefinable|fv(cs){|fv(function)} -\SKV@for@ifdefinable|fv(listcmd){|fv(function)} -\end{macrocode} -\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 (\fn{cs} in the above example) is definable, the \fx{\@ifdefinable} macro begins executing \fn{function} while still in the \fx{\if} \textellipsis \fx{\fi} conditional. The command \fx{\SKV@ifdefinable} seeks to avoid these problems. - -The macro \fx{\SKV@for@ifdefinable} accepts a comma-separated list \fn{listcmd} of control sequence names whose definability are to be tested. Both commands \fx{\SKV@ifdefinable} and \fx{\SKV@for@ifdefinable} are robust. - -\begin{macrocode} -\SKV@expandargs|fv(n)|fv(function)|fv(arg1)|fv(arg2)\SKV@nil -\end{macrocode} -\LaTeX's \fx{\@expandtwoargs} is often used as a utility macro to expand two arguments \fn{arg1} and \fn{arg2} in order to execute \fn{function}. The command \fx{\SKV@expandargs} accepts up to four expansion types, signified by \fn{n}, which runs from 0 to 3: -\begin{compactenum} -\item If \fn{n} is 0, then \fn{arg2} is empty and only \fn{arg1} will be expanded before \fn{function} is executed. -\item If \fn{n} is 1, then both \fn{arg1} and \fn{arg2} are nonempty but only \fn{arg2} will be expanded before \fn{function} is executed. -\item When \fn{n} is 2, then both \fn{arg1} and \fn{arg2} are nonempty and both will be expanded before \fn{function} is executed. This is equivalent to \LaTeX's \fx{\@expandtwoargs}. -\item If \fn{n} is 3, then both \fn{arg1} and \fn{arg2} are nonempty but only \fn{arg1} is expanded before \fn{function} is executed. -\item If \fn{n} isn't in the list \sx{0,1,2,3}, then an error message is flagged. -\end{compactenum} -Because \fn{arg2} is delimited, it can be empty. The command \fx{\SKV@expandargs} can be used to save \fx{\expandafter}'s, but it isn't an all-purpose macro: for example, the \fx{\edef} it uses may expand too deeply in some cases. Also, care should be exercised when the expanded argument (\fn{arg1} and/or \fn{arg2}) involve the \tex primitive \fx{\if}. +\begin{macro} +\SKV@ifnew|redstar|redplus[|cang(optional parser)]{|cang(list)} +\end{macro} +\acmdm*{\SKV@ifnew,\SKV@ifnew*,\SKV@ifnew*+} + +The macro \fx{\SKV@ifnew} is similar to, but more versatile, than the command \fx{\SKV@ifdefinable@n}. The star sign (\RedStar) in \fx{\SKV@ifnew} indicates that \aang{list} is available in a macro, say \fx{\mylist}; and the plus sign (\RedPlus) shows \fx{\SKV@ifnew} that members of \aang{list} (or \fx{\mylist}) are control sequence names, otherwise they are control sequences (see examples below). The default value of the optional \aang{parser} is ``,'' (comma). The macro \fx{\SKV@ifnew} doesn't execute any \aang{function}. Both \fx{\SKV@ifdefinable@n} and \fx{\SKV@ifnew} are robust. + +\begin{example} +\def\mylist{ax,ay,az} +\SKV@ifnew|redstar|redplus[,]\mylist +\SKV@ifnew|redstar|redplus\mylist +\SKV@ifnew|redplus{ax,ay,az} +\SKV@ifnew{\ax\ay\az} +\def\my@list{\ax\ay\az} +\SKV@ifnew|redstar\my@list +\def\my@@list{ax;ay;az} +\SKV@ifnew|redstar|redplus[;]\my@@list +\SKV@ifnew\ax |tto \SKV@ifnew|redplus{ax} |tto \SKV@ifdefinable@n{ax} +\end{example} + +\macrosection{Verifying the status of variables} + +\begin{macro} +\SKV@ifdef|cang(cs){|cang(true)}{|cang(false)} +\SKV@ifcsdef{|cang(name)}{|cang(true)}{|cang(false)} +\SKV@ifundef|cang(cs){|cang(true)}{|cang(false)} +\SKV@ifcsundef{|cang(name)}{|cang(true)}{|cang(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 \aang{cs} or control sequence name \aang{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. \relaxed\ macros are considered undefined by \emph{all} these commands. To test if a macro is \relaxed, use the following commands: + +\begin{macro} +\SKV@ifrelax|cang(cs){|cang(true)}{|cang(false)} +\SKV@ifcsrelax{|cang(name)}{|cang(true)}{|cang(false)} +\end{macro} +\acmdm*{\SKV@ifrelax,\SKV@ifcsrelax} + +\begin{macro} +\SKV@ifdefax|cang(cs){|cang(defined)}{|cang(relaxed)}{|cang(undefined)} +\SKV@ifcsdefax{|cang(name)}{|cang(defined)}{|cang(relaxed)}{|cang(undefined)} +\end{macro} +\acmdm*{\SKV@ifdefax,\SKV@ifcsdefax} +These test if \aang{cs} or \aang{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, \aang{undefined}) because \tex is dominated by two-valued logical tests. + +\macrosection{Undefining macros} + +\begin{macro} +\SKV@Undef|redstar|redplus|redask[|cang(optional parser)]{|cang(cs)} +\end{macro} +\acmdm*{\SKV@Undef,\SKV@Undef*,\SKV@Undef*+,\SKV@Undef*+?} +This undefines the macros or control sequence names in the list \aang{cs} (of nil, one or more elements) such that \tex will subsequently consider each element undefined. The star sign (\RedStar) indicates that \aang{cs} is given as a macro whose \emph{contents} are to be individually undefined, and the plus sign (\RedPlus) shows that \aang{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 \aang{cs}. Control sequence names are to be separated by the parser; control sequences shouldn't be separated. The default value of the \aang{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{|cang(cs)} |tto \SKV@Undef{|cang(cs)} +\SKV@gundef{|cang(cs)} |tto \SKV@Undef|redask{|cang(cs)} +\SKV@csundef{|cang(cs name)} |tto \SKV@Undef|redplus{|cang(cs)} +\SKV@csgundef{|cang(cs name)} |tto \SKV@Undef|redplus|redask{|cang(cs)} +\end{macro} +\acmdm*{\SKV@undef,\SKV@gundef,\SKV@csundef,\SKV@csgundef} + +\macrosection{Expansion control} + +\begin{macro} +\SKV@expox{|cang(cs)} +\end{macro} +\acmdm*{\SKV@expox} +This expands its argument \aang{cs} once and forbids further expansion. + +\begin{macro} +\SKV@expcsox{|cang(name)} +\end{macro} +\acmdm*{\SKV@expcsox} +This is similar to \fx{\SKV@expox} but accepts control sequence name \aang{name} instead of control sequence. + +\begin{macro} +\SKV@exptx{|cang(cs)} +\end{macro} +\acmdm*{\SKV@exptx} +This expands its argument \aang{cs} twice and forbids further expansion. + +\begin{macro} +\SKV@expcstx{|cang(name)} +\end{macro} +\acmdm*{\SKV@expcstx} +This is similar to \fx{\SKV@exptx} but accepts control sequence name \aang{name} instead of control sequence. + +\begin{macro} +\SKV@expargs|cang(n)|cang(function)|cang(arg1)|cang(arg2)\@nil +\end{macro} +\acmdm*{\SKV@expargs} +\LaTeX's \acmdm{\@expandtwoargs} is often used as a utility macro to expand two arguments \aang{arg1} and \aang{arg2} in order to execute \aang{function}. The command \fx{\SKV@expargs}, on the other hand, accepts up to four expansion types, signified by \aang{n}, which runs \mbox{from 0 to 3}: +\begin{enum} +\item If \aang{n} is 0, then \aang{arg2} is empty and only \aang{arg1} will be expanded before \aang{function} is executed. +\item If \aang{n} is 1, then both \aang{arg1} and \aang{arg2} are nonempty but only \aang{arg2} will be expanded before \aang{function} is executed. +\item When \aang{n} is 2, then both \aang{arg1} and \aang{arg2} are nonempty and both will be expanded before \aang{function} is executed. This is equivalent to \LaTeX's \fx{\@expandtwoargs}. +\item If \aang{n} is 3, then both \aang{arg1} and \aang{arg2} are nonempty but only \aang{arg1} is expanded before \aang{function} is executed. +\item If \aang{n} isn't in the list \sx{0,1,2,3}, then an error message is flagged. +\end{enum} +Because \aang{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 (\aang{arg1} and/or \aang{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@expandargs{0}{\def\tempc#1#2}{\def\noexpand##1{##2}}% - \SKV@nil +\SKV@expargs{0}{\def\tempc#1#2}{\def\noexpand##1{##2}}\@nil|label(mac:expargs) \tempc\tempa{aaa} \tempc\tempb{abcaaabbccbca} -\SKV@expandargs{2}\in@\tempa\tempb\SKV@nil +\SKV@expargs{2}\SKV@in@\tempa\tempb\@nil \show\ifin@ \end{example} -Compare these expressions with the chains of \fx{\expandafter}'s in \secref{sec:condit-in-macros}. +\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. -\begin{macrocode} -\SKV@checkchoice{|fv(keyvalue)}{|fv(altlist)}{|fv(true)}{|fv(false)} -\end{macrocode} -This is the expandable form of \sty{xkeyval} package's \fx{\XKV@checkchoice}. It checks if the user-submitted value \fn{keyvalue} of a \fn{key} is in the list \fn{altlist}. It executes \fn{true} if \fn{keyvalue} is found in \fn{altlist} and \fn{false} otherwise. Additionally, it returns \fx{\val} for the expanded value of \fn{keyvalue} and \fx{\nr} for the numerical order of \fx{\val} in the list \fn{altlist}. If \fn{keyvalue} isn't found in \fn{altlist}, then \fx{\nr} will return $-1$. If \fn{keyvalue} and \fn{altlist} are buried in macros, the macros are fully expanded before the search for \fn{keyvalue} in the list \fn{altlist} is effected. In that case, \fx{\val} will hold the expanded form of \fn{keyvalue} 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 \fn{altlist}. For example, \fn{altlist} may be the set \fx{{left,right,center}}, but given as a macro \fx{\altlist@}, while \fn{keyvalue} is given as \fx{\def\keyvalue@{center}}. Obviously, \fx{\keyvalue@} contains one of the elements of \fn{altlist}, but choice keys won't know this without the expansion of both \fx{\altlist@} and \fx{\keyvalue@}. This is \name{raison d'\^e tre} of the \fx{\SKV@checkchoice} macro. +\begin{macro} +\SKV@checkchoice{|cang(value)}{|cang(altlist)}{|cang(true)}{|cang(false)} +\end{macro} +\acmdm*{\SKV@checkchoice} +This is an enhanced form of \pkg{xkeyval}'s \fx{\XKV@checkchoice}. It checks if the user-submitted \aang{value} of a key (say, \aang{keya}) is in the list \aang{altlist}. It executes \aang{true} if \aang{value} is found in \aang{altlist} and \aang{false} otherwise. Additionally, it returns \acmd{\val} for the expanded value of \aang{value} and \acmd{\nr} for the numerical order of \acmd{\val} in the list \aang{altlist}. If \aang{value} isn't found in \aang{altlist}, then \acmd{\nr} will return $-1$. If \aang{value} and \aang{altlist} are buried in macros, the macros are fully expanded before the search for \aang{value} in the list \aang{altlist} is effected. In that case, \acmd{\val} will hold the expanded form of \aang{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 \aang{altlist}. For example, \aang{altlist} may be the set \fx{{left,right,center}}, but given as a macro \fx{\@altlist}, while \aang{value} is given as \fx{\def\@value{center}}. Obviously, \fx{\@value} contains one of the elements of \aang{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. An example follows: +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} +\def\@altlist{left,right,center} \newordkey[KV]{fam}{keya}[true]{% - \SKV@checkchoice{#1}{\altlist@}{% + \SKV@checkchoice{#1}{\@altlist}{% \ifcase\nr\relax \edef\tempa##1##2{##1===\val===##2}% \or @@ -938,194 +1937,187 @@ Moreover, \fx{\SKV@checkchoice} can be used in the definition of non-choice keys \@latex@error{Wrong value for `keya'}\@eha }% } -\def\keyvalue@{center} -\setkeys[KV]{fam}{keya=\keyvalue@} +\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}. -\begin{macrocode} -\requirecmd{|fv(cs)}[|fv(number of args)][|fv(default)]% - {|fv(replacement text)} -\end{macrocode} -This is explained in \secref{sec:toggle-switches}. If \fn{cs} is already defined, \fx{\requirecmd} checks if the new and old definitions are identical. If they aren't, a warning message is logged in the transcript file and the new definition is aborted. - -\begin{macrocode} -\SKV@for@a{|fv(list)}|fv(cmd){|fv(function)} -\SKV@for@b|fv(listcmd)|fv(cmd){|fv(function)} -\end{macrocode} -A fast for-loop adapted from the \sty{xkeyval} package to accept general list parsers. Elements of \fn{list} are stored in \fn{cmd}, and \fn{function} is executed for each element of \fn{list}. The \fn{list}, which is populated by comma-separated elements, is not expanded. This accepts a general list parser, dynamically declarable via -\begin{macrocode} -\SKV@CommandGenParser{|fv(parser)} |color(black) or |color(verbcolor) -\skvoptions{genparser=|fv(parser)}, -\end{macrocode} -instead of just one type of parser (``comma'' in the \sty{xkeyval} package). Also, this uses the more powerful \fx{\SKV@ifblank} to check whether or not \fn{list} is empty or blank. The command \fx{\SKV@for@a} is robust, but in expansion contexts, both \fn{cmd} and \fn{function} will need to be somehow protected. In the \fx{\SKV@for@b} command, \fn{listcmd} is expanded once before the iteration commences. One snag with \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 surprises, since a previous call to \fx{\SKV@CommandGenParser} might have set a parser that is no longer valid. - -\begin{macrocode} -\SKV@tfor@a|fv(cmd){|fv(list)}{|fv(function)} -\SKV@tfor@b|fv(cmd)|fv(listcmd){|fv(function)} -\end{macrocode} -The first of these (\ie, \fx{\SKV@tfor@a}) is equivalent to \latex kernel's \fx{\@tfor}, which loops over \fn{list} token-wise (character or control sequence token), but here we have removed the need for the usual delimitation tokens. Note that \fn{list} is not a comma-separated list! In \fx{\SKV@tfor@b}, \fn{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. - -\begin{macrocode} -\SKV@ifstrequal{|fv(token1)}{|fv(token2)}{|fv(true)}{|fv(false)} -\SKV@oifstrequal{|fv(token1)}{|fv(token2)}{|fv(true)}{|fv(false)} -\SKV@xifstrequal{|fv(token1)}{|fv(token2)}{|fv(true)}{|fv(false)} -\end{macrocode} -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 \fn{true} if \fn{token1} is equal (character code wise) to \fn{token2}, and \fn{false} otherwise. Both \fn{token1} and \fn{token2} are detokenized before the test. The macro \fx{\SKV@oifstrequal} is similar to \fx{\SKV@ifstrequal} but first expands its arguments (the two token lists \fn{token1} and \fn{token2}) once before the test. The macro \fx{\SKV@xifstrequal} first expands its arguments fully before the test. - -\begin{macrocode} -\SKV@ifblank{|fv(token)}{|fv(true)}{|fv(false)} -\SKV@oifblank{|fv(token)}{|fv(true)}{|fv(false)} -\SKV@xifblank{|fv(token)}{|fv(true)}{|fv(false)} -\end{macrocode} -These macros test if the argument is blank or not. The first of these is from \sty{ifmtarg} package. \fx{\SKV@oifblank} expands its argument once before the test, while \fx{\SKV@xifblank} expands its argument fully before the test. - -\begin{macrocode} -\SKV@ifstrempty{|fv(token)}{|fv(true)}{|fv(false)} -\SKV@oifstrempty{|fv(token)}{|fv(true)}{|fv(false)} -\SKV@xifstrempty{|fv(token)}{|fv(true)}{|fv(false)} -\end{macrocode} -These yield \fn{true} if \fn{token} is empty, and \fn{false} otherwise. In the macro \fx{\SKV@ifstrempty}, \fn{token} isn't expanded before the test; in the command \fx{\SKV@oifstrempty}, \fn{token} is expanded once before the test; in the command \fx{\SKV@xifstrempty}, \fn{token} is fully expanded before the test. - -\begin{macrocode} -\SKV@expandox{|fv(cs)} -\end{macrocode} -This expands its argument \fn{cs} once and forbids further expansion. - -\begin{macrocode} -\SKV@expandnameox{|fv(name)} -\end{macrocode} -This is similar to \fx{\SKV@expandox} but accepts control sequence name \fn{name} instead of control sequence. - -\begin{macrocode} -\SKV@expandtx{|fv(cs)} -\end{macrocode} -This expands its argument \fn{cs} twice and forbids further expansion. - -\begin{macrocode} -\SKV@expandnametx{|fv(name)} -\end{macrocode} -This is similar to \fx{\SKV@expandtx} but accepts control sequence name instead of control sequence. - -\begin{macrocode} -\@afterpackageloaded{|fv(package)}{|fv(code)} -\end{macrocode} -This executes \fn{code} only after the package \fn{package} has been loaded. This has been optimized from the \sty{afterpackage} package to avoid filling up the hash table with hooks that are \fx{relax}'ed or indeed undefined. - -\begin{macrocode} -\SKV@newlet{|fv(cs1)}{|fv(cs2)} -\end{macrocode} -This assigns \fn{cs2} to \fn{cs1} if \fn{cs2} exists and if \fn{cs1} isn't already defined, otherwise an error is flagged. - -\begin{macrocode} -\SKV@newtoks{|fv(toks)} -\end{macrocode} -This provides a new token register \fn{toks} if the register didn't already exist, otherwise an error is flagged. - -\begin{macrocode} -\SKV@newcount{|fv(counter)} -\end{macrocode} -This provides a new counter register \fn{counter} if the register didn't already exist, otherwise an error is flagged. - -\begin{macrocode} -\SKV@newdimen{|fv(dimen)} -\end{macrocode} -This provides a new dimension register \fn{dimen} if the register didn't already exist, otherwise an error is flagged. - -\begin{macrocode} -\SKV@numdef{|fv(num)}{|fv(expression)} -\SKV@numnamedef{|fv(num)}{|fv(expression)} -\SKV@numgdef{|fv(num)}{|fv(expression)} -\SKV@numnamegdef{|fv(num)}{|fv(expression)} -\end{macrocode} -\fx{\SKV@numdef} defines \fn{num} from \fn{expression} using \etex's \fx{\numexpr}. It is similar to \sty{etoolbox}'s \fx{\numdef} but is defined by a counter expression instead of \fx{\edef} (which \sty{etoolbox} uses). If \fn{num} is previously undefined, it is first initialized before the expression is built. The difference between \fx{\numdef} and \fx{\SKV@numdef} is that if you do \fx{\numdef\x{1+2+3}}, you can use \fx{\x} without, depending on context, prefixing it with \fx{\the} or \fx{\number}. \fx{\SKV@numdef}, on the other hand, will require \fx{\the} or \fx{\number}. Also, \fx{\SKV@numdef} includes two tests of its arguments. - -\fx{\SKV@numnamedef} is the same as \fx{\SKV@numdef} but takes a control sequence name instead of a control sequence. - -The macros \fx{\SKV@numgdef} and \fx{\SKV@numnamegdef}, unlike \fx{\SKV@numdef} and \fx{\SKV@numnamedef}, effect global assignments and thus can escape local groups. - -\begin{macrocode} -\SKV@dimdef{|fv(dimen)}{|fv(expression)} -\SKV@dimnamedef{|fv(dimen)}{|fv(expression)} -\SKV@dimgdef{|fv(dimen)}{|fv(expression)} -\SKV@dimnamegdef{|fv(dimen)}{|fv(expression)} -\end{macrocode} -\fx{\SKV@dimdef} defines \fn{dimen} from \fn{expression} using \etex's \fx{\dimexpr}. It is similar to \sty{etoolbox}'s \fx{\dimdef} but is defined by a dimension expression instead of \fx{\edef}. If \fn{dimen} is previously undefined, it is first initialized before the expression is built. The difference between \fx{\dimdef} and \fx{\SKV@dimdef} is that if you do \fx{\dimdef\x{1pt+2mm+3cm}}, you can use \fx{\x} without prefixing it with \fx{\the}. \fx{\SKV@dimdef}, on the other hand, will require \fx{\the}. - -The macros \fx{\SKV@dimgdef} and \fx{\SKV@dimnamegdef}, unlike \fx{\SKV@dimdef} and \fx{\SKV@dimnamedef}, effect global assignments. - -\begin{macrocode} -\SKV@newnamedef{|fv(name)}{|fv(definition)} -\SKV@newnamegdef{|fv(name)}{|fv(definition)} -\SKV@newnameedef{|fv(name)}{|fv(definition)} -\SKV@newnamexdef{|fv(name)}{|fv(definition)} -\end{macrocode} -These turn \fn{name} into a control sequence if it wasn't already defined. If it is already defined, an error message is flagged. These derive from a concept based on that of \fx{\newcommand}, but -\begin{inparaenum}[(i)] -\item \fx{\relax}\unskip 'ed commands are considered undefined in this regard, and -\item these commands retain the powerful machinery of plain \tex. -\end{inparaenum} - -\begin{macrocode} -\SKV@namedef{|fv(name)}{|fv(definition)} -\SKV@namegdef{|fv(name)}{|fv(definition)} -\SKV@nameedef{|fv(name)}{|fv(definition)} -\SKV@namexdef{|fv(name)}{|fv(definition)} -\end{macrocode} -These turn \fn{name} into a control sequence whether or not the control was already defined. No error or warning messages are issued. - -\begin{macrocode} -\nameletcs{|fv(name)}{|fv(cs)} -\csletname{|fv(cs)}{|fv(name)} -\nameletname{|fv(name)}{|fv(name)} -\end{macrocode} -These perform \fx{\let} assignments if the second argument is defined, otherwise an error message is flagged. \fn{cs} means a control sequence. - -\begin{macrocode} -\@nameletcs{|fv(name)}{|fv(cs)} -\@csletname{|fv(cs)}{|fv(name)} -\@nameletname{|fv(name)}{|fv(name)} -\end{macrocode} -These perform \fx{\let} assignments whether or not the second argument is defined. If the second argument is undefined, the hash table is not filled. - -\begin{macrocode} -\SKV@nameuse{|fv(name)} -\end{macrocode} -This is similar to \LaTeX's \fx{\@nameuse} but returns \fx{\@empty} if \fn{name} is undefined. The idea derives from the \sty{etoolbox} package. - -\begin{macrocode} -\SKV@ifdef{|fv(cs)}{|fv(true)}{|fv(false)} -\SKV@ifnamedef{|fv(name)}{|fv(true)}{|fv(false)} -\SKV@ifundef{|fv(cs)}{|fv(true)}{|fv(false)} -\SKV@ifnameundef{|fv(name)}{|fv(true)}{|fv(false)} -\end{macrocode} -These use \etex's facilities to test the existence of the control sequence \fn{cs} or \fn{name}. \fx{\relax}\unskip 'ed commands are considered undefined in this regard. These are based on similar concepts from the \sty{etoolbox} package. - -\begin{macrocode} -\SKV@findescape{|fv(arg)}{|fv(true)}{|fv(false)} -\end{macrocode} -This returns \fn{true} if \fn{arg} starts with the \fx{\escapechar}, and \fn{false} otherwise. The \fx{\escapechar} is locally made equal to 92 before the test. - -\begin{macrocode} -\SKV@undef{|fv(cs)} -\SKV@gundef{|fv(cs)} -\SKV@nameundef{|fv(name)} -\SKV@namegundef{|fv(name)} -\end{macrocode} -These undefine the macro \fn{cs} or control sequence name \fn{name} such that \tex will subsequently consider them undefined. The macros \fn{\SKV@gundef} and \fn{\SKV@namegundef} undefine their argument globally. - -\begin{macrocode} -\SKV@aftergroup{|fv(code)} -\SKV@aftergroup|redstar{|fv(code)} -\SKV@afterassignment{|fv(code)} -\SKV@afterassignment|redstar{|fv(code)} -\end{macrocode} -These execute the arbitrary \fn{code} after a group or assignment. The starred versions fully expand \fn{code} before the assignment (or before exiting the group). These are similar to \fx{\AfterGroup} and \fx{\AfterAssignment} of \sty{etextools} package but they don't accumulate the group and assignment counters indefinitely: the counters are initialized after each group or each assignment. +\macrosection{Testing for substring} + +\begin{macro} +\SKV@in@{|cang(substring)}{|cang(string)} +\end{macro} +\acmdm*{\SKV@in@} +This is similar to the \latex kernel's \sz{\in@}{substring}{string} which tests if \aang{substring} is in \aang{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} +\in@tog{|cang(substring)}{|cang(string)} +\end{macro} +\acmdm*{\in@tog} +In this case the returned boolean is the toggle switch \aang{in@} instead of the kernel's \aang{in@} switch which is used as \fx{\ifin@}. The toggle \aang{in@} can be used in the following way and in other manners that toggles can be employed: +\begin{example} +\iftog{in@}{|cang(true)}{|cang(false)}. +\end{example} +\acmd*{\iftog} +The command \fx{\in@tog} is robust. + +\begin{macro} +\in@tok{|cang(substring)}{|cang(string)} +\end{macro} +\acmdm*{\in@tok} +Sometimes you want to use the \latex kernel's \sz{\in@}{substring}{string} to test if \aang{substring} is in \aang{string} irrespective of their catcodes. The robust command \sz{\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 \sz{\in@}{substring}{string}. Actually, it calls \fx{\SKV@in@} to avoid false returns. + +\macrosection{Testing equality of strings} + +\begin{macro} +\SKV@ifstrequal{|cang(string1)}{|cang(string2)}{|cang(true)}{|cang(false)} +\SKV@ifstrnotequal{|cang(string1)}{|cang(string2)}{|cang(not true)}{|cang(not false)} +\SKV@oifstrequal{|cang(string1)}{|cang(string2)}{|cang(true)}{|cang(false)} +\SKV@xifstrequal{|cang(string1)}{|cang(string2)}{|cang(true)}{|cang(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 \aang{true} if \aang{string1} is equal (character code wise) to \aang{string2}, and \aang{false} otherwise. Both \aang{string1} and \aang{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 \aang{string1} and \aang{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{|cang(token)}{|cang(true)}{|cang(false)} +\SKV@ifnotempty{|cang(token)}{|cang(not true)}{|cang(not false)} +\SKV@oifempty{|cang(token)}{|cang(true)}{|cang(false)} +\SKV@xifempty{|cang(token)}{|cang(true)}{|cang(false)} +\end{macro} +\acmdm*{\SKV@ifempty,\SKV@ifnotempty,\SKV@oifempty,\SKV@xifempty} +These yield \aang{true} if \aang{token} is empty, and \aang{false} otherwise. In the command \fx{\SKV@ifempty}, \aang{token} isn't expanded before the test; in the command \fx{\SKV@oifempty}, \aang{token} is expanded once before the test; in the command \fx{\SKV@xifempty}, \aang{token} is fully expanded before the test. + +\begin{macro} +\SKV@ifblank{|cang(token)}{|cang(true)}{|cang(false)} +\SKV@ifnotblank{|cang(token)}{|cang(not true)}{|cang(not false)} +\SKV@oifblank{|cang(token)}{|cang(true)}{|cang(false)} +\SKV@xifblank{|cang(token)}{|cang(true)}{|cang(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{|cang(true)}{|cang(false)} +\SKV@ifnotdraft{|cang(not true)}{|cang(not false)} +\SKV@iffinal{|cang(true)}{|cang(false)} +\SKV@ifnotfinal{|cang(not true)}{|cang(not false)} +\iftog{draft}{|cang(true)}{|cang(false)} +\ifnottog{draft}{|cang(not true)}{|cang(not false)} +\iftog{final}{|cang(true)}{|cang(false)} +\ifnottog{final}{|cang(not true)}{|cang(not false)} +\end{macro} +\acmdm*{\SKV@ifdraft,\SKV@ifnotdraft,\SKV@iffinal,\SKV@ifnotfinal,\iftog\{draft\}, +\ifnottog\{draft\},\iftog\{final\},\ifnottog\{final\}} + +These execute \aang{true} or \aang{false} depending on whether \fx{draft} or \fx{final} appears as \fx{true} in the options list of \acmd{\documentclass} or \sxx{\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{|cang(true)}{|cang(false)} +\ifnotdraft{|cang(not true)}{|cang(not false)} +\iffinal{|cang(true)}{|cang(false)} +\ifnotfinal{|cang(not true)}{|cang(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 \fx{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{|cang(true)}{|cang(false)} +\SKV@ifnotpdf{|cang(not true)}{|cang(not false)} +\iftog{pdf}{|cang(true)}{|cang(false)} +\ifnottog{pdf}{|cang(not true)}{|cang(not false)} +\end{macro} +\acmdm*{\SKV@ifpdf,\SKV@ifnotpdf,\iftog\{pdf\},\ifnottog\{pdf\}} +These execute \aang{true} or \aang{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{|cang(true)}{|cang(false)} +\ifnotpdf{|cang(not true)}{|cang(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} that you are using. + +\macrosection{Tests related to package loading} + +\begin{macro} +\@ifpackagecurrent{|cang(package)}{|cang(date)}{|cang(true)}{|cang(false)} +\@ifpackagenotcurrent{|cang(package)}{|cang(date)}{|cang(not true)}{|cang(not false)} +\end{macro} +\acmdm*{\@ifpackagecurrent,\@ifpackagenotcurrent} +These executes \aang{true} if the date of the current/loaded version \aang{package} is greater than or equal to \aang{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{|cang(package)}{|cang(code)} +\end{macro} +\acmdm*{\@afterpackageloaded} +This executes \aang{code} only after \aang{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 \aang{package} was not eventually loaded. If at the start of document, \aang{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{|cang(packages)} +\end{macro} +\acmdm*{\@ensurepackageloaded} +This will issue an error at start of document if any member of the comma-separated list \aang{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{|cang(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 \aang{list} of commands at once and gives precise error messages related to the incorrectly located commands. The \aang{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{|cang(code)} +\SKV@aftergroup|redstar{|cang(code)} +\SKV@afterassignment{|cang(code)} +\SKV@afterassignment|redstar{|cang(code)} +\end{macro} +\acmdm*{\SKV@aftergroup,\SKV@aftergroup*,\SKV@afterassignment,\SKV@afterassignment*} + +\tex's \fx{\aftergroup} and \fx{\afterassignment} don't accept arbitrary code. These commands execute the arbitrary \aang{code} after a group or assignment. The starred variants expand \aang{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} -\def\aa{aaa}\def\bb{bbb}\def\xx{xxx}\def\yy{yyy} +\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}% @@ -1134,97 +2126,297 @@ Some examples follow: \SKV@aftergroup{\par\yy+++\xx}% \endgroup \endgroup +|makered(\end{document}) -\let\gobblex\@firstofone -\def\protected@funnydef{% - \let\@@protect\protect - \let\protect\@unexpandable@protect - \SKV@afterassignment{\restore@protect\let\gobblex\@gobble}% - \edef -} \end{example} -\begin{macrocode} -\SKV@apptomacro@a|fv(cs)|fv(content) -\SKV@apptomacro@b|fv(cs)|fv(content) -\SKV@gapptomacro@a|fv(cs)|fv(content) -\SKV@gapptomacro@b|fv(cs)|fv(content) -\end{macrocode} -This appends \fn{content} to \fn{cs}. If \fn{cs} was previously undefined, it is initialized with \fn{content}. \fx{\SKV@apptomacro@a} doesn't expand \fn{content} before appending it to \fn{cs}, while \fx{\SKV@apptomacro@b} expands \fn{content} once before appending it's contents to \fn{cs}. -The macros \fx{\SKV@gapptomacro@a} and \fx{\SKV@gapptomacro@b} have global effect, which can escape local groups. Except for the initialization of undefined \fn{cs}, \fx{\SKV@gapptomacro@a} is equivalent to \latex's \fx{\g@addto@macro}. - -\begin{macrocode} -\SKV@preptomacro@a|fv(cs)|fv(content) -\SKV@preptomacro@b|fv(cs)|fv(content) -\SKV@gpreptomacro@a|fv(cs)|fv(content) -\SKV@gpreptomacro@b|fv(cs)|fv(content) -\end{macrocode} -These perpend \fn{content} to \fn{cs}. If \fn{cs} was previously undefined, it is initialized with \fn{content}. \fx{\SKV@preptomacro@a} doesn't expand \fn{content} before prepending it to \fn{cs}, while \fx{\SKV@preptomacro@b} expands \fn{content} once before prepending it's contents to \fn{cs}. The macros \fx{\SKV@gapptomacro@a} and \fx{\SKV@gapptomacro@b} have global effect. - -\begin{macrocode} -\InputFileOnce[|fv(path)]{|fv(filename)} -\end{macrocode} -This inputs \fn{filename} on \fn{path} but only once. The argument \fn{path} is optional and its default value is the current/document's directory. If \fn{filename} had previously been read, an error message is flagged and the input is aborted. If \fn{filename} doesn't exist on \fn{path}, an opportunity is given to the user to type in the correct file name on the screen, or continue with the \latex pass without inputting the file. If the user wants to input \fn{filename} more than once in one document, then he should set \fx{\SKV@inputonce} to \fn{false} before the call to \fx{\InputFileOnce}, either by simply issuing \fx{\SKV@inputoncefalse} or via \fx{\skvoptions}: -\begin{example} -\skvoptions{inputonce=false}. -\end{example} -\fx{\SKV@inputonce} can, of course, be toggled between \fn{false} and \fn{true}. - -\begin{macrocode} -\AtStartOfDocument{|fv(code)} -\end{macrocode} -This is the expansion-context version of the hook \fx{\AtBeginDocument}. Sometimes you want to do something like -\begin{macrocode} -\edef\tempa{\AtBeginDocument{% - \def\noexpand\tempb{come with me}}}, -\end{macrocode} -which is impossible without a \fx{\noexpand} before \fx{\AtBeginDocument}. With \fx{\AtStartOfDocument} the protection is not necessary. - -Two more expansion-context document hooks are provided below: -\begin{macrocode} -\BeforeStartOfDocument{|fv(code)} -\AfterStartOfDocument{|fv(code)}. -\end{macrocode} -These mimic the \fx{\AtEndPreamble} and \fx{\AfterEndPreamble} hooks from the \sty{etoolbox} package. +\macrosection{List processing} + +\begin{macro} +\SKV@for@a{|cang(list)}|cang(cmd){|cang(function)} +\SKV@for@b|cang(listcmd)|cang(cmd){|cang(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 \aang{list} are stored in \aang{cmd}, and \aang{function} is executed for each element of \aang{list}. The \aang{list}, which is populated by parser-separated elements, is not expanded before the iteration, but \aang{listcmd} is expanded once before the commencement of the loop. The list parser is dynamically declarable via +\begin{macro} +\SKV@CommandGenParser{|cang(parser)} |orr +\skvoptions{genparser=|cang(parser)}, +\end{macro} +\acmdm*{\SKV@CommandGenParser} +Also, these iteration macros use the more powerful \acmd{\SKV@ifblank} to check whether or not \aang{list} is empty or blank. The commands \fx{\SKV@for@a} and \fx{\SKV@for@b} are robust, but in expansion contexts, both \aang{cmd} and \aang{function} will need to be protected. In the \fx{\SKV@for@b} command, \aang{listcmd} is expanded once before the iteration commences. The \aang{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[|cang(parser)]{|cang(list)}|cang(cmd){|cang(function)} +\SKV@for|redstar[|cang(parser)]|cang(listcmd)|cang(cmd){|cang(function)} +\end{macro} +\acmdm*{\SKV@for,\SKV@for*} +The \aang{parser} appears as an optional argument in these commands and its default value is ``\fx{,}'' (comma). These commands allow the user to provide the \aang{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 \aang{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 \aang{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 \aang{parser} is provided, resets the \aang{parser}. + +The list parser itself is available in \acmd{\parser}, which can be used in \aang{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}. -\section{Version history} +\begin{macro} +\SKV@tfor@a{|cang(list)}|cang(cmd){|cang(function)} +\SKV@tfor@b|cang(listcmd)|cang(cmd){|cang(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 \aang{list} token-wise (character or control sequence token), but these two macros have been prompted by the following rationale. Note that \aang{list} is not a comma-separated list! In \fx{\SKV@tfor@b}, \aang{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. -This package was called the \sty{keyreader} package until version~0.5, when the name became a misnomer. - -\setdefaultleftmargins{0em}{3.0em}{1.87em}{1.7em}{1em}{1em} -\begin{compactenum} -\item Version 0.1 [01/01/2010] - \begin{compactenum} - \item Provided machinery for reading multiple keys of all kinds from just one command. - \item Introduced complementary boolean keys. - \end{compactenum} - -\item Version 0.2 [10/01/2010] - \begin{compactenum} - \item Corrected a bug. - \end{compactenum} - -\item Version 0.3 [20/01/2010] - \begin{compactenum} - \item Introduced toggles and toggle keys. - \end{compactenum} - -\item Version 0.4 [01/02/2010] - \begin{compactenum} - \item Introduced complementary toggle keys. - \end{compactenum} - -\item Version 0.5 [23/02/2010] - \begin{compactenum} - \item Provided facilities for avoiding repeated definition of same key (when desired). - \item Provided mechanisms for disabling, reserving, unreserving, suspending, restoring, and removing keys after they have been defined. - \item Redefined a few of \sty{xkeyval} package's macros. - \item Included some developer macros. - \end{compactenum} -\end{compactenum} -\restoredefaultleftmargins +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 \aang{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 \aang{function} (or sanitized in the \aang{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 \aang{list} comes before \aang{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{|cang(list)}|cang(cmd){|cang(function)} +\SKV@tfor|redstar|cang(listcmd)|cang(cmd){|cang(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|cang(cs){|cang(content)} +\end{macro} +\acmdm*{\SKV@appto,\SKV@appto*,\SKV@appto*+,\SKV@appto*+?} +This appends \aang{content} to \aang{cs}. If \aang{cs} was previously undefined, it is initialized with \aang{content}. The star (\RedStar) sign directs \fx{\SKV@appto} to expand \aang{content} once before appending \aang{content} to \aang{cs}. The plus (\RedPlus) sign means that \aang{cs} is a control sequence name instead of a control sequence, while the question mark (\RedAsk) instructs \fx{\SKV@appto} to append \aang{content} to \aang{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 \aang{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|cang(cs){|cang(content)} + |tto \SKV@appto|cang(cs){|cang(content)} +\gapptomac|cang(cs){|cang(content)} + |tto \SKV@appto|redask|cang(cs){|cang(content)} +\csapptomac{|cang(name)}{|cang(content)} + |tto \SKV@appto|redplus{|cang(name)}{|cang(content)} +\csgapptomac{|cang(name)}{|cang(content)} + |tto \SKV@appto|redplus|redask{|cang(name)}{|cang(content)} +\end{macro} +\acmdm*{\apptomac,\gapptomac,\csapptomac,\csgapptomac} + +\bigskip +\begin{macro} +\SKV@prepto|redstar|redplus|redask|cang(cs){|cang(content)} +\end{macro} +\acmdm*{\SKV@prepto,\SKV@prepto*,\SKV@prepto*+,\SKV@prepto*+?} +This prepends \aang{content} to \aang{cs}. If \aang{cs} was previously undefined, it is initialized with \aang{content}. The star (\RedStar) sign directs \fx{\SKV@prepto} to expand \aang{content} once before prepending it to \aang{cs}. The plus (\RedPlus) sign means that \aang{cs} is a control sequence name instead of a control sequence, while the question mark (\RedAsk) instructs \fx{\SKV@prepto} to prepend \aang{content} to \aang{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|cang(cs){|cang(content)} + |tto \SKV@prepto|cang(cs){|cang(content)} +\gpreptomac|cang(cs){|cang(content)} + |tto \SKV@prepto|redask|cang(cs){|cang(content)} +\cspreptomac{|cang(name)}{|cang(content)} + |tto \SKV@prepto|redplus{|cang(name)}{|cang(content)} +\csgpreptomac{|cang(name)}{|cang(content)} + |tto \SKV@prepto|redplus|redask{|cang(name)}{|cang(content)} +\end{macro} +\acmdm*{\preptomac,\gpreptomac,\cspreptomac,\csgpreptomac} + +\bigskip +\begin{macro} +\SKV@addtolist|redplus|redask[|cang(parser)]|cang(csa)|cang(csb) +\end{macro} +\acmdm*{\SKV@addtolist,\SKV@addtolist+,\SKV@addtolist+?} +This adds the contents of the macro \aang{csb} to the list in the container \aang{csa}. The plus sign~(\RedPlus) means that \aang{csa} is a control sequence name, and the question mark~(\RedAsk) directs \fx{\SKV@addtolist} to add the contents of \aang{csb} to \aang{csa} globally (to escape local groups). The optional argument \aang{parser} is the list parser, ie, the separator of the instances in \aang{csa}. Its default value is ``,'' (comma). + +\macrosubsection{Package and document hooks} + +\begin{macro} +\SKV@AtPackageEnd{|cang(code)} +\SKV@AtClassEnd{|cang(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{|cang(code)} |label(befpkgend) +\SKV@BeforeClassEnd{|cang(code)} |label(befclsend) +\SKV@AfterPackageEnd{|cang(code)} +\SKV@AfterClassEnd{|cang(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{|cang(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{|cang(code)}|label(beforedocstart) +\SKV@AfterDocumentStart{|cang(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{|cang(code)} +\SKV@BeforeLastPage{|cang(code)} +\SKV@AfterLastPage{|cang(code)} +\SKV@AfterDocumentEnd{|cang(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 \aang{code} after the \acmd{\@enddocumenthook} but before the last \acmd{\clearpage}, and thus before the last shipout. The command \fx{\SKV@AfterLastPage} executes \aang{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 \aang{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[|cang(path)]{|cang(file)} +\InputFileOnce|redstar[|cang(path)]{|cang(file)} +\end{macro} +\acmdm*{\InputFileOnce} +The unstarred variant of this command inputs \aang{file} on \aang{path} but only once in one \latex pass. The argument \aang{path} is optional and its default value is the current/document's environment/directory. If \aang{file} had previously been read, a warning message is entered in the transcript log file (if the package option \fx{verbose} is selected) and the input is aborted. If \aang{file} doesn't exist on \aang{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 \aang{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}\xecref + \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:multiplekeys} +\end{version} + + \begin{version}{0.2}{2010/01/10} + \item Fixed a bug and optimized the \acmd{\define@keylist} loop \secref{sec:multiplekeys} + \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}\xecref + \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 + + \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, 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} are nested in a class file, gives non-empty \acmdm{\@unusedoptionlist} even if all the options of \acmd{\documentclass} have been used \xecref + \end{version} + +\end{versionhist} + +\IndexPreamble{Index numbers refer to page numbers.} +\IndexPreambleAlign{\centering} +\IndexColumns\tw@ +\printindex \end{document} %%% End of file skeyval-guide.tex %%%
\ No newline at end of file |