%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
%                                                                          %
% This is file 'keyreader.sty', version 0.4b, January 2012.                %
%                                                                          %
% This package and accompanying files may be distributed and/or            %
% modified under the conditions of the LaTeX Project Public License,       %
% either version 1.3 of this license or any later version. The latest      %
% version of this license is in http://www.latex-project.org/lppl.txt      %
% and version 1.3 or later is part of all distributions of LaTeX           %
% version 2005/12/01 or later.                                             %
%                                                                          %
% The LPPL maintenance status of this software is 'author-maintained'.     %
%                                                                          %
% This software is provided 'as it is', without warranty of any kind,      %
% either expressed or implied, including, but not limited to, the          %
% implied warranties of merchantability and fitness for a particular       %
% purpose.                                                                 %
%                                                                          %
% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com).                  %
%                                                                          %
%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%

\ProvidesPackage{keyreader}
  [2012/01/14 v0.4b Robust interfaces to xkeyval package (AM)]
\ifcase
  \ifx\eTeXversion\@undefined\z@\else
    \ifnum\eTeXversion<\tw@\z@\else\@ne\fi\fi
  \PackageError{keyreader}
    {eTeX not loaded or old version}
    {This package requires eTeX version 2 or higher.}%
  \expandafter\endinput
\fi
\NeedsTeXFormat{LaTeX2e}[2011/06/27]
\begingroup
\catcode064 11% @
\catcode123 01% {
\catcode125 02% }
\catcode044 12% ,
\def\reserved@a{\endgroup
  \def\do##1,{%
    \ifx##1\end\else
      \catcode##1\string=\the\catcode##1 %
      \expandafter\do
    \fi
  }%
  \edef\krd@restorecodes{\do035,064,123,125,061,059,\end,}%
}
\reserved@a
\catcode035 06% #
\catcode064 11% @
\catcode123 01% {
\catcode125 02% }
\catcode061 12% =
\catcode044 12% ,
\def\do#1=#2,{%
  \ifx#1\end\else
    \edef\krd@restorecodes{%
      \krd@restorecodes
      \catcode#1=\the\catcode#1 %
    }%
    \catcode#1=#2\relax
    \expandafter\do
  \fi
}
\do 032=10,033=12,036=03,038=04,040=12,041=12,042=12,043=12,%
059=12,045=12,047=12,058=12,063=12,091=12,093=12,126=13,\end=,%
\AtEndOfPackage{%
  \krdAfterEndPackage{%
    \krd@restorecodes
    \let\krd@restorecodes\@undefined
  }%
}
\RequirePackage{xkeyval}[2008/08/13]
\def\@space{ }
\protected\def\krdnewlet#1{\@ifdefinable#1\relax\let#1}
\krdnewlet\krd@nil\relax
\def\krd@nnil{\krd@nil}
\def\krdswap#1#2{#2#1}
\def\krd@quark{\@gobble\krd@quark}
\newcount\krd@csvdepth
\newif\ifkrdloopbreak
\newif\ifkrd@st
\newif\ifkrddef
\krdnewlet\krdloopbreak\krdloopbreaktrue
\begingroup
\catcode`\&=7
\gdef\krdtrimspace#1{\krd@trimspace@a.#1& &}
\gdef\krd@trimspace@a#1 &{\krd@trimspace@b#1&}
\gdef\krd@trimspace@b#1&#2{%
  \krdexpandonce{\romannumeral-`\q\expandafter\noexpand\@gobble#1}%
}
\endgroup
\protected\def\krdAfterEndPackage{%
  \krdifcsndef{\@currname.\@currext-krd@endpkghook}{}{%
    \@namedef{\@currname.\@currext-krd@endpkghook}{}%
  }%
  \expandafter\g@addto@macro
  \csname\@currname.\@currext-krd@endpkghook\endcsname
}
\xdef\@popfilename{%
  \unexpanded{%
    \csname\@currname.\@currext-krd@endpkghook\endcsname
    \expandafter\let
    \csname\@currname.\@currext-krd@endpkghook\endcsname
    \relax
  }%
  \unexpanded\expandafter{\@popfilename}%
}
\newcommand*\krdifdef[1]{%
  \krdifblank{#1}\@secondoftwo{%
    \ifx#1\@undefined
      \expandafter\@secondoftwo
    \else
      \ifx#1\relax
        \expandafter\expandafter\expandafter\@secondoftwo
      \else
        \expandafter\expandafter\expandafter\@firstoftwo
      \fi
    \fi
  }%
}
\newcommand*\krdifcsndef[1]{%
  \krdifblank{#1}{%
    \expandafter\@secondoftwo\@gobble
  }{%
    \ifcsname#1\endcsname
      \expandafter\@firstofone
    \else
      \expandafter\expandafter\expandafter
      \@secondoftwo\expandafter\@gobble
    \fi
  }{%
    \expandafter\krdifdef\csname#1\endcsname
  }%
}
\def\krd@ifx@quark{\@gobble\krd@ifx@quark}
\newcommand\krdifx[2]{%
  \ifx#1#2\krd@ifx@quark
  \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\long\def\krdifblank#1{%
  \ifcat$\detokenize\expandafter{\@gobble#1.}$%
  \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}
\def\krdifbool#1{%
  \krdifblank{#1}{%
    \@secondoftwo
  }{%
    \krdifcsndef{if#1}{%
      \csname @\csname if#1\endcsname
        first\else second\fi oftwo\endcsname
    }{%
      \@latex@error{Undefined boolean '#1'}\@ehc
    }%
  }%
}
\def\krd@ifswitch@aux#1#2\krd@nil{%
  \krdifblank{#2}\@secondoftwo\@firstoftwo
}
\def\krdifswitch#1{%
  \krdifblank{#1}{%
    \@secondoftwo
  }{%
    \expandafter\krd@ifswitch@aux\romannumeral-`\q#1\krd@nil{%
      \if#1\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
    }{%
      \@latex@error{Invalid switch '#1'}\@ehc
    }%
  }%
}
\krdifx\pdfstrcmp\@undefined{%
  \RequirePackage{pdftexcmds}%
  \krdifx\pdf@strcmp\@undefined{%
    \cpt@err{Neither '\string\pdfstrcmp' nor '\string\pdf@strcmp' exists}\@ehc
  }{%
    \let\krd@pdfstrcmp\pdf@strcmp
  }%
}{%
  \let\krd@pdfstrcmp\pdfstrcmp
}
\newcommand\krdifstrcmp[2]{%
  \csname @\ifnum\krd@pdfstrcmp{\detokenize{#1}}%
    {\detokenize{#2}}=0first\else second\fi oftwo\endcsname
}
\def\krdifbraced#1{%
  \expandafter\krdswap\expandafter{%
    \expandafter{\romannumeral-`\q\krd@ifbraced@a{#1}}%
  }{%
    \expandafter\krd@ifbraced@d\romannumeral-`\q\krd@ifbraced@a{#1}\krd@nil
  }%
}
\begingroup
\catcode`\&=7
\gdef\krd@ifbraced@a#1{\krd@ifbraced@b.#1& &}
\gdef\krd@ifbraced@b#1 &{\krd@ifbraced@c#1&}
\gdef\krd@ifbraced@c#1&#2{\expandafter\noexpand\@gobble#1}
\endgroup
\def\krd@ifbraced@d#1\krd@nil#2{%
  \krdifstrcmp{#1}{#2}\@secondoftwo\@firstoftwo
}
\def\krdexpandonce#1{\unexpanded\expandafter{#1}}
\def\krdnoexpandcsn#1{\krdexpandonce{\csname#1\endcsname}}
\protected\def\krdexpanded#1{%
  \begingroup
  \protected@edef\reserved@a{\endgroup#1}\reserved@a
}
\protected\def\krdexpandarg#1#2{\krdexpanded{\unexpanded{#1}{#2}}}
\protected\def\krdexpandargonce#1#2{%
  \krdexpanded{\unexpanded{#1}{\krdexpandonce{#2}}}%
}
\protected\def\krdexpandsecond#1#2{\krdexpanded{\unexpanded{#1}#2}}
\protected\def\krdexpandsecondonce#1#2{%
  \krdexpanded{\unexpanded{#1}\krdexpandonce{#2}}%
}
% Eg,
% \newcount\nr\nr=\tw@
% \def\do#1{%
%   \let\noexpand#1%
%   \expandafter\noexpand\csname\expandafter\@gobble\string#1@%
%   \romannumeral\nr\endcsname
% }
% \edef\x{\krdfor{\cmda,\cmdb}}
% \show\x -> \let\cmda\cmda@ii \let\cmdb\cmdb@ii
\def\krdfor#1{\krd@for@a#1,\krd@nnil,\krd@nil}
\def\krd@for@a#1,#2\krd@nil{%
  \krdifblank{#1}{%
    \krd@for@a#2\krd@nil
  }{%
    \expandafter\krdifx\@car#1\@nil\krd@nnil
    {}{\do{#1}\krd@for@a#2\krd@nil}%
  }%
}
% We redefine xkeyval's loops to increase robustness.
% We can't replace \@nil by \krd@nil here because xkeyval
% uses \@nil in calling these macros:
\protected\long\def\XKV@for@n#1#2#3{%
  \edef#2{\unexpanded{#1}}%
  \krdifx#2\@empty{}{%
    \XKV@f@r#2{#3}#1,\@nil,%
  }%
}
\protected\long\def\XKV@f@r#1#2#3,{%
  \edef#1{\unexpanded{#3}}%
  \krdifx#1\@nnil{}{#2\XKV@f@r#1{#2}}%
}
\protected\long\def\XKV@for@eo#1#2#3{%
  \edef#2{\unexpanded{\XKV@f@r#2{#3}}}%
  \expandafter#2#1,\@nil,%
}
\protected\long\def\XKV@whilist#1#2#3\fi#4{%
  #3\relax
    \expandafter\@firstofone
  \else
    \expandafter\@gobble
  \fi
  {\expandafter\XKV@wh@list#1,\@nil,\@nnil#2#3\fi{#4}{}}%
}
\long\def\XKV@wh@list#1,#2\@nnil#3#4\fi#5#6{%
  \edef#3{\unexpanded{#1}}%
  \krdifx#3\@nnil{%
    \def#3{#6}\@gobble
  }{%
    #4\relax
      \expandafter\@firstofone
    \else
      \def#3{#6}%
      \expandafter\@gobble
    \fi
  }%
  {#5\XKV@wh@list#2\@nnil#3#4\fi{#5}{#1}}%
}
\protected\def\KV@@sp@def#1#2{\edef#1{\krdtrimspace{#2}}}
\protected\def\XKV@sp@deflist#1#2{%
  \edef#1{\unexpanded{#2}}%
  \krdcsvnormalize#1%
}
\def\krd@loopdo@stack{}
\protected\def\krd@pushloopdo{%
  \global\advance\krd@csvdepth\@ne
  \def\reserved@a##1{\expandafter\@gobble\string##1@%
    \romannumeral\krd@csvdepth}%
  \def\do##1{\let\noexpand##1\krdnoexpandcsn{\reserved@a{##1}}}%
  \xdef\krd@loopdo@stack{%
    \krdfor{\krd@loopdo,\ifkrdloopbreak,\krd@final@loopact,%
      \krd@regular@loopact}%
    {\krdexpandonce\krd@loopdo@stack}%
  }%
  \def\do##1{\let\krdnoexpandcsn{\reserved@a{##1}}\noexpand##1}%
  \krdexpanded{%
    \krdfor{\krd@loopdo,\ifkrdloopbreak,\krd@final@loopact,%
      \krd@regular@loopact}%
  }%
}
\protected\def\krd@poploopdo{%
  \begingroup
  \def\reserved@a##1##{\endgroup##1\gdef\krd@loopdo@stack}%
  \expandafter\reserved@a\krd@loopdo@stack
  \global\advance\krd@csvdepth\m@ne
}
\protected\def\krd@testst#1{\@ifstar{\krd@sttrue#1}{\krd@stfalse#1}}

