% \iffalse
%% File: l3keys.dtx Copyright (C) 2009-2010 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 ``expl3 bundle'' (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: l3keys.dtx 1894 2010-04-13 07:37:59Z joseph $
  {L3 Experimental key-value support}
%\iffalse
%<*driver>
%\fi
\ProvidesFile{\filename.\filenameext}
  [\filedate\space v\fileversion\space\filedescription]
%\iffalse
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{l3keys.dtx}
\end{document}
%</driver>
% \fi
% 
% \title{The \textsf{l3keys} package\thanks{This file
%         has version number \fileversion, last
%         revised \filedate.}\\
% Key--value support}
% \author{\Team}
% \date{\filedate}
% \maketitle
% 
%\begin{documentation}
%
% The key--value method is a popular system for creating large numbers
% of settings for controlling function or package behaviour.  For the
% user, the system normally results in input of the form
%\begin{verbatim}
%  \PackageControlMacro{
%    key-one = value one,
%    key-two = value two
%  }
%\end{verbatim}
% or
%\begin{verbatim}
%  \PackageMacro[
%    key-one = value one,
%    key-two = value two
%  ]{argument}.
%\end{verbatim}
% For the programmer, the original \pkg{keyval} package gives only
% the most basic interface for this work.  All key macros have to be
% created one at a time, and as a result the \pkg{kvoptions} and
% \pkg{xkeyval} packages have been written to extend the ease of
% creating keys.  A very different approach has been provided by
% the \pkg{pgfkeys} package, which uses a key--value list to
% generate keys.
% 
% The \pkg{l3keys} package is aimed at creating a programming 
% interface for key--value controls in \LaTeX3. Keys are
% created using a key--value interface, in a similar manner to 
% \pkg{pgfkeys}. Each key is created by setting one or more
% \emph{properties} of the key:
%\begin{verbatim}
%  \keys_define:nn { module }
%    key-one .code:n   = code including parameter #1,
%    key-two .tl_set:N = \l_module_store_tl
%  }
%\end{verbatim}
% These values can then be set as with other key--value approaches:
%\begin{verbatim}
%  \keys_set:nn { module }
%    key-one = value one,
%    key-two = value two
%  }
%\end{verbatim}
%
% At a document level, \cs{keys_set:nn} is used within a  
% document function. For \LaTeXe, a generic set up function could be 
% created with
%\begin{verbatim}
%  \newcommand*\SomePackageSetup[1]{%
%    \@nameuse{keys_set:nn}{module}{#1}%
%  }
%\end{verbatim}
% or to use key--value input as the optional argument for a macro:
%\begin{verbatim}
%  \newcommand*\SomePackageMacro[2][]{%
%    \begingroup
%      \@nameuse{keys_set:nn}{module}{#1}%
%      % Main code for \SomePackageMacro
%    \endgroup
%  }
%\end{verbatim} 
% The same concepts using \pkg{xparse} for \LaTeX3 use:
%\begin{verbatim}
%  \DeclareDocumentCommand \SomePackageSetup { m } {
%    \keys_set:nn { module } { #1 }
%  }
%  \DeclareDocumentCommand \SomePackageMacro { o m } {
%    \group_begin:
%      \keys_set:nn { module } { #1 }
%      % Main code for \SomePackageMacro
%    \group_end:
%  }
%\end{verbatim}
%
% Key names may contain any tokens, as they are handled internally
% using \cs{tl_to_str:n}. As will be discussed in 
% section~\ref{sec:subdivision}, it is suggested that the character 
% `\texttt{/}' is reserved for sub-division of keys into logical
% groups. Macros are \emph{not} expanded when creating key names,
% and so
%\begin{verbatim}
%  \tl_set:Nn \l_module_tmp_tl { key }
%  \keys_define:nn { module } {
%    \l_module_tmp_tl .code:n = code
%  }
%\end{verbatim} 
% will create a key called \cs{l_module_tmp_tl}, and not one called
% \texttt{key}.
%
%\section{Creating keys}
%
%\begin{function}{\keys_define:nn}
%  \begin{syntax}
%    "\keys_define:nn" \Arg{module} \Arg{keyval list}
%  \end{syntax}
%  Parses the <keyval list> and defines the keys listed there for
%  <module>. The <module> name should be a text value, but there are
%  no restrictions on the nature of the text. In practice the
%  <module> should be chosen to be unique to the module in question
%  (unless deliberately adding keys to an existing module).
%  
%  The <keyval list> should consist of one or more key names along
%  with an associated key \emph{property}. The properties of a key 
%  determine how it acts. The individual properties are described
%  in the following text; a typical use of \cs{keys_define:nn} might
%  read
%  \begin{verbatim}
%    \keys_define:nn { mymodule } {
%      keyname .code:n = Some~code~using~#1,
%      keyname .value_required:
%    }
%  \end{verbatim}
%  where the properties of the key begin from the \texttt{.} after
%  the key name.
%  
%  The \cs{keys_define:nn} function does not skip spaces in the 
%  input, and does not check the category codes for \texttt{,} and
%  \texttt{=} tokens. This means that it is intended for use with
%  code blocks and other environments where spaces are ignored.
%\end{function}
% 
%\begin{function}{
%  .bool_set:N  |
%  .bool_gset:N  
%}
%  \begin{syntax}
%    <key> .bool_set:N = <bool>
%  \end{syntax}
%  Defines <key> to set <bool> to <value> (which must be either 
%  \texttt{true} or \texttt{false}).  Here, <bool> is a \LaTeX3
%  boolean variable (\emph{i.e}.~created using \cs{bool_new:N}).
%  If the variable does not exist, it will be created at the point
%  that the key is set up.
%\end{function}
% 
%\begin{function}{.choice:}
%  \begin{syntax}
%    <key> .choice:
%  \end{syntax}
%  Sets <key> to act as a multiple choice key. Each valid choice 
%  for <key> must then be created, as discussed in 
%  section~\ref{sec:choice}.
%\end{function}
%
%\begin{function}{
%  .choice_code:n |
%  .choice_code:x
%}  
%  \begin{syntax}
%    <key> .choice_code:n = <code>
%  \end{syntax}
%  Stores <code> for use when \texttt{.generate_choices:n} creates one
%  or more choice sub-keys of the current key. Inside <code>, 
%  \cs{l_keys_choice_tl} contains the name of the choice made, and 
%  \cs{l_keys_choice_int} is the position of the choice in the list
%  given to \texttt{.generate_choices:n}. Choices are discussed in 
%  detail in section~\ref{sec:choice}.
%\end{function}
%
%\begin{function}{
%   .code:n |
%   .code:x
%  }
%  \begin{syntax}
%    <key> .code:n = <code>
%  \end{syntax}
%  Stores the <code> for execution when <key> is called. The <code> can
%  include one parameter ("#1"), which will be the <value> given for the
%  <key>. The \texttt{.code:x} variant will expand <code> at the point
%  where the <key> is created.
%\end{function}
% 
%\begin{function}{
%   .default:n |
%   .default:V
%  }
%  \begin{syntax}
%    <key> .default:n = <default>
%  \end{syntax}
%  Creates a <default> value for <key>, which is used if no value is 
%  given. This will be used if only the key name is given, but not if
%  a blank <value> is given:
%  \begin{verbatim}
%    \keys_define:nn { module } {
%      key .code:n    = Hello #1,
%      key .default:n = World
%    }
%    \keys_set:nn { module} {
%      key = Fred, % Prints 'Hello Fred'
%      key,        % Prints 'Hello World'
%      key = ,     % Prints 'Hello '
%    }
%  \end{verbatim}
%  \begin{texnote}
%    The <default> is stored as a token list variable, and therefore
%    should not contain unescaped "#" tokens.
%  \end{texnote}
%\end{function}
%
%\begin{function}{
%  .dim_set:N  |
%  .dim_set:c  |
%  .dim_gset:N |
%  .dim_gset:c |
%}
%  \begin{syntax}
%    <key> .dim_set:N  = <dimension>
%  \end{syntax}
%  Sets <key> to store the value it is given in <dimension>. Here, 
%  <dimension> is a \LaTeX3 \texttt{dim} variable 
%  (\emph{i.e}.~created using \cs{dim_new:N})  or a \LaTeXe\ 
%  \texttt{dimen} (\emph{i.e} created using \cs{newdimen}). If the 
%  variable does not exist, it will be created at the point that the 
%  key is set up.
%\end{function}
% 
%\begin{function}{.generate_choices:n}
%  \begin{syntax}
%    <key> .generate_choices:n = <comma list> 
%  \end{syntax}
%  Makes <key> a multiple choice key, accepting the choices specified
%  in <comma list>. Each choice will execute code which should 
%  previously have been defined using \texttt{.choice_code:n} or
%  \texttt{.choice_code:x}. Choices are discussed in detail in 
%  section~\ref{sec:choice}.
%\end{function}
%
%\begin{function}{
%  .int_set:N  |
%  .int_set:c  |
%  .int_gset:N |
%  .int_gset:c |
%}
%  \begin{syntax}
%    <key> .int_set:N  = <integer>
%  \end{syntax}
%  Sets <key> to store the value it is given in <integer>. Here, 
%  <integer> is a \LaTeX3 \texttt{int} variable 
%  (\emph{i.e}.~created using \cs{int_new:N})  or a \LaTeXe\ 
%  \texttt{count} (\emph{i.e} created using \cs{newcount}). If the 
%  variable does not exist, it will be created at the point that the 
%  key is set up.
%\end{function}
%
%\begin{function}{
%  .meta:n |
%  .meta:x
%}
%  \begin{syntax}
%    <key> .meta:n = <multiple keys>
%  \end{syntax}
%  Makes <key> a meta-key, which will set <multiple keys> in 
%  one go.  If <key> is given with a value at the time the key
%  is used, then the value will be passed through to the subsidiary 
%  <keys> for processing (as "#1").
%\end{function}
%
%\begin{function}{
%  .skip_set:N  |
%  .skip_set:c  |
%  .skip_gset:N |
%  .skip_gset:c |
%}
%  \begin{syntax}
%    <key> .skip_set:N  = <skip>
%  \end{syntax}
%  Sets <key> to store the value it is given in <skip>, which is 
%  created if it does not already exist. Here, 
%  <skip> is a \LaTeX3 \texttt{skip} variable 
%  (\emph{i.e}.~created using \cs{skip_new:N})  or a \LaTeXe\ 
%  \texttt{skip} (\emph{i.e} created using \cs{newskip}). If the 
%  variable does not exist, it will be created at the point that the 
%  key is set up.
%\end{function}
%
%\begin{function}{
%  .tl_set:N    |
%  .tl_set:c    |
%  .tl_set_x:N  |
%  .tl_set_x:c  |
%  .tl_gset:N   |
%  .tl_gset:c   |
%  .tl_gset_x:N |
%  .tl_gset_x:c |
%}
%  \begin{syntax}
%    <key> .tl_set:N  = <token list variable>
%  \end{syntax}
%  Sets <key> to store the value it is given in <token list variable>, 
%  which is created if it does not already exist. Here, 
%  <token list variable> is a \LaTeX3 \texttt{tl} variable 
%  (\emph{i.e}.~created using \cs{tl_new:N})  or a \LaTeXe\ 
%  macro with no arguments (\emph{i.e}.~created using
%  \cs{newcommand} or \cs{def}). If the variable does not exist, it 
%  will be created at the point that the key is set up. The \texttt{x}
%  variants perform an \texttt{x} expansion at the time the <value>
%  passed to the <key> is saved to the <token list variable>.
%\end{function}
% 
%\begin{function}{
%   .value_forbidden: |
%   .value_required:  |
% }
%  \begin{syntax}
%    <key> .value_forbidden:
%  \end{syntax}
%  Flags for forbidding and requiring a <value> for <key>. Giving a
%  <value> for a <key> which has the \texttt{.value_forbidden:} 
%  property set will result in an error. In the same way, if a <key> has
%  the \texttt{.value_required:} property set then a <value> must be
%  given when the <key> is used.
%\end{function}
%
%\section{Sub-dividing keys}
%\label{sec:subdivision}
%
% When creating large numbers of keys, it may be desirable to divide 
% them into several sub-groups for a given module. This can be achieved
% either by adding a sub-division to the module name:
%\begin{verbatim}
%  \keys_define:nn { module / subgroup } {
%    key .code:n = code
%  }
%\end{verbatim} 
% or to the key name:
%\begin{verbatim}
%  \keys_define:nn { module } {
%    subgroup / key .code:n = code
%  }
%\end{verbatim}  
% As illustrated, the best choice of token for sub-dividing keys in
% this way is `\texttt{/}'. This is because of the method that is
% used to represent keys internally. Both of the above code fragments
% set the same key, which has full name \texttt{module/subgroup/key}.
% 
% As will be illustrated in the next section, this subdivision is
% particularly relevant to making multiple choices.
%
%\subsection{Multiple choices}
%\label{sec:choice}
%
% Multiple choices are created by setting the \texttt{.choice:} 
% property:
%\begin{verbatim}
%  \keys_define:nn { module } {
%    key .choice:
%  }
%\end{verbatim}
% For keys which are set up as choices, the valid choices are generated
% by creating sub-keys of the choice key. This can be carried out in
% two ways.
% 
% In many cases, choices execute similar code which is dependant only 
% on the name of the choice or the position of the choice in the
% list of choices. Here, the keys can share the same code, and can
% be rapidly created using the  \texttt{.choice_code:n} and
% \texttt{.generate_choices:n} properties:
%\begin{verbatim}
%  \keys_define:nn { module } {
%    key .choice_code:n      = {
%      You~gave~choice~``\int_use:N \l_keys_choice_tl'',~
%      which~is~in~position~
%      \int_use:N\l_keys_choice_int\space
%      in~the~list.
%    },
%    key .generate_choices:n = {
%      choice-a, choice-b, choice-c
%    } 
%  }
%\end{verbatim}
% Following common computing practice, \cs{l_keys_choice_int} is
% indexed from \(0\) (as an offset), so that the value of
% \cs{l_keys_choice_int} for the first choice in a list will be
% zero. This means that \cs{l_keys_choice_int} can be used directly 
% with \cs{if_case:w} and so on.
% 
%\begin{variable}{
%  \l_keys_choice_int |
%  \l_keys_choice_tl
%}
%  Inside the code block for a choice generated using
%  \texttt{.generate_choice:}, the variables \cs{l_keys_choice_tl} and
%  \cs{l_keys_choice_int} are available to indicate the name of the
%  current choice, and its position in the comma list.  The position
%  is indexed from \(0\).
%\end{variable}
%
% On the other hand, it is sometimes useful to create choices which
% use entirely different code from one another. This can be achieved
% by setting the \texttt{.choice:} property of a key, then manually
% defining sub-keys.
%\begin{verbatim}
%  \keys_define:nn { module } {
%    key .choice:n,
%    key / choice-a .code:n = code-a,
%    key / choice-b .code:n = code-b,
%    key / choice-c .code:n = code-c,
%  }
%\end{verbatim}
%
% It is possible to mix the two methods, but manually-created choices
% should \emph{not} use \cs{l_keys_choice_tl} or \cs{l_keys_choice_int}.
% These variables do not have defined behaviour when used outside of
% code created using \texttt{.generate_choices:n} 
% (\emph{i.e}.~anything might happen!).
%
%\section{Setting keys}
%
%\begin{function}{
%  \keys_set:nn |
%  \keys_set:nV |
%  \keys_set:nv
%}
%  \begin{syntax}
%    "\keys_set:nn" \Arg{module} \Arg{keyval list}
%  \end{syntax}
%  Parses the <keyval list>, and sets those keys which are defined
%  for <module>. The behaviour on finding an unknown key can be
%  set by defining a special \texttt{unknown} key: this will be 
%  illustrated later. In contrast to \cs{keys_define:nn}, this function
%  does check category codes and ignore spaces, and is therefore 
%  suitable for user input.
%\end{function}
%
% If a key is not known, \cs{keys_set:nn} will look for a special
% \texttt{unknown} key for the same module. This mechanism can be
% used to create new keys from user input.
%\begin{verbatim}
%  \keys_define:nn { module } {
%    unknown .code:n = 
%      You~tried~to~set~key~'\l_keys_path_tl'~to~'#1'
%  }
%\end{verbatim}
%
%\begin{variable}{\l_keys_key_tl}
%  When processing an unknown key, the name of the key is available
%  as \cs{l_keys_key_tl}. Note that this will have been processed
%  using \cs{tl_to_str:N}. The value passed to the key (if any) is
%  available as the macro parameter "#1".
%\end{variable}
% 
%\subsection{Examining keys: internal representation}
%
%\begin{function}{\keys_if_exist:nn / (TF)}
%  \begin{syntax}
%    "\keys_if_exist:nnTF" \Arg{module} \Arg{key} \Arg{true code} 
%    ~~~~\Arg{false code}
%  \end{syntax}
%  Tests if <key> exists for <module>, \emph{i.e}.~if any code has 
%  been defined for <key>.
%  \begin{texnote}
%    The function works by testing for the existence of the internal 
%    function \cs{keys > <module>/<key>.cmd:n}.
%  \end{texnote}
%\end{function}
%
%\begin{function}{\keys_show:nn}
%  \begin{syntax}
%    "\keys_show:nn" \Arg{module} \Arg{key}
%  \end{syntax}
%  Shows the internal representation of a <key>.
%  \begin{texnote}
%    Keys are stored as functions with names of the format
%    \cs{keys > <module>/<key>.cmd:n}.
%  \end{texnote}
%\end{function}
% 
%\section{Internal functions}
%
%\begin{function}{\keys_bool_set:NN}
%   \begin{syntax}
%     "\keys_bool_set:NN" <bool> <scope>
%   \end{syntax}
%   Creates code to set <bool> when <key> is given, with setting using
%   <scope> (\texttt{l} or \texttt{g} for local or global, 
%   respectively). <bool> should be a \LaTeX3 boolean variable.
%\end{function}
%
%\begin{function}{\keys_choice_code_store:x}
%   \begin{syntax}
%     "\keys_choice_code_store:x" <code>
%   \end{syntax}
%   Stores <code> for later use by \texttt{.generate_code:n}.
%\end{function}
%
%\begin{function}{\keys_choice_make:}
%   \begin{syntax}
%     "\keys_choice_make:" 
%   \end{syntax}
%   Makes <key> a choice key.
%\end{function}
%
%\begin{function}{\keys_choices_generate:n}
%   \begin{syntax}
%     "\keys_choices_generate:n" \Arg{comma list}
%   \end{syntax}
%   Makes <comma list> choices for <key>.
%\end{function}
%
%\begin{function}{\keys_choice_find:n}
%   \begin{syntax}
%     "\keys_choice_find:n" \Arg{choice}
%   \end{syntax}
%   Searches for <choice> as a sub-key of <key>.
%\end{function}
%
%\begin{function}{
%    \keys_cmd_set:nn |
%    \keys_cmd_set:nx
%}
%   \begin{syntax}
%     "\keys_cmd_set:nn" \Arg{path} \Arg{code}
%   \end{syntax}
%   Creates a function for <path> using <code>.
%\end{function}
%
%\begin{function}{
%    \keys_default_set:n |
%    \keys_default_set:V
%}
%   \begin{syntax}
%     "\keys_default_set:n" \Arg{default}
%   \end{syntax}
%   Sets <default> for <key>.
%\end{function}
%
%\begin{function}{
%    \keys_define_elt:n |
%    \keys_define_elt:nn
%}
%   \begin{syntax}
%     "\keys_define_elt:nn" \Arg{key} \Arg{value}
%   \end{syntax}
%   Processing functions for key--value pairs when defining keys.
%\end{function}
%
%\begin{function}{\keys_define_key:n}
%   \begin{syntax}
%     "\keys_define_key:n" \Arg{key}
%   \end{syntax}
%   Defines <key>.
%\end{function}
%
%\begin{function}{\keys_execute:}
%   \begin{syntax}
%     "\keys_execute:" 
%   \end{syntax}
%   Executes <key> (where the name of the <key> will be stored 
%   internally).
%\end{function}
%
%\begin{function}{\keys_execute_unknown:}
%   \begin{syntax}
%     "\keys_execute_unknown:" 
%   \end{syntax}
%   Handles unknown <key> names.
%\end{function}
%
%\begin{function}{\keys_if_value_requirement:nTF / (EXP)}
%   \begin{syntax}
%     "\keys_if_value_requirement:nTF" \Arg{requirement}
%     ~~~~\Arg{true code} \Arg{false code}
%   \end{syntax}
%   Check if <requirement> applies to <key>.
%\end{function}
%
%\begin{function}{
%  \keys_meta_make:n |
%  \keys_meta_make:x
%}
%   \begin{syntax}
%     "\keys_meta_make:n" \Arg{keys}
%   \end{syntax}
%   Makes <key> a meta-key to set <keys>.
%\end{function}
%
%\begin{function}{\keys_property_find:n}
%   \begin{syntax}
%     "\keys_property_find:n" \Arg{key}
%   \end{syntax}
%   Separates <key> from <property>.
%\end{function}
%
%\begin{function}{
%  \keys_property_new:nn      |
%  \keys_property_new_arg:nn
%}
%   \begin{syntax}
%     "\keys_property_new:nn" \Arg{property} \Arg{code}
%   \end{syntax}
%   Makes a new <property> expanding to <code>. The \texttt{arg}
%   version makes properties with one argument.
%\end{function}
%
%\begin{function}{\keys_property_undefine:n}
%   \begin{syntax}
%     "\keys_property_undefine:n" \Arg{property}
%   \end{syntax}
%   Deletes <property> of <key>.
%\end{function}
%
%\begin{function}{
%    \keys_set_elt:n  |
%    \keys_set_elt:nn 
%}
%   \begin{syntax}
%     "\keys_set_elt:nn" \Arg{key} \Arg{value}
%   \end{syntax}
%   Processing functions for key--value pairs when setting keys.
%\end{function}
%
%\begin{function}{\keys_tmp:w}
%   \begin{syntax}
%     "\keys_tmp:w" <args>
%   \end{syntax}
%   Used to store <code> to execute a <key>.
%\end{function}
%
%\begin{function}{\keys_value_or_default:n}
%   \begin{syntax}
%     "\keys_value_or_default:n" \Arg{value}
%   \end{syntax}
%   Sets \cs{l_keys_value_tl} to <value>, or <default> if
%   <value> was not given and if <default> is available.
%\end{function}
%
%\begin{function}{\keys_value_requirement:n}
%   \begin{syntax}
%     "\keys_value_requirement:n" \Arg{requirement}
%   \end{syntax}
%   Sets <key> to have <requirement> concerning <value>.
%\end{function}
%
%\begin{function}{
%  \keys_variable_set:NnNN |
%  \keys_variable_set:cnNN |
%}
%   \begin{syntax}
%     "\keys_variable_set:NnNN" <var> <type> <scope> <expansion>
%   \end{syntax}
%   Sets <key> to assign <value> to <variable>. The <scope> (blank
%   for local, \texttt{g} for global) and <type> (\texttt{tl},
%   \texttt{int}, etc.) are given explicitly.
%\end{function}
% 
%\section{Variables and constants}
%
%\begin{variable}{
%  \c_keys_properties_root_tl |
%  \c_keys_root_tl
%}
%  The root paths for keys and properties, used to generate the
%  names of the functions which store these items.
%\end{variable}
% 
%\begin{variable}{
%  \c_keys_value_forbidden_tl |
%  \c_keys_value_required_tl
%}
%  Marker text containers: by storing the values the code can make
%  comparisons slightly faster. 
%\end{variable}
%
%\begin{variable}{\l_keys_choice_code_tl}
%  Used to transfer code from storage when making multiple choices.
%\end{variable}
% 
%\begin{variable}{
%  \l_keys_module_tl   |
%  \l_keys_path_tl     |
%  \l_keys_property_tl
%}
%  Various key paths need to be stored. These are flexible items 
%  that are set during the key reading process.
%\end{variable}
%
%\begin{variable}{\l_keys_no_value_bool}
%  A marker for `no value' as key input.
%\end{variable}
%
%\begin{variable}{\l_keys_value_tl}
%  Holds the currently supplied value, in a token register as 
%  there may be "#" tokens.
%\end{variable}
% 
%\end{documentation}
% 
%\begin{implementation}
%
% The usual preliminaries.  
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage
  {\filename}{\filedate}{\fileversion}{\filedescription}
\package_check_loaded_expl:
%</package>
%<*initex|package>
%    \end{macrocode}
%
%\subsubsection{Variables and constants}
%
%\begin{macro}{\c_keys_root_tl}
%\begin{macro}{\c_keys_properties_root_tl}
% Where the keys are really stored.
%    \begin{macrocode}
\tl_const:Nn \c_keys_root_tl { keys~>~ }
\tl_const:Nn \c_keys_properties_root_tl { keys_properties }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\c_keys_value_forbidden_tl}
%\begin{macro}{\c_keys_value_required_tl}
% Two marker token lists.
%    \begin{macrocode}
\tl_const:Nn \c_keys_value_forbidden_tl { forbidden }
\tl_const:Nn \c_keys_value_required_tl { required }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\l_keys_choice_int}
%\begin{macro}{\l_keys_choice_tl}
% Used for the multiple choice system.
%    \begin{macrocode}
\int_new:N \l_keys_choice_int
\tl_new:N \l_keys_choice_tl
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\l_keys_choice_code_tl}
% When creating multiple choices, the code is stored here.
%    \begin{macrocode}
\tl_new:N \l_keys_choice_code_tl
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\l_keys_key_tl}
%\begin{macro}{\l_keys_path_tl}
%\begin{macro}{\l_keys_property_tl}
% Storage for the current key name and the path of the key (key name 
% plus module name).
%    \begin{macrocode}
\tl_new:N \l_keys_key_tl
\tl_new:N \l_keys_path_tl
\tl_new:N \l_keys_property_tl
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\l_keys_module_tl}
% The module for an entire set of keys.
%    \begin{macrocode}
\tl_new:N \l_keys_module_tl
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\l_keys_no_value_bool}
% To indicate that no value has been given.
%    \begin{macrocode}
\bool_new:N \l_keys_no_value_bool
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\l_keys_value_tl}
% A token variable for the given value.
%    \begin{macrocode}
\tl_new:N \l_keys_value_tl
%    \end{macrocode}
%\end{macro}
%
%\subsubsection{Internal functions}
%
%\begin{macro}{\keys_bool_set:NN}
% Boolean keys are really just choices, but all done by hand.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_bool_set:NN #1#2 {
  \keys_cmd_set:nx { \l_keys_path_tl / true } {
    \exp_not:c { bool_ #2 set_true:N } 
      \exp_not:N #1
  }
  \keys_cmd_set:nx { \l_keys_path_tl / false } {
    \exp_not:N \use:c 
      { bool_ #2 set_false:N } 
      \exp_not:N #1
  }
  \keys_choice_make:
  \cs_if_exist:NF #1 {
    \bool_new:N #1
  }
  \keys_default_set:n { true }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_choice_code_store:x}
% The code for making multiple choices is stored in a token list as there should
% not be any "#" tokens.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_choice_code_store:x #1 {
  \tl_set:cx { \c_keys_root_tl \l_keys_path_tl .choice_code_tl } {#1}
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_choice_find:n}
% Executing a choice has two parts. First, try the choice given, then
% if that fails call the unknown key. That will exist, as it is created
% when a choice is first made. So there is no need for any escape code.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_choice_find:n #1 {
  \keys_execute_aux:nn { \l_keys_path_tl / #1 } {
    \keys_execute_aux:nn { \l_keys_path_tl / unknown } { }
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_choice_make:}
% To make a choice from a key, two steps: set the code, and set the 
% unknown key.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_choice_make: {
  \keys_cmd_set:nn { \l_keys_path_tl } {
    \keys_choice_find:n {##1}
  }
  \keys_cmd_set:nn { \l_keys_path_tl / unknown } {
    \msg_kernel_error:nnxx { keys } { choice-unknown } 
      { \l_keys_path_tl } {##1} 
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_choices_generate:n}
%\begin{macro}[aux]{\keys_choices_generate_aux:n}
% Creating multiple-choices means setting up the ``indicator'' code,
% then applying whatever the user wanted.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_choices_generate:n #1 {
  \keys_choice_make:
  \int_zero:N \l_keys_choice_int
  \cs_if_exist:cTF { 
    \c_keys_root_tl \l_keys_path_tl .choice_code_tl 
  } {
    \tl_set:Nv \l_keys_choice_code_tl {
      \c_keys_root_tl \l_keys_path_tl .choice_code_tl
    }
  }{
    \msg_kernel_error:nnx { keys } { generate-choices-before-code } 
      { \l_keys_path_tl }
  }
  \clist_map_function:nN {#1} \keys_choices_generate_aux:n 
}
\cs_new_protected_nopar:Npn \keys_choices_generate_aux:n #1 {
  \keys_cmd_set:nx { \l_keys_path_tl / #1 } {
    \exp_not:n { \tl_set:Nn \l_keys_choice_tl } {#1}
    \exp_not:n { \int_set:Nn \l_keys_choice_int }
      { \int_use:N \l_keys_choice_int }
    \exp_not:V \l_keys_choice_code_tl
  }
  \int_incr:N \l_keys_choice_int
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\keys_cmd_set:nn}
%\begin{macro}{\keys_cmd_set:nx}
%\begin{macro}[aux]{\keys_cmd_set_aux:n}
% Creating a new command means setting properties and then creating
% a function with the correct number of arguments.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_cmd_set:nn #1#2 {
  \keys_cmd_set_aux:n {#1}
  \cs_generate_from_arg_count:cNnn { \c_keys_root_tl #1 .cmd:n } 
    \cs_set:Npn 1 {#2}
}
\cs_new_protected:Npn \keys_cmd_set:nx #1#2 {
  \keys_cmd_set_aux:n {#1} 
  \cs_generate_from_arg_count:cNnn { \c_keys_root_tl #1 .cmd:n } 
    \cs_set:Npx 1 {#2}
}
\cs_new_protected_nopar:Npn \keys_cmd_set_aux:n #1 {
  \keys_property_undefine:n { #1 .default_tl }
  \cs_if_free:cT { \c_keys_root_tl #1 .req_tl }
    { \tl_new:c { \c_keys_root_tl #1 .req_tl } }
  \tl_clear:c { \c_keys_root_tl #1 .req_tl }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\keys_default_set:n}
%\begin{macro}{\keys_default_set:V}
% Setting a default value is easy.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_default_set:n #1 {
  \cs_if_free:cT { \c_keys_root_tl \l_keys_path_tl .default_tl }
    { \tl_new:c { \c_keys_root_tl \l_keys_path_tl .default_tl } }
  \tl_set:cn { \c_keys_root_tl \l_keys_path_tl .default_tl } {#1}
}
\cs_generate_variant:Nn \keys_default_set:n { V }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\keys_define:nn}
% The main key-defining function mainly sets up things for \pkg{l3keyval}
% to use.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_define:nn #1#2 {
  \tl_set:Nn \l_keys_module_tl {#1}
  \KV_process_no_space_removal_no_sanitize:NNn 
    \keys_define_elt:n \keys_define_elt:nn {#2}
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_define_elt:n}
%\begin{macro}{\keys_define_elt:nn}
% The element processors for defining keys.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_define_elt:n #1 {
  \bool_set_true:N \l_keys_no_value_bool
  \keys_define_elt_aux:nn {#1} { }
}
\cs_new_protected:Npn \keys_define_elt:nn #1#2 {
  \bool_set_false:N \l_keys_no_value_bool
  \keys_define_elt_aux:nn {#1} {#2}
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\begin{macro}[aux]{\keys_define_elt_aux:nn}
% The auxiliary function does most of the work.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_define_elt_aux:nn #1#2 {
  \keys_property_find:n {#1}
  \cs_set_eq:Nc \keys_tmp:w 
    { \c_keys_properties_root_tl \l_keys_property_tl }
  \cs_if_exist:NTF \keys_tmp:w {
    \keys_define_key:n {#2}
  }{
    \msg_kernel_error:nnxx { keys } { property-unknown } 
      { \l_keys_property_tl } { \l_keys_path_tl }
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_define_key:n}
% Defining a new key means finding the code for the appropriate 
% property then running it. As properties have signatures, a check
% can be made for required values without needing anything set
% explicitly.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_define_key:n #1 {
  \bool_if:NTF \l_keys_no_value_bool {
    \intexpr_compare:nTF { 
      \exp_args:Nc \cs_get_arg_count_from_signature:N 
        { \l_keys_property_tl } = \c_zero
    } {
      \keys_tmp:w 
    }{
      \msg_kernel_error:nnxx { key } { property-requires-value } 
        { \l_keys_property_tl } { \l_keys_path_tl }
    }  
  }{
    \keys_tmp:w {#1} 
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_execute:}
%\begin{macro}{\keys_execute_unknown:}
%\begin{macro}[aux]{\keys_execute_aux:nn}
% Actually executing a key is done in two parts. First, look for the
% key itself, then look for the \texttt{unknown} key with the same
% path. If both of these fail, complain!
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_execute: {
  \keys_execute_aux:nn { \l_keys_path_tl } {
    \keys_execute_unknown:
  }
}
\cs_new_protected_nopar:Npn \keys_execute_unknown: {
  \keys_execute_aux:nn { \l_keys_module_tl / unknown } {
    \msg_kernel_error:nnxx { keys } { key-unknown } { \l_keys_path_tl }
      { \l_keys_module_tl }
  }
}
%    \end{macrocode}
% If there is only one argument required, it is wrapped in braces so
% that everything is passed through properly. On the other hand, if more
% than one is needed it is down to the user to have put things in 
% correctly! The use of \cs{q_keys_stop} here means that arguments
% do not run away (hence the nine empty groups), but that the module
% can clean up the spare groups at the end of executing the key.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_execute_aux:nn #1#2 {
  \cs_set_eq:Nc \keys_tmp:w { \c_keys_root_tl #1 .cmd:n }
  \cs_if_exist:NTF \keys_tmp:w {
    \exp_args:NV \keys_tmp:w \l_keys_value_tl
  }{
    #2
  }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}[TF]{\keys_if_exist:nn}
% A check for the existance of a key. This works by looking for the
% command function for the key (which ends \texttt{.cmd:n}).
%    \begin{macrocode}
\prg_set_conditional:Nnn \keys_if_exist:nn {TF,T,F} {
  \cs_if_exist:cTF { \c_keys_root_tl #1 / #2 .cmd:n } {
    \prg_return_true:
  }{
    \prg_return_false:
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_if_value_requirement:nTF}
% To test if a value is required or forbidden. Only one version is
% needed, so done by hand.
%    \begin{macrocode}
\cs_new_nopar:Npn \keys_if_value_requirement:nTF #1 {
  \tl_if_eq:ccTF { c_keys_value_ #1 _tl } {
    \c_keys_root_tl \l_keys_path_tl .req_tl
  } 
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_meta_make:n}
%\begin{macro}{\keys_meta_make:x}
% To create a met-key, simply set up to pass data through.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_meta_make:n #1 {
  \exp_last_unbraced:NNo \keys_cmd_set:nn \l_keys_path_tl 
    \exp_after:wN { \exp_after:wN \keys_set:nn  \exp_after:wN { \l_keys_module_tl } {#1} }
}
\cs_new_protected_nopar:Npn \keys_meta_make:x #1 {
  \keys_cmd_set:nx { \l_keys_path_tl } {
    \exp_not:N \keys_set:nn { \l_keys_module_tl } {#1}
  }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\keys_property_find:n}
%\begin{macro}[aux]{\keys_property_find_aux:n}
%\begin{macro}[aux]{\keys_property_find_aux:w}
% Searching for a property means finding the last ``\texttt{.}'' in
% the input, and storing the text before and after it.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_property_find:n #1 {
  \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / }
  \tl_if_in:nnTF {#1} {.} {
    \keys_property_find_aux:n {#1}
  }{
    \msg_kernel_error:nnx { keys } { key-no-property } {#1}
  }
}
\cs_new_protected_nopar:Npn \keys_property_find_aux:n #1 {
  \keys_property_find_aux:w #1 \q_stop
}
\cs_new_protected_nopar:Npn \keys_property_find_aux:w #1 . #2 \q_stop {
  \tl_if_in:nnTF {#2} { . } {
    \tl_set:Nx \l_keys_path_tl { 
      \l_keys_path_tl \tl_to_str:n {#1} .
    }
    \keys_property_find_aux:w #2 \q_stop
  }{
    \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} }
    \tl_set:Nn \l_keys_property_tl { . #2 }
  }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\keys_property_new:nn}
%\begin{macro}{\keys_property_new_arg:nn}
% Creating a new property is simply a case of making the correctly-named
% function.
%    \begin{macrocode}
\cs_new_nopar:Npn \keys_property_new:nn #1#2 {
  \cs_new:cpn { \c_keys_properties_root_tl #1 } {#2}
}
\cs_new_protected_nopar:Npn \keys_property_new_arg:nn #1#2 {
  \cs_new:cpn { \c_keys_properties_root_tl #1 } ##1 {#2}
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\keys_property_undefine:n}
% Removing a property means undefining it.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_property_undefine:n #1 {
  \cs_set_eq:cN { \c_keys_root_tl #1 } \c_undefined
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_set:nn}
%\begin{macro}{\keys_set:nV}
%\begin{macro}{\keys_set:nv}
% The main setting function just does the set up to get \pkg{l3keyval}
% to do the hard work.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_set:nn #1#2 {
  \tl_set:Nn \l_keys_module_tl {#1}
  \KV_process_space_removal_sanitize:NNn 
    \keys_set_elt:n \keys_set_elt:nn {#2}
}
\cs_generate_variant:Nn \keys_set:nn { nV, nv }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\keys_set_elt:n}
%\begin{macro}{\keys_set_elt:nn}
% The two element processors are almost identical, and pass the data 
% through to the underlying auxiliary, which does the work.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_set_elt:n #1 {
  \bool_set_true:N \l_keys_no_value_bool
  \keys_set_elt_aux:nn {#1} { }
}
\cs_new_protected:Npn \keys_set_elt:nn #1#2 {
  \bool_set_false:N \l_keys_no_value_bool
  \keys_set_elt_aux:nn {#1} {#2}
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\begin{macro}[aux]{\keys_set_elt_aux:nn}
%\begin{macro}[aux]{\keys_set_elt_aux:}
% First, set the current path and add a default if needed. There are 
% then checks to see if the a value is required or forbidden. If 
% everything passes, move on to execute the code.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_set_elt_aux:nn #1#2 {
  \tl_set:Nx \l_keys_key_tl { \tl_to_str:n {#1} }
  \tl_set:Nx \l_keys_path_tl { \l_keys_module_tl / \l_keys_key_tl }
  \keys_value_or_default:n {#2}
  \keys_if_value_requirement:nTF { required } {
    \bool_if:NTF \l_keys_no_value_bool {
      \msg_kernel_error:nnx  { keys } { value-required } 
        { \l_keys_path_tl }
    }{
      \keys_set_elt_aux:
    }
  }{
    \keys_set_elt_aux:
  } 
}
\cs_new_protected_nopar:Npn \keys_set_elt_aux: {
  \keys_if_value_requirement:nTF { forbidden } {
    \bool_if:NTF \l_keys_no_value_bool {
      \keys_execute:
    }{
      \msg_kernel_error:nnxx { keys } { value-forbidden } 
        { \l_keys_path_tl } { \tl_use:N \l_keys_value_tl }
    }
  }{
    \keys_execute:
  }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\keys_show:nn}
% Showing a key is just a question of using the correct name.
%    \begin{macrocode}
\cs_new_nopar:Npn \keys_show:nn #1#2 {
  \cs_show:c { \c_keys_root_tl #1 / \tl_to_str:n {#2} .cmd:n }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_tmp:w}
% This scratch function is used to actually execute keys.
%    \begin{macrocode}
\cs_new:Npn \keys_tmp:w {}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_value_or_default:n}
% If a value is given, return it as "#1", otherwise send a default if
% available.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_value_or_default:n #1 {
  \tl_set:Nn \l_keys_value_tl  {#1}
  \bool_if:NT \l_keys_no_value_bool {
    \cs_if_exist:cT { \c_keys_root_tl \l_keys_path_tl .default_tl } {
      \tl_set:Nv \l_keys_value_tl  { 
        \c_keys_root_tl \l_keys_path_tl .default_tl 
      }
    }
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_value_requirement:n}
% Values can be required or forbidden by having the appropriate marker
% set.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_value_requirement:n #1 { 
  \tl_set_eq:cc { \c_keys_root_tl \l_keys_path_tl .req_tl } 
    { c_keys_value_ #1 _tl }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\keys_variable_set:NnNN}
%\begin{macro}{\keys_variable_set:cnNN}
% Setting a variable takes the type and scope separately so that 
% it is easy to make a new variable if needed.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \keys_variable_set:NnNN #1#2#3#4 {
  \cs_if_exist:NF #1 {
    \use:c { #2 _new:N } #1
  }
  \keys_cmd_set:nx { \l_keys_path_tl } {
    \exp_not:c { #2 _ #3 set:N #4 } \exp_not:N #1 {##1}
  }
}
\cs_generate_variant:Nn \keys_variable_set:NnNN { c }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\subsubsection{Properties}
%
%\begin{macro}{.bool_set:N}
%\begin{macro}{.bool_gset:N}
% One function for this.
%    \begin{macrocode}
\keys_property_new_arg:nn { .bool_set:N } {
  \keys_bool_set:NN #1 { }
}
\keys_property_new_arg:nn { .bool_gset:N } {
  \keys_bool_set:NN #1 n
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.choice:}
% Making a choice is handled internally, as it is also needed by
% \texttt{.generate_choices:n}.
%    \begin{macrocode}
\keys_property_new:nn { .choice: } {
  \keys_choice_make:
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{.choice_code:n}
%\begin{macro}{.choice_code:x}
% Storing the code for choices, using \cs{exp_not:n} to avoid needing
% two internal functions.
%    \begin{macrocode}
\keys_property_new_arg:nn { .choice_code:n } {
  \keys_choice_code_store:x { \exp_not:n {#1} }
}
\keys_property_new_arg:nn { .choice_code:x } {
  \keys_choice_code_store:x {#1}
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.code:n}
%\begin{macro}{.code:x}
% Creating code is simply a case of passing through to the underlying
% \texttt{set} function.
%    \begin{macrocode}
\keys_property_new_arg:nn { .code:n } {
  \keys_cmd_set:nn { \l_keys_path_tl } {#1}
}
\keys_property_new_arg:nn { .code:x } {
  \keys_cmd_set:nx { \l_keys_path_tl } {#1}
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.default:n}
%\begin{macro}{.default:V}
% Expansion is left to the internal functions.
%    \begin{macrocode}
\keys_property_new_arg:nn { .default:n } {
  \keys_default_set:n  {#1} 
}
\keys_property_new_arg:nn { .default:V } {
  \keys_default_set:V #1
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.dim_set:N}
%\begin{macro}{.dim_set:c}
%\begin{macro}{.dim_gset:N}
%\begin{macro}{.dim_gset:c}
% Setting a variable is very easy: just pass the data along.
%    \begin{macrocode}
\keys_property_new_arg:nn { .dim_set:N } {
  \keys_variable_set:NnNN #1 { dim } { } n
}
\keys_property_new_arg:nn { .dim_set:c } {
  \keys_variable_set:cnNN {#1} { dim } { } n
}
\keys_property_new_arg:nn { .dim_gset:N } {
  \keys_variable_set:NnNN #1 { dim } g n
}
\keys_property_new_arg:nn { .dim_gset:c } {
  \keys_variable_set:cnNN {#1} { dim } g n
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.generate_choices:n}
% Making choices is easy.
%    \begin{macrocode}
\keys_property_new_arg:nn { .generate_choices:n } {
  \keys_choices_generate:n {#1}
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{.int_set:N}
%\begin{macro}{.int_set:c}
%\begin{macro}{.int_gset:N}
%\begin{macro}{.int_gset:c}
% Setting a variable is very easy: just pass the data along.
%    \begin{macrocode}
\keys_property_new_arg:nn { .int_set:N } {
  \keys_variable_set:NnNN #1 { int } { } n
}
\keys_property_new_arg:nn { .int_set:c } {
  \keys_variable_set:cnNN {#1} { int } { } n
}
\keys_property_new_arg:nn { .int_gset:N } {
  \keys_variable_set:NnNN #1 { int } g n
}
\keys_property_new_arg:nn { .int_gset:c } {
  \keys_variable_set:cnNN {#1} { int } g n
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.meta:n}
%\begin{macro}{.meta:x}
% Making a meta is handled internally.
%    \begin{macrocode}
\keys_property_new_arg:nn { .meta:n } {
  \keys_meta_make:n {#1}
}
\keys_property_new_arg:nn { .meta:x } {
  \keys_meta_make:x {#1}
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.skip_set:N}
%\begin{macro}{.skip_set:c}
%\begin{macro}{.skip_gset:N}
%\begin{macro}{.skip_gset:c}
% Setting a variable is very easy: just pass the data along.
%    \begin{macrocode}
\keys_property_new_arg:nn { .skip_set:N } {
  \keys_variable_set:NnNN #1 { skip } { } n
}
\keys_property_new_arg:nn { .skip_set:c } {
  \keys_variable_set:cnNN {#1} { skip } { } n
}
\keys_property_new_arg:nn { .skip_gset:N } {
  \keys_variable_set:NnNN #1 { skip } g n
}
\keys_property_new_arg:nn { .skip_gset:c } {
  \keys_variable_set:cnNN {#1} { skip } g n
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.tl_set:N}
%\begin{macro}{.tl_set:c}
%\begin{macro}{.tl_set_x:N}
%\begin{macro}{.tl_set_x:c}
%\begin{macro}{.tl_gset:N}
%\begin{macro}{.tl_gset:c}
%\begin{macro}{.tl_gset_x:N}
%\begin{macro}{.tl_gset_x:c}
% Setting a variable is very easy: just pass the data along.
%    \begin{macrocode}
\keys_property_new_arg:nn { .tl_set:N } {
  \keys_variable_set:NnNN #1 { tl } { } n
}
\keys_property_new_arg:nn { .tl_set:c } {
  \keys_variable_set:cnNN {#1} { tl } { } n
}
\keys_property_new_arg:nn { .tl_set_x:N } {
  \keys_variable_set:NnNN #1 { tl } { } x
}
\keys_property_new_arg:nn { .tl_set_x:c } {
  \keys_variable_set:cnNN {#1} { tl } { } x
}
\keys_property_new_arg:nn { .tl_gset:N } {
  \keys_variable_set:NnNN #1 { tl } g n
}
\keys_property_new_arg:nn { .tl_gset:c } {
  \keys_variable_set:cnNN {#1} { tl } g n
}
\keys_property_new_arg:nn { .tl_gset_x:N } {
  \keys_variable_set:NnNN #1 { tl } g x
}
\keys_property_new_arg:nn { .tl_gset_x:c } {
  \keys_variable_set:cnNN {#1} { tl } g x
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{.value_forbidden:}
%\begin{macro}{.value_required:}
% These are very similar, so both call the same function.
%    \begin{macrocode}
\keys_property_new:nn { .value_forbidden: } {
  \keys_value_requirement:n { forbidden }
}
\keys_property_new:nn { .value_required: } {
  \keys_value_requirement:n { required } 
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\subsubsection{Messages}
%
% For when there is a need to complain.
%    \begin{macrocode}
\msg_kernel_new:nnnn { keys } { choice-unknown } 
  { Choice~'#2'~unknown~for~key~'#1'. }
  {
    The~key~'#1'~takes~a~limited~number~of~values.\\
    The~input~given,~'#2',~is~not~on~the~list~accepted.
  }
\msg_kernel_new:nnnn { keys } { generate-choices-before-code } 
  { No~code~available~to~generate~choices~for~key~'#1'. }
  { 
    \l_msg_coding_error_text_tl
    Before~using~.generate_choices:n~the~code~should~be~defined\\%
    with~.choice_code:n~or~.choice_code:x.
  }
\msg_kernel_new:nnnn { keys } { key-no-property } 
  { No~property~given~in~definition~of~key~'#1'. }
  {
    \c_msg_coding_error_text_tl
    Inside~\token_to_str:N \keys_define:nn \c_space_tl each~key~name
    needs~a~property:  \\
    ~ ~ #1 .<property> \\
    LaTeX~did~not~find~a~'.'~to~indicate~the~start~of~a~property.
  }
\msg_kernel_new:nnnn { keys } { key-unknown } 
  { The~key~'#1'~is~unknown~and~is~being~ignored. }
  {
    The~module~'#2'~does~not~have~a~key~called~#1'.\\
    Check~that~you~have~spelled~the~key~name~correctly.
  }
\msg_kernel_new:nnnn { keys } { property-requires-value } 
  { The~property~'#1'~requires~a~value. }
  {
    \l_msg_coding_error_text_tl
    LaTeX~was~asked~to~set~property~'#2'~for~key~'#1'.\\
    No~value~was~given~for~the~property,~and~one~is~required.
  }
\msg_kernel_new:nnnn { keys } { property-unknown } 
  { The~key~property~'#1'~is~unknown. }
  {
    \l_msg_coding_error_text_tl
    LaTeX~has~been~asked~to~set~the~property~'#1'~for~key~'#2':\\
    this~property~is~not~defined.
  }
\msg_kernel_new:nnnn { keys } { value-forbidden }
  { The~key~'#1'~does~not~taken~a~value. }
  { 
    The~key~'#1'~should~be~given~without~a~value.\\
    LaTeX~will~ignore~the~given~value~'#2'.
  }
\msg_kernel_new:nnnn { keys } { value-required }
  { The~key~'#1'~requires~a~value. }
  {
    The~key~'#1'~must~have~a~value.\\
    No~value~was~present:~the~key~will~be~ignored.
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
%\end{implementation}
