\documentclass{article}
\usepackage[scaled=0.9]{helvet}
\usepackage{lipsum,parskip,xspace}
\usepackage{fancyvrb}
\usepackage{xcolor}
\usepackage{multicol}
\usepackage{hyperref}
\usepackage[parser=;,macroprefix=mp@,keyprefix=KV,
  keyfamily=myfamily]{keyreader}
\makeatletter
\newcommand*\email[1]{\href{mailto:#1}{#1}}
\skip\footins20pt\relax
\xglobal\definecolorset{rgb}{x}{1}{green,0.00,0.59,0.00;%
  teal,0.00,0.82,0.82;magenta,0.50,0.00,1.00;purple,0.50,0.00,0.25}
\def\eg{\kr@ifnextchar.{e.g}{e.g.}\xspace}
\def\ie{\kr@ifnextchar.{i.e}{i.e.}\xspace}
\def\etc{\kr@ifnextchar.{etc}{etc.}\xspace}
\date{\textcolor{purple}{\today}\vadjust{\kern0ex}}
\newcommand*\krsty[1]{\textcolor{xgreen1}{\texttt{#1}}\xspace}
\newcommand*\krcmd[1]{\textcolor{xteal1}{\texttt{\@backslashchar#1}}\xspace}
\hypersetup{colorlinks=true,linkcolor=red,pdfpagemode=UseThumbs,
  implicit=true,breaklinks=true,pagebackref=true,backref=true,
  bookmarks=true,bookmarksnumbered=true,hyperfootnotes=true,debug=true,
  naturalnames=false,citecolor=purple,pdfview=FitH,pdfstartview=FitH}
\def\krverblabel{\textcolor{green}{\fboxrule1pt\fcolorbox{red}{gray!45}{\hspace{1cm}}}}
\CustomVerbatimEnvironment{krverbatim}{Verbatim}{numbers=left,
  label={\krverblabel},labelposition=topline,numberblanklines=false, firstnumber=last,frame=single,rulecolor=\color{xmagenta1},framerule=1pt,
  framesep=7pt,formatcom=\color{blue},xrightmargin=0pc,commandchars=\|\(\),
  commentchar=&}

\begin{document}
\DefineShortVerb{\+}
\title{The \texttt{\color{blue}keyreader} Package\footnote{Version 0.2.}}
\author{Ahmed Musa\\\email{a.musa@rocketmail.com}}
\maketitle
\thispagestyle{empty}

\leavevmode\textcolor{blue}{\rule[0ex]{\hsize}{2pt}}
\columnseprule0.5pt\premulticols2cm\relax
\begin{multicols}{2}
  \small\tableofcontents\normalsize
\end{multicols}
\removelastskip
\leavevmode\textcolor{blue}{\rule[0ex]{\hsize}{2pt}}

\section{Motivation}

The elaborate and powerful \krsty{xkeyval} package provides \krcmd{define@cmdkeys} and \krcmd{define@boolkeys} for defining and setting 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 minimizes tokens, as hundreds of keys can, in principle, be issued simultaneously by one command.

Also, the \krsty{xkeyval} package doesn't have the notion of complementary keys, which can be handy 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.

\section{Usage}

The package can be loaded in style and class files by
\begin{krverbatim}
\RequirePackage[options]{keyreader}
\end{krverbatim}
and in document files via
\begin{krverbatim}
\usepackage[options]{keyreader}
\end{krverbatim}
where the options and their default values are
\begin{krverbatim}
parser=;, macroprefix=mp@, keyprefix=KV, keyfamily=myfamily,
xchoicelist=false.
\end{krverbatim}
The \krsty{parser} is the separator between the keys in the key list to be defined in one go (see examples in section~\ref{sec:examples}). All these options can be set dynamically by using the \krcmd{krsetup} macro:
\begin{krverbatim}
\krsetup{parser=;, macroprefix=mp@, keyprefix=KV,
  keyfamily=myfamily, xchoicelist=false}.
\end{krverbatim}

The main user interface is the \krcmd{define@keylist} macro, whose syntax is
\begin{krverbatim}
\define@keylist{<key type/id>, <key>, <key value>,
  <key macro/function>; <another set of key specifiers>; etc}
\end{krverbatim}

There are four key types: 1 (ordinary key), 2 (command key), 3 (boolean key),
4 (choice key). The key and its attributes are separated by commas; they constitute one \krsty{object}. The objects are separated by the \krsty{parser}, which is the semicolon in the above example.

If the key list is available in a macro, say,
\begin{krverbatim}
\def\keylist{<key type/id>, <key>, <key value>,
  <key macro/function>; <another set of key specifiers>; etc},
\end{krverbatim}
then the keys can be defined by the starred form of \krcmd{define@keylist}:
\begin{krverbatim}
\define@keylist*\keylist.
\end{krverbatim}
\krcmd{define@keylist*} takes a macro as argument, while \krcmd{define@keylist} accepts a key list.

The \krcmd{ChoiceKeyValues} macro is needed for 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{krverbatim}
\ChoiceKeyValues{<key>}{<admissible key values>}.
\end{krverbatim}
To save tokens, the abbreviation \krcmd{CKVS} is provided for \krcmd{ChoiceKeyValues} and may be used in place of \krcmd{ChoiceKeyValues}.

It has to be defined each time a choice key is being defined. For example, if we want to define two choice keys \krsty{align} and \krsty{election}, then before the call to \krcmd{define@keylist}, we have to set
\begin{krverbatim}
\CKVS{align}{center,right,left,justified}
\CKVS{election}{state,federal,congress,senate}.
\end{krverbatim}
It doesn't matter which choice key first gets a \krcmd{CKVS}. The prevailing key family, obtainable from  \krcmd{kr@keyfamily}, is used internally by \krcmd{ChoiceKeyValues} to build distinct alternate values lists for choice keys. Unless the key family changes, you can't set two \krcmd{ChoiceKeyValues} for the same choice key. This will be possible only if the package option \krsty{xchoicelist} (meaning ``allow overwriting of choice list'') has been set \krsty{true}, either through \krcmd{documentclass}, \krcmd{usepackage}, or \krcmd{krsetup}.

As mentioned earlier, the key family (and other package options) can be changed via
\begin{krverbatim}
\krsetup{parser=;,macroprefix=mp@,keyprefix=KV,
  keyfamily=myfamily,xchoicelist=false}.
\end{krverbatim}

Thus any number of choice keys can appear in one \krcmd{define@keylist} statement if their lists of alternate/admissible values have been set by \krcmd{CKVS}.

In line with the philosophy of the \krsty{xkeyval} package, all the choice keys to be defined using this package require \krcmd{ChoiceKeyValues}: choice keys by definition have pre-ordained or acceptable values.

\section{Examples}
\label{sec:examples}

Suppose we wish to define a set of keys \krsty{\{color,angle,scale,align\}}. The keys \krsty{color}, \krsty{angle} and \krsty{scale} will de defined using command keys, while the key \krsty{align} will be defined by choice keys. Assume that the \krsty{align} key can only assume the values \krsty{\{center,right,left,justified\}}, where the first three values would further imply \krcmd{centering}, \krcmd{flushright}, and \krcmd{flushleft}, respectively. Moreover, we assume that the key \krsty{scale} will be associated with a macro called \krcmd{mydo}, where \krcmd{do} is assumed defined elsewhere. The keys \krsty{color} and \krsty{angle} aren't associated with macros. Then we can go:
\begin{krverbatim}
\CKVS{align}{center,right,left,justified}

\def\f@align{%
  \ifcase\nr\relax
    \def\kr@align{\centering}%
  \or
    \def\kr@align{\flushright}%
  \or
    \def\kr@align{\flushleft}%
  \or
    \let\kr@align\relax
  \fi
}

\define@keylist{2,color,gray!25,;2,angle,45,;
  2,scale,1,\def\mydo##1{\do ##1};4,align,center,\f@align;
  |color(red)\stopread|color(blue);3,mybool,true,}.
\end{krverbatim}
The \krcmd{nr} macro is a bin parameter defined by the keyreader package in accordance with the instructions in the \krsty{xkeyval} guide. It refreshes with the choice key. See the \krsty{xkeyval} guide for further details.

Instead of defining the macro \krcmd{f@align} before hand, we can submit its replacement text directly to the macro \krcmd{define@keylist}, but, because \krcmd{f@align} contains a conditional, some care is needed in doing so (see section~\ref{sec:conditionals}). Once the key \krsty{align} has been defined, the macro \krcmd{f@align} can be reused---perhaps to define other keys---even before the key \krsty{align} is set. This is because it isn't \krcmd{f@align} that is used in defining the key \krsty{align} but its ``meaning'' (\ie, the meaning of \krcmd{f@align}). In this way, the user can economize on tokens. The same applies to all the macros that may be used in defining keys.

Note the \krcmd{stopread} command inserted above. Because of it, the key \krsty{mybool} will not be read and defined; the rest (\ie, \krsty{color}, \krsty{angle}, \krsty{scale} and \krsty{align}) will be read and defined. All the entries for \krsty{mybool} will instead be saved in the macro \krcmd{kr@remainder}.

Hundreds of keys can be defined efficiently in this way, using very few tokens.

As another example, we consider the following page setup keys:
\begin{krverbatim}
\CKVS{align}{center,right,left,justified}
\CKVS{election}{state,federal,congress,senate}
% |color(gray)need to be defined only once|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,;
  4,align,center,\f@align;
  4,election,congress,;
  2,testdim,2cm,\long\def\f@testdim##1{A test dimension ##1
    \par\bigskip}%
}
\end{krverbatim}
which have the following trivial key macros:
\begin{krverbatim}
\def\f@textwidth{\AtBeginDocument{\wlog{`textwidth' %
  is \mp@textwidth}}}

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

\def\f@paperwidth{\wlog{`paperwidth' was defined as %
  ordinary key.}}
\newcommand\f@align{%
  \ifcase\nr\relax
    \def\mp@align{\centering}%
  \or
    \def\mp@align{\flushright}%
  \or
    \def\mp@align{\flushleft}%
  \or
    \let\mp@align\relax
  \fi
}
\end{krverbatim}
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 \krcmd{define@keylist}:
\begin{krverbatim}
\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,align,center,\f@align;
  4,election,congress,;
  2,testdim,2cm,\long\def\f@testdim####1%
    {Do something with ####1}%
    % |color(gray) Note the number of parameter characters here.
}
\define@keylist*\keylist.
\end{krverbatim}

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

The macro \krcmd{mp@align} holds the value \krcmd{flushright}, while
\begin{krverbatim}
\KV@myfamily@testdim
\end{krverbatim}
holds the macros:
\begin{krverbatim}
\def\mp@testdim{#1}
\long\def\f@testdim##1{A test dimension##1\par\bigskip},
\end{krverbatim}
where \krsty{\#1} is the value submitted for the key \krsty{testdim}.
Try \krcmd{show\string\mp@align}, \krcmd{show\string\KV@myfamily@testdim}, and \krcmd{show\string\f@testdim} to confirm the above assertions.

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

\subsection[Demonstrating an effect]%
  {Demonstrating the effect of limiting {\tt\textbackslash textwidth}}

After defining and setting the keys above, the following tokens can be used in a source file to demonstrate the effect of setting the page setup keys shown above:
\begin{krverbatim}
\begin{center}
  \begin{minipage}{\mp@textwidth}
    \lipsum[1]
      % |color(gray)From the |emph(lipsum) package.
      % |color(gray)The |emph(blindtext) package can also be used.
  \end{minipage}
\end{center}

\lipsum[1]
\end{krverbatim}

\section{Complementary boolean keys}

The syntax of complementary boolean keys is
\begin{krverbatim}
\define@comp@boolkeys[<key-prefix>]{<family>}[<macro-prefix]
  {<primary boolean>}[<default value for primary boolean>]
  {<secondary boolean>}{<func for primary boolean>}
  {<func for secondary boolean>}.
\end{krverbatim}

When the user doesn't supply the \krsty{key-prefix} and/or \krsty{macro-prefix}, the package will use \krsty{KV} and \krsty{mp@}, respectively. When one boolean (primary or secondary) is true, the other is
automatically set false. Infinite loops, which are possible in back-linked key settings, are avoided in the \krsty{keyreader} package.

As an example, we define below two complementary keys \krsty{draft} and \krsty{final} with different key macros:
\begin{krverbatim}
\define@comp@boolkeys[KV]{myfamily}[kr@]{draft}[true]{final}%
  {%
    \def\gobble##1{}%
  }{%
    \def\notgobble##1{##1}%
  }.
\end{krverbatim}
The key prefix (default \krsty{KV}), macro prefix (default \krsty{mp@}), and key macros (no default) can be empty:
\begin{krverbatim}
\define@comp@boolkeys{myfamily}{draft}[true]{final}{}{}.
\end{krverbatim}

The defined complementary keys \krsty{draft} and \krsty{final} can now be set as follows:
\begin{krverbatim}
\setkeys[KV]{myfamily}{draft=true}

\setkeys[KV]{myfamily}{final=true}
\end{krverbatim}
The second statement above reverses the boolean \krsty{draft} to \krsty{false}, which had been set in the first statement to \krsty{true}. There is no meaning to the following:
\begin{krverbatim}
\setkeys[KV]{myfamily}{draft=true,final=true}.
\end{krverbatim}

As an exercise, in a document file, after defining and setting the above keys, one can issue the command \krcmd{krsetup\{draft=true\}} and do
\begin{krverbatim}
\show\ifkr@draft \show\ifkr@final \show\gobble
\show\KV@myfamily@draft.
\end{krverbatim}
These statements assume the macro prefix to be \krsty{kr@}. Next, we may set
\begin{krverbatim}
\krsetup{final=true}
\end{krverbatim}
and do
\begin{krverbatim}
\show\ifkr@final \show\ifkr@draft \show\notgobble.
\end{krverbatim}

\section{Input error}

Both boolean and choice keys issue error messages if the input is not valid, \ie, not in the list of admissible values. The default input error is defined by \krcmd{kr@inputerr} macro to be
\begin{krverbatim}
<Erroneous value `#1' for key `#2'>.
\end{krverbatim}
\krcmd{kr@inputerr} can be redefined by the user. It takes two arguments (\ie, value and key).


\section{Conditionals in key macros}
\label{sec:conditionals}

The \TeX{} conditional primitives \krcmd{if} and \krcmd{fi} cannot appear in the key macro when \krcmd{define@keylist} is being invoked. The reason can be traced to the discussion on page~211 of the \TeX Book. Key macros/functions involving conditional operations such as
\begin{krverbatim}
\ifmp@boolone \do \fi
\end{krverbatim}
can be submitted to \krcmd{define@keylist} via macros, as seen above. We give more examples below.

Suppose we want to submit the following:
\begin{krverbatim}
\define@keylist{3,boolone,true,\ifmp@boolone \do \fi}.
\end{krverbatim}
The presence of \krcmd{if...} and \krcmd{fi} in the argument will trigger an error when \TeX{} is  scanning or skipping tokens (see the \TeX Book). Neither \krcmd{protect} nor \krcmd{noexpand} is helpful here. One solution is to first define
\begin{krverbatim}
\def\f@boolone{\ifmp@boolone \do \fi}
\end{krverbatim}
and then do
\begin{krverbatim}
\define@keylist{3,boolone,true,\f@boolone},
\end{krverbatim}
which will execute \krcmd{f@boolone} when the key \krsty{boolone} is set. Once the key \krsty{boolone} has been defined by the above statement, the function \krcmd{f@boolone} may be  redefined and reused many times, any time, even before the setting of the key \krsty{boolone}. It isn't the function \krcmd{f@boolone} that is used in defining the key \krsty{boolone}, but the ``meaning'' of \krcmd{f@boolone}.

As another example, we may do
\begin{krverbatim}
\def\f@bool{\ifmp@bool\def\do####1{%
  \def####1########1{\expandafter\expandafter\expandafter\in@
  \expandafter\expandafter\expandafter{\expandafter####1
  \expandafter}\expandafter{########1}}}\fi}

\define@keylist{3,bool,true,\f@bool}.
\end{krverbatim}

``Toggles,'' introduced in the \krsty{etoolbox} package, can also be used to circumvent the problem of matching \krcmd{if} and \krcmd{fi} in difficult circumstances, since toggles aren't \TeX\ primitives, but the \krsty{xkeyval} doesn't as yet have a mechanism for defining and setting toggle keys. However, this shouldn't be difficult to implement in the future.

\section{Disabling keys}

The \krsty{keyreader} package has modified the definition of \krcmd{disable@keys} from the \krsty{xkeyval} package to allow for bespoke warnings and error messages. The new command is \krcmd{krdisable@keys}; the use syntax remains the same as that of \krcmd{disable@keys}:
\begin{krverbatim}
\krdisable@keys[<key prefix>]{<key family>}{<comma %
  separated list of keys to disable>}.
\end{krverbatim}

Any attempt to subsequently set a disabled key will prompt the following error message. (The \krsty{xkeyval} package issues a warning in this case.) The error message can be modified by the user, but the ``names'' \krcmd{disabledkeyerr} and \krcmd{disabledkey} should be retained.
\begin{krverbatim}
\def\disabledkeyerr{%
  \PackageError{keyreader}{%
    Key `\disabledkey' has been disabled.\MessageBreak
    You can't set or reset it at this late stage.\MessageBreak
    You should have set it earlier in the\MessageBreak
    \string\documentclass\space or \string\usepackage
  }{\@ehc}%
}
\end{krverbatim}
If the user attempts to disable an undefined key, the \krsty{xkeyval} package issues a fatal error; the \krsty{keyreader} package, on the other hand, issues a warning in the transcript .log file, since the situation isn't fatal to the outcome.

\end{document}

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