% \iffalse
%% File: l3keys2e.dtx (C) Copyright 2009 LaTeX3 Project 
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the ``l3keys2e'' (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%% 
%
%<*driver|package>
\RequirePackage{l3names}
%</driver|package>
%\fi
\GetIdInfo$Id: l3keys2e.dtx 2076 2010-10-13 19:09:59Z joseph $
  {Parsing LaTeX3 keyvals as LaTeX2e package options}
%\iffalse
%<*driver>
%\fi
\ProvidesFile{\filename.\filenameext}
  [\filedate\space v\fileversion\space\filedescription]
%\iffalse
\documentclass{l3doc}
\begin{document}
  \DocInput{l3keys2e.dtx}
\end{document}
%</driver>
% \fi
%
% \title{The \textsf{l3keys2e} package\thanks{This file
%         has version number \fileversion, last revised \filedate.}\\
% Parsing \LaTeX3 keyvals as \LaTeXe\ package options}
% \author{\Team}
% \date{\filedate}
% \maketitle
%
%\begin{documentation}
%
%\section{Key--value arguments as \LaTeXe\ class and package options}
%
% The key--value method for optional arguments is very popular, as it
% allows the class or package author to define a large number of
% options with a simple interface. The \pkg{expl3} bundle of \LaTeX3
% base code includes the module \pkg{l3keys} for defining keys, but
% to use these when loading \LaTeXe\ packages and classes requires
% extra support. That support is provided by this small package, which
% is intended to enable \LaTeXe\ packages to benefit from the power of 
% the \LaTeX3 key--value system.
% 
%\subsection{Creating and using keyval options}
%
% As with any key--value input, using key--value pairs as package or
% class options has two parts. The first stage is to define one or
% more keys, using the \cs{keys_define:nn} function. For example, an 
% option which simply stores a value would be created using:
%\begin{verbatim} 
%  \keys_define:nn { module } {
%    option .set:N = \l_module_variable_tl
%  }
%\end{verbatim}
% On its own, this will not make the key an option for the package or
% class containing the definition. The second stage is therefore to 
% process the current options, searching for applicable keys.
% 
%\begin{function}{ \ProcessKeysOptions }
%  \begin{syntax}
%    \cs{ProcessKeysOptions} \Arg{module}
%  \end{syntax}
%  The \cs{ProcessKeysOptions} function is used to check the current 
%  option list against the keys defined for \Arg{module}. Global (class)
%  options and local (package) options are checked when this function
%  is called in a package. Each option which does match a key name is
%  then used to attempt to set the appropriate key using
%  \cs{keys_set:nn}. For example, the option defined earlier would be
% processed by the line
% \begin{verbatim}
%   \ProcessKeysOptions { module }
% \end{verbatim}
%\end{function}
%
%\begin{function}{ \ProcessKeysPackageOptions }
%  \begin{syntax}
%    \cs{ProcessKeysPackageOptions} \Arg{module}
%  \end{syntax}
%  This function works in a similar manner to \cs{ProcessKeysOptions}.
%  When used in a \LaTeXe\ package, \cs{ProcessKeysPackageOptions}
%  will not examine any class options available. In contrast,
%  \cs{ProcessKeysOptions} does parse class options (in common with the 
%  \LaTeXe\ kernel function \cs{ProcessOptions}).
%\end{function}
%
%\end{documentation}
% 
%\begin{implementation}
%
%\subsection{Implementation}
%
% The usual lead-off.
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage
  {\filename}{\filedate}{\fileversion}{\filedescription}
\RequirePackage { xparse }
%    \end{macrocode}
% 
%\begin{macro}{\keys_latexe_options_clist}
% A single list is used for all options, into which they are collected
% before processing.
%    \begin{macrocode}
\clist_new:N \keys_latexe_options_clist
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\_l_keys_process_class_bool}
% A flag to indicate that class options should be processed for
% packages.
%    \begin{macrocode}
\bool_new:N \_l_keys_process_class_bool
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_latexe_options:n}
% The main function calls functions to collect up the global and local
% options into \cs{keys_latexe_options_clist} before calling the 
% underlying functions to actually do the processing. So that a suitable
% message is produced if the option is unknown, the special 
% \texttt{unknown} key is set if it does not already exist for the 
% current module.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_latexe_options:n #1 {
  \clist_clear:N \keys_latexe_options_clist
  \keys_latexe_options_global:n {#1}
  \keys_latexe_options_local:
  \cs_if_exist:cTF { \c_keys_root_tl {#1} / unknown .cmd:n }
    {
      \keys_define:nn {#1} 
        {
          unknown .code:n = 
            { 
              \msg_kernel_error:nnxx { keyvalue } { option-unknown }
                { \l_keys_key_tl } { \@currname }
            }
        }
    }
  \keys_set:nV {#1} \keys_latexe_options_clist
  \AtEndOfPackage { \cs_set_eq:NN \@unprocessedoptions \scan_stop: }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_latexe_options_global:n}
% Global (class) options are handled differently for \LaTeXe\ packages
% and classes. Hence this function is essentially a check on the current
% file type. The initial test is needed as \LaTeXe\ allows variables to
% be equal to \cs{scan_stop:}, which is forbidden in \LaTeX3 code.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_latexe_options_global:n #1 {
  \cs_if_eq:NNF \@classoptionslist \scan_stop: 
    {
      \cs_if_eq:NNTF \@currext \@clsextension 
        { \keys_latexe_options_class:n {#1} }
        {
          \bool_if:NT \_l_keys_process_class_bool
           { \keys_latexe_options_package:n {#1} }
        }
    }
}
%    \end{macrocode}
%\end{macro}    
%    
%\begin{macro}{\keys_latexe_options_class:n}
% For classes, each option (stripped of any content after `\texttt{=}')
% is checked for existence as a key. If found, the option is added to 
% the combined list for processing. On the other hand, unused options
% are stored up in \cs{@unusedoptionlist}.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_latexe_options_class:n #1 {
  \clist_map_inline:Nn \@classoptionslist 
    {
      \cs_if_exist:cTF 
        { 
          \c_keys_root_tl #1 / 
            \keys_latexe_remove_equals:n {##1} .cmd:n
        }
        { \clist_put_right:Nn \keys_latexe_options_clist {##1} }
        { \clist_put_right:Nn \@unusedoptionlist {##1} }
    }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_latexe_options_package:n}
% For global options when processing a package, the tasks are slightly
% different from those for a class. The check is the same, but here
% there is nothing to do if the option is not applicable. Each valid
% option also needs to be removed from \cs{@unusedoptionlist}.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_latexe_options_package:n #1 {
  \clist_map_inline:Nn \@classoptionslist 
    {
      \cs_if_exist:cTF 
        { 
          \c_keys_root_tl #1 / 
            \keys_latexe_remove_equals:n {##1} .cmd:n
        }
        {
          \clist_put_right:Nn \keys_latexe_options_clist {##1}
          \clist_remove_element:Nn \@unusedoptionlist {##1}
        }
    }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_latexe_options_local:}
% If local options are found, the are added to the processing list.
% \LaTeXe\ stores options for each file in a macro which may or may not
% exist, hence the need to use \cs{cs_if_exist:c}.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_latexe_options_local: {
  \cs_if_eq:NNF \@currext \@clsextension 
    {
      \cs_if_exist:cT { opt@ \@currname . \@currext } 
        {
          \exp_args:NNc \clist_put_right:NV \keys_latexe_options_clist 
            { opt@ \@currname . \@currext }
        }
    }
}
%    \end{macrocode}
%\end{macro}   
%    
%\begin{macro}{\keys_latexe_remove_equals:n}
%\begin{macro}{\keys_latexe_remove_equals:w}
% As the name suggests, this is a simple function to remove an equals
% sign from the input. This is all wrapped up in an \texttt{n} function
% so that there will always be a sign available.
%    \begin{macrocode}
\cs_new:Npn \keys_latexe_remove_equals:n #1 {
  \keys_latexe_remove_equals:w #1 = \q_stop
}
\cs_new:Npn \keys_latexe_remove_equals:w #1 = #2 \q_stop {#1}
%    \end{macrocode}
%\end{macro}
%\end{macro}
% 
%\begin{macro}{\ProcessKeysOptions}
%\begin{macro}{\ProcessKeysOptions}
% The user macro are simply wrappers around the internal process. In
% contrast to other similar packages, the module name is always required
% here.
%    \begin{macrocode}
\cs_new_protected:Npn \ProcessKeysOptions #1 {
  \bool_set_true:N \_l_keys_process_class_bool
  \keys_latexe_options:n {#1}
}
\cs_new_protected:Npn \ProcessKeysPackageOptions #1 {
  \bool_set_false:N \_l_keys_process_class_bool
  \keys_latexe_options:n {#1}
}
\@onlypreamble \ProcessKeysOptions
\@onlypreamble \ProcessKeysPackageOptions
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
% One message to give.
%    \begin{macrocode}
\msg_kernel_new:nnnn { keyvalue } { option-unknown } 
  { Unknown~option~'#1'~for~package~#2. }
  {
    LaTeX~has~been~asked~to~set~an~option~called~'#1'\\
    but~the~#2~package~has~not~created~an~option~with~this~name. 
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
% 
% \PrintIndex