% \krdlistloop[<parser>]{<list>}<\if...>\fi<ini-code><final-code><reg-code>
% When the conditional <\if...> isn't true, the regular code <reg-code>
% will be executed for every member of the list.
% <final-code> will be executed when the conditional <\if...> is true.
% <ini-code> may be used to first turn <\if...> off before commencing
% the loop. \ifkrdloopbreak may be used as the conditional in <\if...>.
% Both <ini-code> and <final-code> can be empty (ie, {}).
% Use '#1' in <final-code> and <reg-code> to access the current element
% of the list.
\protected\def\krdlistloop{\krd@testst{\@testopt\krd@listloop,}}
\protected\def\krd@listloop[#1]#2#3\fi#4#5#6{%
  \krd@pushloopdo
  \edef\krd@csvarg{\krdifbool{krd@st}\krdexpandonce\unexpanded{#2}}%
  \krdcsvnormalize[#1]\krd@csvarg
  \def\krd@final@loopact##1{#5}%
  \def\krd@regular@loopact##1{#6}%
  % Initial code:
  #4\relax
  \def\krd@loopdo##1#1##2\krd@nnil{%
    \edef\krd@csvarg{\krdexpandonce{\@gobble##1}}%
    \krdifx\krd@csvarg\krd@nnil{}{%
      #3\relax
      \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
      {%
        \expandafter\krd@final@loopact\expandafter{\krd@csvarg}\relax
      }{%
        \expandafter\krd@regular@loopact\expandafter{\krd@csvarg}\relax
        \krd@loopdo.##2\krd@nnil
      }%
    }%
  }%
  \expandafter\krd@loopdo\expandafter.\krd@csvarg#1\krd@nil#1\krd@nnil
  \krd@poploopdo
}
\protected\def\krdaddtolist{\krd@testst{\@testopt{\krd@addtolist{e}},}}
\protected\def\krdgaddtolist{\krd@testst{\@testopt{\krd@addtolist{x}},}}
\protected\def\krd@addtolist#1[#2]#3#4{%
  \@nameuse{#1def}#3{%
    \krdifdef#3{%
      \krdifx#3\@empty{}{\krdexpandonce#3#2}%
    }{}%
    \krdifbool{krd@st}\krdexpandonce\unexpanded{#4}%
  }%
}
\protected\def\krdcsvnormalize{\@testopt\krd@csvnormalize,}
\protected\def\krd@csvnormalize[#1]#2{%
  \begingroup
  \krd@setupnormalize{#1}%
  \def\krd@inkv{01}%
  \edef#2{\expandafter\krd@normalizelist\expandafter{#2}}%
  \krdexpanded{\endgroup
    \edef\noexpand#2{\noexpand\unexpanded{\krdexpandonce{#2}}}%
  }%
}
\protected\def\krdkvnormalize#1{%
  \begingroup
  \krd@setupnormalize{,}%
  \def\krd@inkv{00}%
  \edef#1{\expandafter\krd@normalizelist\expandafter{#1^?^}}%
  \def\reserved@b##1^?^##2\krd@nil{%
    \edef#1{\unexpanded{##1##2}}%
  }%
  \expandafter\reserved@b#1\krd@nil
  \krdexpanded{\endgroup
    \edef\noexpand#1{\noexpand\unexpanded{\krdexpandonce{#1}}}%
  }%
}
\begingroup
\catcode`\~=13
\catcode`\!=13
\protected\gdef\krd@setupnormalize#1{%
  \begingroup
  \uccode`\~=`#1%
  \uccode`\!=`\=%
  \uppercase{\endgroup
    \def\krd@normalizelist##1{%
      \unexpanded\expandafter{\romannumeral-`\q
        \krd@activeparser#1##1#1~\krd@nil}%
    }%
    \def\krd@activeparser##1~##2\krd@nil{%
      \krdifblank{##2}{%
        \krdifswitch\krd@inkv{%
          \krd@activeequal##1!\krd@nil
        }{%
          \krd@spaceparser##1 #1\krd@nil
        }%
      }{%
        \krd@activeparser##1#1##2\krd@nil
      }%
    }%
  }%
  \begingroup
  \uccode`\~=`\=%
  \uppercase{\endgroup
    \def\krd@activeequal##1~##2\krd@nil{%
      \krdifblank{##2}{%
        \krd@spaceparser##1 #1\krd@nil
      }{%
        \krd@activeequal##1=##2\krd@nil
      }%
    }%
  }%
  \def\krd@spaceparser##1 #1##2\krd@nil{%
    \krdifblank{##2}{%
      \krd@parserspace##1#1 \krd@nil
    }{%
      \krd@spaceparser##1#1##2\krd@nil
    }%
  }%
  \def\krd@parserspace##1#1 ##2\krd@nil{%
    \krdifblank{##2}{%
      \krdifswitch\krd@inkv{%
        \krd@spaceequal##1 =\krd@nil
      }{%
        \krd@doubleparser##1#1#1\krd@nil
      }%
    }{%
      \krd@parserspace##1#1##2\krd@nil
    }%
  }%
  \def\krd@spaceequal##1 =##2\krd@nil{%
    \krdifblank{##2}{%
      \krd@equalspace##1= \krd@nil
    }{%
      \krd@spaceequal##1=##2\krd@nil
    }%
  }%
  \def\krd@equalspace##1= ##2\krd@nil{%
    \krdifblank{##2}{%
      \krd@doubleparser##1#1#1\krd@nil
    }{%
      \krd@equalspace##1=##2\krd@nil
    }%
  }%
  \def\krd@doubleparser##1#1#1##2\krd@nil{%
    \krdifblank{##2}{%
      \krdifswitch\krd@inkv{%
        \krd@doubleequal##1==\krd@nil
      }{%
        \krdifblank{##1}{}{%
          \krd@remleadparser##1\krd@nil
        }%
      }%
    }{%
      \krd@doubleparser##1#1##2\krd@nil
    }%
  }%
  \def\krd@doubleequal##1==##2\krd@nil{%
    \krdifblank{##2}{%
      \krdifblank{##1}{}{%
        \krd@remleadparser##1\krd@nil
      }%
    }{%
      \krd@doubleequal##1=##2\krd@nil
    }%
  }%
  \def\krd@remleadparser#1##1\krd@nil{\noexpand##1}%
  \def\krd@parserequalerr##1#1=##2\krd@nil{%
    \krdifblank{##2}{}{%
      \@latex@error{There is '#1=' in your key-value list}\@ehc
    }%
  }%
}
\endgroup
\krd@setupnormalize{,}

% Redefine \XKV@define@key to heed a complaint about argument grabbing:
\protected\def\XKV@define@key#1{%
  \@ifnextchar[{\XKV@d@fine@k@y{#1}}{%
    \begingroup
    \toks1{\endgroup\@namedef{\XKV@header#1}####1}%
    \def\reserved@a{\the\toks\expandafter1\expandafter{\the\toks0}}%
    \afterassignment\reserved@a\toks0=%
  }%
}
\def\XKV@d@fine@k@y#1[#2]#3{%
  \XKV@define@default{#1}{#2}%
  \expandafter\def\csname\XKV@header#1\endcsname##1{#3}%
}
\protected\def\XKV@checksanitizea#1#2{%
  \XKV@ch@cksanitize{#1}#2=%
  \ifin@\else\XKV@ch@cksanitize{#1}#2,\fi
  \krdifbool{in@}{\krdkvnormalize#2}{}%
}
\protected\def\XKV@checksanitizeb#1#2{%
  \XKV@ch@cksanitize{#1}#2,%
  \krdifbool{in@}{\krdcsvnormalize[,]#2}{}%
}
% Don't apply the new schemes to \setkeys, because old calls to
% \setkeys will now discover that braces are preserved. This may
% break their codes:
\protected\def\krdsetkeys{\XKV@testopta{\XKV@testoptc\krd@setkeys}}
\protected\def\krd@setkeys[#1]#2{%
  \edef\krd@na{\unexpanded{#1}}%
  \krdifx\krd@na\@empty{}{\krdcsvnormalize\krd@na}%
  \edef\XKV@resb{\unexpanded{#2}}%
  \krdkvnormalize\XKV@resb
  \let\XKV@naa\@empty
  \XKV@for@o\XKV@resb\XKV@tempa{%
    \expandafter\XKV@g@tkeyname\XKV@tempa=\@nil\XKV@tempa
    \XKV@addtolist@x\XKV@naa\XKV@tempa
  }%
  \ifnum\XKV@depth=\z@\let\XKV@rm\@empty\fi
  \expandafter\XKV@usepresetkeys\expandafter{\krd@na}{preseth}%
  \krdexpandsecond\krd@s@tkeys
    {{\krdexpandonce\XKV@resb}{\krdexpandonce\krd@na}}%
  \expandafter\XKV@usepresetkeys\expandafter{\krd@na}{presett}%
  \let\CurrentOption\@empty
}
\protected\def\krd@s@tkeys#1#2{%
  \edef\key@list{\unexpanded{#1}}%
  \krdkvnormalize\key@list
  \edef\XKV@na{\unexpanded{#2}}%
  \krdifx\XKV@na\@empty{}{\krdcsvnormalize\XKV@na}%
  \def\krd@s@tkeys@a##1={%
    \def\reserved@a####1=####2\@nil{%
      \edef\reserved@a{\expandafter\krdtrimspace\expandafter{\@gobble####1}}%
      \krdifx\reserved@a\@empty{%
        \expandafter\krd@s@tk@ys##1==\@nil
      }{%
        \expandafter\krdifbraced\expandafter{\reserved@a}{%
          \edef\CurrentOption{%
            \unexpanded{##1}={{\krdexpandonce\reserved@a}}%
          }%
        }{%
          \edef\CurrentOption{\unexpanded{##1}=\krdexpandonce\reserved@a}%
        }%
        \expandafter\krd@s@tk@ys\CurrentOption==\@nil
      }%
    }%
    \reserved@a.%
  }%
  \XKV@for@o\key@list\CurrentOption{%
    \expandafter\krd@s@tkeys@a\CurrentOption==\@nil
  }%
}
% \XKV@s@tk@ys is responsible for the inability of
% xkeyval's \setkeys to handle unbalanced conditionals. So
% we redefine it here, but only for \krdsetkeys:
\protected\def\krd@s@tk@ys#1=#2=#3\@nil{%
  \XKV@g@tkeyname#1=\@nil\XKV@tkey
  \krdexpandargonce{\KV@@sp@def\XKV@tkey}\XKV@tkey
  \krdifx\XKV@tkey\@empty{%
    \krdifblank{#2}{}{%
      \XKV@err{No key specified for value '\the\XKV@toks'}%
    }%
  }{%
    \@expandtwoargs\in@{,\XKV@tkey,}{,\XKV@na,}%
    \krdifbool{in@}{}{%
      \XKV@knftrue
      \KV@@sp@def\XKV@tempa{#2}%
      \krdifbool{XKV@preset}{%
        \XKV@s@tk@ys@{#3}%
      }{%
        \krdifbool{XKV@pl}{%
          \XKV@for@eo\XKV@fams\XKV@tfam{%
            \XKV@makehd\XKV@tfam
            \XKV@s@tk@ys@{#3}%
          }%
        }{%
          \XKV@whilist\XKV@fams\XKV@tfam\ifXKV@knf\fi{%
            \XKV@makehd\XKV@tfam
            \XKV@s@tk@ys@{#3}%
          }%
        }%
      }%
      \krdifbool{XKV@knf}{%
        \krdifbool{XKV@inpox}{%
          \krdifx\XKV@doxs\relax{%
            \ifx\@currext\@clsextension\else
              \let\CurrentOption\XKV@tkey\@unknownoptionerror
            \fi
          }{%
            \XKV@doxs
          }%
        }{%
          \krdifbool{XKV@st}{%
            \XKV@addtolist@o\XKV@rm\CurrentOption
          }{%
            \XKV@err{Key '\XKV@tkey' undefined in families '\XKV@fams'}%
          }%
        }%
      }{%
        \krdifbool{XKV@inpox}{%
          \krdifx\XKV@testclass\XKV@documentclass{%
            \expandafter\XKV@useoption\expandafter{\CurrentOption}%
          }{}%
        }{}%
      }%
    }%
  }%
}
\protected\def\krdsetrmkeys{\XKV@testopta{\XKV@testoptc\krd@setrmkeys}}
\protected\def\krd@setrmkeys[#1]{%
  \krdexpandargonce{\krd@setkeys[#1]}\XKV@rm
}
% We alias xkeyval's \savekeys to \savevaluekeys:
\krdnewlet\savevaluekeys\savekeys
% We split xkeyval's \presetkeys (head and tail) into
% \krdpresetkeys (head only) and \krdpostsetkeys (tail only):
\protected\def\krdpresetkeys{\@testopt\krd@presetkeys{KV}}
\protected\def\krd@presetkeys[#1]#2#3{\presetkeys[#1]{#2}{#3}{}}
\protected\def\krdpostsetkeys{\@testopt\krd@postsetkeys{KV}}
\protected\def\krd@postsetkeys[#1]#2#3{\presetkeys[#1]{#2}{}{#3}}
\protected\def\krd@disabledkey@err#1{%
  \@latex@error{Key '#1' has been disabled}
    {You can't set or reset key '#1' at this\MessageBreak
    late stage. Perhaps you should have set it \MessageBreak
    earlier in \string\documentclass\@space or \string\usepackage}%
}
\protected\def\krddisablekeys{\XKV@testoptb\krd@disablekeys}
\protected\def\krd@disablekeys#1{%
  \def\krd@tempa{#1}%
  \krdcsvnormalize\krd@tempa
  \XKV@for@o\krd@tempa\krd@tempa{%
    \krdifcsndef{\XKV@header\krd@tempa}{}{%
      \@latex@warning@no@line{Key '\krd@tempa' is undefined:
        couldn't be disabled}%
    }%
    \krdifcsndef{\XKV@header\krd@tempa @default}{%
      \edef\krd@tempb{\noexpand\XKV@define@key{\krd@tempa}[]}%
    }{%
      \edef\krd@tempb{\noexpand\XKV@define@key{\krd@tempa}}%
    }%
    \krdexpandarg{\expandafter\krd@tempb\expandafter}%
      {\krd@disabledkey@err{\krd@tempa}}%
  }%
}
\edef\krd@hashchar{\string#}
\protected\def\krddefinekeys{%
  \begingroup
  \endlinechar\m@ne
  \krd@testst{\@testopt\krd@d@finekeys{KRD}}%
}
\protected\def\krd@d@finekeys[#1]#2{%
  \@testopt{\krd@d@f@nekeys{#1}{#2}}{krdmp@}%
}
\protected\def\krd@d@f@nekeys#1#2[#3]#4{%
  \expandafter\endgroup
  \ifkrd@st
    \def\krd@keyst{00}%
  \else
    \def\krd@keyst{01}%
  \fi
  \krddeftrue
  \begingroup
  \edef\key@prefix{\krdtrimspace{#1}}%
  \edef\key@family{\krdtrimspace{#2}}%
  \edef\macro@prefix{\krdtrimspace{#3}}%
  \toks@{}%
  \def\krd@rej{^?^}%
  \def\key@vals{}%
  \def\krd@altlista{}%
  \def\krd@altlistb{}%
  \def\krd@splita##1/##2/{\krd@splitb##1/##2/.}%
  \def\krd@splitb##1/##2/##3/##4/##5/##6\krd@nil{%
    \edef\key@type{\krdtrimspace{##1}}%
    \edef\key@name{\krdtrimspace{##2}}%
    \@expandtwoargs\in@{\krd@hashchar}{\detokenize{##2}}%
    \ifin@
      \@latex@error{Bad key name '\detokenize{##2}'}\@ehc
    \fi
    \if\krd@keyst
      \krdifcsndef{\key@prefix @\key@family @##2}{%
        \@latex@error{Key '##2' already exists in
          family '\key@family'}\@ehc
      }{}%
    \fi
    \@expandtwoargs\in@{,\detokenize\expandafter{\key@type},}%
      {,\detokenize{ord,cmd,bool,choice},}%
    \ifin@\else
      \@latex@error{Unknown key type '\key@type'}\@ehc
    \fi
    \edef\key@default{\expandafter\krdtrimspace\expandafter{\@gobble##3}}%
    \edef\krd@resa{\krdtrimspace{##4}}%
    \edef\krd@resb{\krdtrimspace{##5}}%
    \@expandtwoargs\in@{,\detokenize\expandafter{\key@default},}%
      {,\detokenize{true,false},}%
    \edef\key@vals{%
      \ifx\key@vals\@empty\else\krdexpandonce\key@vals,\fi
      \ifx\key@default\krd@rej\else
        \key@name=\ifin@ false\else\krdexpandonce\key@default\fi
      \fi
    }%
    \def\reserved@a####1{%
      \def\reserved@a########1####1########2########3\krd@nil{%
        \def\key@typenr{########2}%
        \ifx\key@typenr\krd@nnil
          \@latex@error{Invalid key type '####1'}\@ehc
        \fi
      }%
      \reserved@a ord{0}cmd{1}bool{2}choice{3}####1{\krd@nil}\krd@nil
    }%
    \expandafter\reserved@a\expandafter{\key@type}%
    \ifnum\key@typenr=\thr@@
      \edef\reserved@a{\unexpanded{##4}}%
      \krdifx\reserved@a\@empty{%
        \@latex@error{Empty alternate list for choice key \key@name}\@ehc
      }{%
        \krdifx\reserved@a\krd@rej{%
          \@latex@error{Empty alternate list for choice key \key@name}\@ehc
        }{%
          \krd@getaltlist{##4}%
        }%
      }%
    \fi
    \krdexpanded{%
      \toks@{\the\toks@
        \krdnoexpandcsn{define@\ifnum\key@typenr>\z@\key@type\fi key}%
        \ifnum\key@typenr=\thr@@*\fi
        \ifnum\key@typenr>\@ne+\fi
        [\key@prefix]{\key@family}%
        \ifnum\key@typenr>\z@
          \ifnum\key@typenr<\thr@@[\macro@prefix]\fi
        \fi
        {\key@name}%
        \ifnum\key@typenr=\thr@@
          [\unexpanded{\krduserinput\krdorder}]%
          {\krdexpandonce\krd@altlista}%
        \fi
        \krdifx\key@default\krd@rej{}{%
          [\expandafter\krdifbraced\expandafter{\key@default}%
            {{{\krdexpandonce\key@default}}}{\krdexpandonce\key@default}]%
        }{%
          \ifnum\key@typenr=\thr@@
            \krdifx\krd@resb\krd@rej{}{\unexpanded{##5}}%
            \krd@executealt{########1}{\krdexpandonce\krd@altlistb}%
          \else
            \krdifx\krd@resa\krd@rej{}{\unexpanded{##4}}%
          \fi
        }%
        % Second branch of callback for '+' variants:
        \ifnum\key@typenr>\@ne{\noexpand\krd@keyvalerr}\fi
      }%
    }%
  }%
  \edef\key@list{\unexpanded{#4}}%
  \krdlistloop*[;]\key@list\ifx\end\@undefined\fi{}{}{%
    \krd@splita##1/^?^/^?^/^?^/^?^/\krd@nil
  }%
  \krdexpanded{\endgroup
    \the\toks@
    \noexpand\krdsetkeys[\key@prefix]%
      {\key@family}{\krdexpandonce\key@vals}%
  }%
  \krddeffalse
}
\protected\def\krd@keyvalerr{%
  \krd@getinnoval
  \@latex@error{Erroneous value '\krd@ival' for key or option
    \MessageBreak'\XKV@tkey'}{Invalid key value encountered.}%
}
\protected\def\krd@getaltlist#1{%
  \def\krd@g@taltlist##1.do=##2\krd@nil{%
    \edef\krd@tempa{\krdtrimspace{##1}}%
    \edef\krd@tempb{\detokenize\expandafter{\krd@tempa}{\krdtrimspace{##2}}}%
    \krdaddtolist*\krd@altlista\krd@tempa
    \krdaddtolist*\krd@altlistb\krd@tempb
  }%
  \krdlistloop[,]{#1}\ifx\end\@undefined\fi{}{}{%
    \@expandtwoargs\in@{\detokenize{.do=}}{\detokenize{##1}}%
    \krdifbool{in@}{%
      \krd@g@taltlist##1\krd@nil
    }{%
      \krd@g@taltlist##1.do=\krd@nil
    }%
  }%
}
\protected\def\krd@executealt#1#2{%
  \edef\reserved@a{\krdtrimspace{#1}}%
  \edef\reserved@a{\detokenize\expandafter{\reserved@a}}%
  \krdexpandsecond{\def\reserved@a##1}\reserved@a##2##3\krd@nil{%
    \edef\reserved@a{\unexpanded{##2}}%
    \krdifx\reserved@a\krd@nnil{%
      \@latex@error{No alternate list match for key '\XKV@tkey'}\@ehc
    }{%
      ##2%
    }%
  }%
  \reserved@a#2#1{\krd@nil}\krd@nil
}
\protected\def\krd@getinnoval{%
  \begingroup
  \def\reserved@a##1=##2=##3\krd@nil{%
    \def\krd@tval{##2}%
  }%
  \expandafter\reserved@a\CurrentOption==\krd@nil
  \krdifx\krd@tval\@empty{%
    \def\krd@ival{???}%
  }{%
    \def\krd@ival{}%
    \@tempcnta\z@
    \def\do##1{%
      \def\reserved@a{##1}%
      \krdifx\reserved@a\krd@nnil{}{%
        \advance\@tempcnta\@ne
        \ifnum\@tempcnta<20\relax
          \edef\krd@ival{\krd@ival##1}%
          \expandafter\do
        \else
          \def\do####1\krd@nil{}%
          \expandafter\do
        \fi
      }%
    }%
    \expandafter\do\detokenize\expandafter{\krd@tval}\krd@nil
  }%
  \krdexpanded{\endgroup
    \def\noexpand\krd@ival{\krd@ival}%
  }%
}
\krdnewlet\krdDeclareOption\DeclareOptionX
\krdnewlet\krdExecuteOptions\ExecuteOptionsX
\krdnewlet\krdProcessOptions\ProcessOptionsX
\krdDeclareOption*{\PackageWarning{keyreader}{Unknown option
  '\CurrentOption' ignored.}}
\krdProcessOptions[KRD]<keyreader>\relax

\endinput
