From dac945b204407dae96f70ec228206516093156d7 Mon Sep 17 00:00:00 2001
From: Karl Berry <karl@freefriends.org>
Date: Sun, 31 Jul 2011 18:27:06 +0000
Subject: l3kernel (5jun11)

git-svn-id: svn://tug.org/texlive/trunk@23282 c570f23f-e606-0410-a88d-b1316a301751
---
 Master/texmf-dist/source/latex/l3kernel/l3keys.dtx | 1365 ++++++++++++++++++++
 1 file changed, 1365 insertions(+)
 create mode 100644 Master/texmf-dist/source/latex/l3kernel/l3keys.dtx

(limited to 'Master/texmf-dist/source/latex/l3kernel/l3keys.dtx')

diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
new file mode 100644
index 00000000000..cbc1fb62a7d
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
@@ -0,0 +1,1365 @@
+% \iffalse meta-comment
+%
+%% File: l3keys.dtx Copyright (C) 2009-2011 The 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 LaTeX3 Project.
+%%
+%% -----------------------------------------------------------------------
+%
+%<*driver|package>
+\RequirePackage{l3names}
+\GetIdInfo$Id: l3keys.dtx 2478 2011-06-19 21:34:23Z joseph $
+  {L3 Experimental key-value interfaces}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\begin{document}
+  \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+%   The \pkg{l3keys} package\\ Key--value interfaces^^A
+%   \thanks{This file describes v\ExplFileVersion,
+%      last revised \ExplFileDate.}^^A
+% }
+%
+% \author{^^A
+%  The \LaTeX3 Project\thanks
+%    {^^A
+%      E-mail:
+%        \href{mailto:latex-team@latex-project.org}
+%          {latex-team@latex-project.org}^^A
+%    }^^A
+% }
+%
+% \date{Released \ExplFileDate}
+%
+% \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}
+%
+% The high level functions here are intended as a method to create
+% key--value controls. Keys are themselves created using a key--value
+% interface, minimising the number of functions and arguments
+% required. 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} will be used within a
+% document function, for example
+% \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
+% |/| is reserved for sub-division of keys into logical
+% groups. Functions and variables 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}
+%     \cs{keys_define:nn} \Arg{module} \Arg{keyval list}
+%   \end{syntax}
+%   Parses the \meta{keyval list} and defines the keys listed there for
+%   \meta{module}. The \meta{module} name should be a text value, but
+%   there are no restrictions on the nature of the text. In practice the
+%   \meta{module} should be chosen to be unique to the module in question
+%   (unless deliberately adding keys to an existing module).
+%
+%   The \meta{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 |.| after the key
+%   name.
+% \end{function}
+%
+% The various properties available take either no arguments at
+% all, or require exactly one argument. This is indicated in the
+% name of the property using an argument specification. In the following
+% discussion, each property is illustrated attached to an
+% arbitrary \meta{key}, which when used may be supplied with a
+% \meta{value}. All key \emph{definitions} are local.
+%
+% \begin{function}{.bool_set:N}
+%   \begin{syntax}
+%     \meta{key} .bool_set:N = \meta{boolean}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{boolean} to \meta{value} (which
+%   must be either \texttt{true} or \texttt{false}).  If the variable
+%   does not exist, it will be created at the point that the key is
+%   set up. The \meta{boolean} will be assigned locally.
+% \end{function}
+%
+% \begin{function}{.bool_gset:N}
+%   \begin{syntax}
+%     \meta{key} .bool_gset:N = \meta{boolean}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{boolean} to \meta{value} (which
+%   must be either \texttt{true} or \texttt{false}).  If the variable
+%   does not exist, it will be created at the point that the key is
+%   set up. The \meta{boolean} will be assigned globally.
+% \end{function}
+%
+% \begin{function}{.choice:}
+%   \begin{syntax}
+%     \meta{key} .choice:
+%   \end{syntax}
+%   Sets \meta{key} to act as a multiple choice key. Each valid choice
+%   for \meta{key} must then be created, as discussed in
+%   section~\ref{sec:choice}.
+% \end{function}
+%
+% \begin{function}{.choice_code:n, .choice_code:x}
+%   \begin{syntax}
+%     \meta{key} .choice_code:n = \meta{code}
+%   \end{syntax}
+%   Stores \meta{code} for use when \texttt{.generate_choices:n} creates
+%   one or more choice sub-keys of the current key. Inside \meta{code},
+%   \cs{l_keys_choice_tl} will expand to the name of the choice made, and
+%   \cs{l_keys_choice_int} will be 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}
+%     \meta{key} .code:n = \meta{code}
+%   \end{syntax}
+%   Stores the \meta{code} for execution when \meta{key} is used. The
+%   The \meta{code} can include one parameter ("#1"), which will be the
+%   \meta{value} given for the \meta{key}. The \texttt{x}-type variant
+%   will expand \meta{code} at the point  where the \meta{key} is
+%   created.
+% \end{function}
+%
+% \begin{function}{.default:n, .default:V}
+%   \begin{syntax}
+%     \meta{key} .default:n = \meta{default}
+%   \end{syntax}
+%   Creates a \meta{default} value for \meta{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 \meta{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}
+% \end{function}
+%
+% \begin{function}{.dim_set:N, .dim_set:c}
+%   \begin{syntax}
+%     \meta{key} .dim_set:N = \meta{dimension}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{dimension} to \meta{value} (which
+%   must a dimension expression).  If the variable does not exist, it
+%   will be created at the point that the key is set up. The
+%   \meta{dimension} will be assigned locally.
+% \end{function}
+%
+% \begin{function}{.dim_gset:N, .dim_gset:c}
+%   \begin{syntax}
+%     \meta{key} .dim_gset:N = \meta{dimension}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{dimension} to \meta{value} (which
+%   must a dimension expression).  If the variable does not exist, it
+%   will be created at the point that the key is set up. The
+%   \meta{dimension} will be assigned globally.
+% \end{function}
+%
+% \begin{function}{.fp_set:N, .fp_set:c}
+%   \begin{syntax}
+%     \meta{key} .fp_set:N = \meta{floating point}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{floating point} to \meta{value}
+%   (which must a integer expression).  If the variable does not exist,
+%   it will be created at the point that the key is set up. The
+%   \meta{integer} will be assigned locally.
+% \end{function}
+%
+% \begin{function}{.fp_gset:N, .fp_gset:c}
+%   \begin{syntax}
+%     \meta{key} .fp_gset:N = \meta{floating point}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{floating-point} to \meta{value}
+%   (which must a integer expression).  If the variable does not exist,
+%   it will be created at the point that the key is set up. The
+%   \meta{integer} will be assigned globally.
+% \end{function}
+%
+% \begin{function}{.generate_choices:n}
+%   \begin{syntax}
+%     \meta{key} .generate_choices:n = \Arg{list}
+%   \end{syntax}
+%   This property will mark \meta{key} as a multiple choice key,
+%   and will use the \meta{list} to define the choices. The \meta{list}
+%   should consist of a comma-separated list of choice names. Each
+%   choice will be set up to execute \meta{code} as set 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}
+%   \begin{syntax}
+%     \meta{key} .int_set:N = \meta{integer}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{integer} to \meta{value} (which
+%   must a integer expression).  If the variable does not exist, it
+%   will be created at the point that the key is set up. The
+%   \meta{integer} will be assigned locally.
+% \end{function}
+%
+% \begin{function}{.int_gset:N, .int_gset:c}
+%   \begin{syntax}
+%     \meta{key} .int_gset:N = \meta{integer}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{integer} to \meta{value} (which
+%   must a integer expression).  If the variable does not exist, it
+%   will be created at the point that the key is set up. The
+%   \meta{integer} will be assigned globally.
+% \end{function}
+%
+% \begin{function}{.meta:n, .meta:x}
+%   \begin{syntax}
+%     \meta{key} .meta:n = \Arg{keyval list}
+%   \end{syntax}
+%   Makes \meta{key} a meta-key, which will set \meta{keyval list} in
+%   one go.  If \meta{key} is given with a value at the time the key
+%   is used, then the value will be passed through to the subsidiary
+%   \meta{keys} for processing (as |#1|).
+% \end{function}
+%
+% \begin{function}{.skip_set:N, .skip_set:c}
+%   \begin{syntax}
+%     \meta{key} .skip_set:N = \meta{skip}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{skip} to \meta{value} (which
+%   must a skip expression). If the variable does not exist, it
+%   will be created at the point that the key is set up. The
+%   \meta{skip} will be assigned locally.
+% \end{function}
+%
+% \begin{function}{.skip_gset:N, .skip_gset:c}
+%   \begin{syntax}
+%     \meta{key} .skip_gset:N = \meta{skip}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{skip} to \meta{value} (which
+%   must a skip expression). If the variable does not exist, it
+%   will be created at the point that the key is set up. The
+%   \meta{skip} will be assigned globally.
+% \end{function}
+%
+% \begin{function}{.tl_set:N, .tl_set:c}
+%   \begin{syntax}
+%     \meta{key} .tl_set:N = \meta{token list variable}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{token list variable} to \meta{value}.
+%   If the variable does not exist, it will be created at the point that
+%   the key is set up. The \meta{token list variable} will be assigned
+%   locally.
+% \end{function}
+%
+% \begin{function}{.tl_gset:N, .tl_gset:c}
+%   \begin{syntax}
+%     \meta{key} .tl_gset:N = \meta{token list variable}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{token list variable} to \meta{value}.
+%   If the variable does not exist, it will be created at the point that
+%   the key is set up. The \meta{token list variable} will be assigned
+%   globally.
+% \end{function}
+%
+% \begin{function}{.tl_set_x:N, .tl_set_x:c}
+%   \begin{syntax}
+%     \meta{key} .tl_set_x:N = \meta{token list variable}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{token list variable} to \meta{value},
+%   which will be subjected to an \texttt{x}-type expansion
+%   (\emph{i.e.}~using \cs{tl_set:Nx}). If the variable does not exist,
+%   it will be created at the point that the key is set up. The
+%   \meta{token list variable} will be assigned locally.
+% \end{function}
+%
+% \begin{function}{.tl_gset_x:N, .tl_gset_x:c}
+%   \begin{syntax}
+%     \meta{key} .tl_gset_x:N = \meta{token list variable}
+%   \end{syntax}
+%   Defines \meta{key} to set \meta{token list variable} to \meta{value},
+%   which will be subjected to an \texttt{x}-type expansion
+%   (\emph{i.e.}~using \cs{tl_set:Nx}). If the variable does not exist,
+%   it will be created at the point that the key is set up. The
+%   \meta{token list variable} will be assigned globally.
+% \end{function}
+%
+% \begin{function}{.value_forbidden:}
+%   \begin{syntax}
+%     \meta{key} .value_forbidden:
+%   \end{syntax}
+%   Specifies that \meta{key} cannot receive a \meta{value} when used.
+%   If a \meta{value} is given then an error will be issued.
+% \end{function}
+%
+% \begin{function}{.value_required:}
+%   \begin{syntax}
+%      \meta{key} .value_required:
+%   \end{syntax}
+%   Specifies that \meta{key} must receive a \meta{value} when used.
+%   If a \meta{value} is not given then an error will be issued.
+% \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 |/|. 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.
+%
+% \section{Multiple choice keys}
+% \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 \c_space_tl
+%           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.
+%
+% \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, \keys_set:no}
+%   \begin{syntax}
+%     \cs{keys_set:nn} \Arg{module} \Arg{keyval list}
+%   \end{syntax}
+%   Parses the \meta{keyval list}, and sets those keys which are defined
+%   for \meta{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_key_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}
+%
+% \begin{variable}{\l_keys_path_tl}
+%   When processing an unknown key, the path of the key used is available
+%   as \cs{l_keys_path_tl}. Note that this will have been processed
+%   using \cs{tl_to_str:n}.
+% \end{variable}
+%
+% \section{Utility functions for keys}
+%
+% \begin{function}[EXP,pTF]{\keys_if_exist:nn}
+%   \begin{syntax}
+%     \cs{keys_if_exist:nn} \meta{module} \meta{key}
+%     \cs{keys_if_exist:nn} \meta{module} \meta{key}
+%     ~~\Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   Tests if the \meta{key} exists for \meta{module}, \emph{i.e.}~if any code
+%   has been defined for \meta{key}.
+%   The branching versions then leave either \meta{true code} or
+%   \meta{false code} in the input stream, as appropriate to the truth
+%   of the test and the variant of the function chosen. The logical
+%   truth of the test is left in the input stream by the predicate
+%   version.
+% \end{function}
+%
+% \begin{function}{\keys_show:nn}
+%   \begin{syntax}
+%     \cs{keys_show:nn} \Arg{module} \Arg{key}
+%   \end{syntax}
+%   Shows the function which is used to actually implement a
+%   \meta{key} for a \meta{module}.
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3keys} Implementation}
+%
+%    \begin{macrocode}
+%<*initex|package>
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<*package>
+\ProvidesExplPackage
+  {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\package_check_loaded_expl:
+%</package>
+%    \end{macrocode}
+%
+% \subsection{Constants and variables}
+%
+% \begin{variable}{\c_keys_code_root_tl, \c_keys_vars_root_tl}
+%   The prefixes for the code and variables of the keys themselves.
+%    \begin{macrocode}
+\tl_const:Nn \c_keys_code_root_tl { key~code~>~ }
+\tl_const:Nn \c_keys_vars_root_tl { key~var~>~ }
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_keys_props_root_tl}
+%   The prefix for storing properties.
+%    \begin{macrocode}
+\tl_const:Nn \c_keys_props_root_tl { key~prop~>~ }
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_keys_value_forbidden_tl, \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{variable}
+%
+% \begin{variable}{\l_keys_choice_int, \l_keys_choices_tl}
+%   Publicly accessible data on which choice is being used when several
+%   are generated as a set.
+%    \begin{macrocode}
+\int_new:N \l_keys_choice_int
+\tl_new:N \l_keys_choices_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_keys_key_tl}
+%   The name of a key itself: needed when setting keys.
+%    \begin{macrocode}
+\tl_new:N \l_keys_key_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_keys_module_tl}
+%   The module for an entire set of keys.
+%    \begin{macrocode}
+\tl_new:N \l_keys_module_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_keys_no_value_bool}
+%   A marker is needed internally to show if only a key or a key plus a
+%   value was seen: this is recorded here.
+%    \begin{macrocode}
+\bool_new:N \l_keys_no_value_bool
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_keys_path_tl}
+%   The \enquote{path} of the current key is stored here: this is
+%   available to the programmer and so is public.
+%    \begin{macrocode}
+\tl_new:N \l_keys_path_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_keys_property_tl}
+%   The \enquote{property} begin set for a key at definition time is
+%   stored here.
+%    \begin{macrocode}
+\tl_new:N \l_keys_property_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_keys_value_tl}
+%   The value given for a key: may be empty if no value was given.
+%    \begin{macrocode}
+\tl_new:N \l_keys_value_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \subsection{The key defining mechanism}
+%
+% \begin{macro}{\keys_define:nn}
+% \begin{macro}[aux]{\keys_define_aux:nnn, \keys_define_aux:onn}
+%   The public function for definitions is just a wrapper for the lower
+%   level mechanism, more or less. The outer function is designed to
+%   keep a track of the current module, to allow safe nesting.
+%    \begin{macrocode}
+\cs_new_protected:Npn \keys_define:nn
+  { \keys_define_aux:onn \l_keys_module_tl }
+\cs_new_protected:Npn \keys_define_aux:nnn #1#2#3
+  {
+    \tl_set:Nx \l_keys_module_tl { \tl_to_str:n {#2} }
+    \keyval_parse:NNn \keys_define_elt:n \keys_define_elt:nn {#3}
+    \tl_set:Nn \l_keys_module_tl {#1}
+  }
+\cs_generate_variant:Nn \keys_define_aux:nnn { o }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_define_elt:n}
+% \begin{macro}[int]{\keys_define_elt:nn}
+% \begin{macro}[aux]{\keys_define_elt_aux:nn}
+%   The outer functions here record whether a value was given and then
+%   converge on a common internal mechanism. There is first a search for
+%   a property in the current key name, then a check to make sure it is
+%   known before the code hands off to the next step.
+%    \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}
+  }
+\cs_new_protected:Npn \keys_define_elt_aux:nn #1#2 {
+  \keys_property_find:n {#1}
+  \cs_if_exist:cTF { \c_keys_props_root_tl \l_keys_property_tl }
+    { \keys_define_key:n {#2} }
+    {
+      \msg_kernel_error:nnxx { keys } { property-unknown }
+        { \l_keys_property_tl } { \l_keys_path_tl }
+    }
+}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_property_find:n}
+% \begin{macro}[aux]{\keys_property_find_aux:w}
+%   Searching for a property means finding the last |.| in the input,
+%   and storing the text before and after it. Everything is turned into
+%   strings, so there is no problem using an \texttt{x}-type expansion.
+%    \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:w #1 \q_stop }
+      { \msg_kernel_error:nnx { keys } { key-no-property } {#1} }
+  }
+\cs_new_protected_nopar:Npn \keys_property_find_aux:w #1 . #2 \q_stop
+  {
+    \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl \tl_to_str:n {#1} }
+    \tl_if_in:nnTF {#2} { . }
+      {
+        \tl_set:Nx \l_keys_path_tl { \l_keys_path_tl . }
+        \keys_property_find_aux:w #2 \q_stop
+      }
+      { \tl_set:Nn \l_keys_property_tl { . #2 } }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_define_key:n}
+% \begin{macro}[aux]{\keys_define_key_aux:w}
+%   Two possible cases. If there is a value for the key, then just use
+%   the function. If not, then a check to make sure there is no need for
+%   a value with the property. If there should be one then complain,
+%   otherwise execute it. There is no need to check for a |:| as if it
+%   is missing the earlier tests will have failed.
+%    \begin{macrocode}
+\cs_new_protected:Npn \keys_define_key:n #1
+  {
+    \bool_if:NTF \l_keys_no_value_bool
+      {
+        \exp_after:wN \keys_define_key_aux:w
+          \l_keys_property_tl \q_stop
+          { \use:c { \c_keys_props_root_tl \l_keys_property_tl } }
+          {
+            \msg_kernel_error:nnxx { keys }
+              { property-requires-value } { \l_keys_property_tl }
+              { \l_keys_path_tl }
+            }
+      }
+      { \use:c { \c_keys_props_root_tl \l_keys_property_tl } {#1} }
+  }
+\cs_new_protected:Npn \keys_define_key_aux:w #1 : #2 \q_stop
+  { \tl_if_empty:nTF {#2} }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Turning properties into actions}
+%
+% \begin{macro}[int]{\keys_bool_set:NN}
+%   Boolean keys are really just choices, but all done by hand. The
+%   second argument here is the scope: either empty or \texttt{g} for
+%   global.
+%    \begin{macrocode}
+\cs_new_nopar:Npn \keys_bool_set:NN #1#2
+  {
+    \cs_if_exist:NF #1 { \bool_new:N #1 }
+    \keys_choice_make:
+    \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:c { bool_ #2 set_false:N } \exp_not:N #1 }
+    \keys_cmd_set:nn { \l_keys_path_tl / unknown }
+      {
+        \msg_kernel_error:nnx { keys } { boolean-values-only }
+          { \l_keys_key_tl }
+      }
+    \keys_default_set:n { true }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\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}[int]{\keys_choices_generate:n}
+% \begin{macro}[aux]{\keys_choices_generate_aux:n}
+%   Creating multiple-choices means setting up the \enquote{indicator}
+%   code, then applying whatever the user wanted.
+%    \begin{macrocode}
+\cs_new_protected:Npn \keys_choices_generate:n #1
+  {
+    \cs_if_exist:cTF
+      { \c_keys_vars_root_tl \l_keys_path_tl .choice~code }
+      {
+        \keys_choice_make:
+        \int_zero:N \l_keys_choice_int
+        \clist_map_function:nN {#1} \keys_choices_generate_aux:n
+      }
+      {
+        \msg_kernel_error:nnx { keys }
+          { generate-choices-before-code } { \l_keys_path_tl }
+      }
+  }
+\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
+          { \c_keys_vars_root_tl \l_keys_path_tl .choice~code }
+      }
+    \int_incr:N \l_keys_choice_int
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_choice_code_store:x}
+%   The code for making multiple choices is stored in a token list.
+%    \begin{macrocode}
+\cs_new_protected:Npn \keys_choice_code_store:x #1
+  {
+    \cs_if_exist:cF
+      { \c_keys_vars_root_tl \l_keys_path_tl .choice~code }
+      {
+        \tl_new:c
+          { \c_keys_vars_root_tl \l_keys_path_tl .choice~code }
+      }
+    \tl_set:cx { \c_keys_vars_root_tl \l_keys_path_tl .choice~code }
+      {#1}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_cmd_set:nn, \keys_cmd_set:nx}
+% \begin{macro}[aux]{\keys_cmd_set_aux:n}
+%   Creating a new command means tidying up the properties and then making
+%   the internal function which actually does the work.
+%    \begin{macrocode}
+\cs_new_protected:Npn \keys_cmd_set:nn #1#2
+  {
+    \keys_cmd_set_aux:n {#1}
+    \cs_set:cpn { \c_keys_code_root_tl #1 } ##1 {#2}
+  }
+\cs_new_protected:Npn \keys_cmd_set:nx #1#2
+  {
+    \keys_cmd_set_aux:n {#1}
+    \cs_set:cpx { \c_keys_code_root_tl #1 } ##1 {#2}
+  }
+\cs_new_protected_nopar:Npn \keys_cmd_set_aux:n #1
+  {
+    \tl_clear_new:c { \c_keys_vars_root_tl #1 .default }
+    \tl_set:cn { \c_keys_vars_root_tl #1 .default } { \q_no_value }
+    \tl_clear_new:c { \c_keys_vars_root_tl #1 .req }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_default_set:n, \keys_default_set:V}
+%   Setting a default value is easy.
+%    \begin{macrocode}
+\cs_new_protected:Npn \keys_default_set:n #1
+  { \tl_set:cn { \c_keys_vars_root_tl \l_keys_path_tl .default } {#1} }
+\cs_generate_variant:Nn \keys_default_set:n { V }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\keys_meta_make:n, \keys_meta_make:x}
+%   To create a meta-key, simply set up to pass data through.
+%    \begin{macrocode}
+\cs_new_protected_nopar:Npn \keys_meta_make:n #1
+  {
+    \exp_args:NNo \keys_cmd_set:nn \l_keys_path_tl
+      { \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}
+%
+% \begin{macro}[int]{\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_vars_root_tl \l_keys_path_tl .req }
+      { c_keys_value_ #1 _tl }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_variable_set:NnNN, \keys_variable_set:cnNN}
+% \begin{macro}[int]{\keys_variable_set:NnN, \keys_variable_set:cnN}
+%   Setting a variable takes the type and scope separately so that
+%   it is easy to make a new variable if needed. The three-argument
+%   version is set up so that the use of |{ }| as an \texttt{N}-type
+%   variable is only done once!
+%    \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_new_protected_nopar:Npn \keys_variable_set:NnN #1#2#3
+  { \keys_variable_set:NnNN #1 {#2} { } #3 }
+\cs_generate_variant:Nn \keys_variable_set:NnNN { c }
+\cs_generate_variant:Nn \keys_variable_set:NnN  { c }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Creating key properties}
+%
+% The key property functions are all wrappers for internal functions,
+% meaning that things stay readable and can also be altered later on.
+%
+% \begin{macro}{.bool_set:N}
+% \begin{macro}{.bool_gset:N}
+%   One function for this.
+%    \begin{macrocode}
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .bool_set:N } #1
+  { \keys_bool_set:NN #1 { } }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .bool_gset:N } #1
+  { \keys_bool_set:NN #1 g }
+%    \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}
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .choice: }
+  { \keys_choice_make: }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{.code:n, .code:x}
+%   Creating code is simply a case of passing through to the underlying
+%   \texttt{set} function.
+%    \begin{macrocode}
+\cs_new_protected:cpn { \c_keys_props_root_tl .code:n } #1
+  { \keys_cmd_set:nn { \l_keys_path_tl } {#1} }
+\cs_new_protected:cpn { \c_keys_props_root_tl .code:x } #1
+  { \keys_cmd_set:nx { \l_keys_path_tl } {#1} }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{.choice_code:n, .choice_code:x}
+%   Storing the code for choices, using \cs{exp_not:n} to avoid needing
+%   two internal functions.
+%    \begin{macrocode}
+\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:n } #1
+  { \keys_choice_code_store:x { \exp_not:n {#1} } }
+\cs_new_protected:cpn { \c_keys_props_root_tl .choice_code:x } #1
+  { \keys_choice_code_store:x {#1} }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{.default:n, .default:V}
+%   Expansion is left to the internal functions.
+%    \begin{macrocode}
+\cs_new_protected:cpn { \c_keys_props_root_tl .default:n } #1
+  { \keys_default_set:n {#1} }
+\cs_new_protected:cpn { \c_keys_props_root_tl .default:V } #1
+  { \keys_default_set:V #1 }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{.dim_set:N, .dim_set:c}
+% \begin{macro}{.dim_gset:N, .dim_gset:c}
+% Setting a variable is very easy: just pass the data along.
+%    \begin{macrocode}
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_set:N } #1
+  { \keys_variable_set:NnN #1 { dim } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_set:c } #1
+  { \keys_variable_set:cnN {#1} { dim } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_gset:N } #1
+  { \keys_variable_set:NnNN #1 { dim } g n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .dim_gset:c } #1
+  { \keys_variable_set:cnNN {#1} { dim } g n }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{.fp_set:N, .fp_set:c}
+% \begin{macro}{.fp_gset:N, .fp_gset:c}
+%   Setting a variable is very easy: just pass the data along.
+%    \begin{macrocode}
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_set:N } #1
+  { \keys_variable_set:NnN #1 { fp } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_set:c } #1
+  { \keys_variable_set:cnN {#1} { fp } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_gset:N } #1
+  { \keys_variable_set:NnNN #1 { fp } g n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .fp_gset:c } #1
+  { \keys_variable_set:cnNN {#1} { fp } g n }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{.generate_choices:n}
+%   Making choices is easy.
+%    \begin{macrocode}
+\cs_new_protected:cpn { \c_keys_props_root_tl .generate_choices:n } #1
+  { \keys_choices_generate:n {#1} }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{.int_set:N, .int_set:c}
+% \begin{macro}{.int_gset:N, .int_gset:c}
+%   Setting a variable is very easy: just pass the data along.
+%    \begin{macrocode}
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_set:N } #1
+  { \keys_variable_set:NnN #1 { int } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_set:c } #1
+  { \keys_variable_set:cnN {#1} { int } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_gset:N } #1
+  { \keys_variable_set:NnNN #1 { int } g n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .int_gset:c } #1
+  { \keys_variable_set:cnNN {#1} { int } g n }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%\begin{macro}{.meta:n, .meta:x}
+% Making a meta is handled internally.
+%    \begin{macrocode}
+\cs_new_protected:cpn { \c_keys_props_root_tl .meta:n } #1
+  { \keys_meta_make:n {#1} }
+\cs_new_protected:cpn { \c_keys_props_root_tl .meta:x } #1
+  { \keys_meta_make:x {#1} }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{.skip_set:N, .skip_set:c}
+% \begin{macro}{.skip_gset:N, .skip_gset:c}
+%   Setting a variable is very easy: just pass the data along.
+%    \begin{macrocode}
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_set:N } #1
+  { \keys_variable_set:NnN #1 { skip } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_set:c } #1
+  { \keys_variable_set:cnN {#1} { skip } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_gset:N } #1
+  { \keys_variable_set:NnNN #1 { skip } g n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .skip_gset:c } #1
+  { \keys_variable_set:cnNN {#1} { skip } g n }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{.tl_set:N, .tl_set:c}
+% \begin{macro}{.tl_gset:N, .tl_gset:c}
+% \begin{macro}{.tl_set_x:N, .tl_set_x:c}
+% \begin{macro}{.tl_gset_x:N, .tl_gset_x:c}
+%   Setting a variable is very easy: just pass the data along.
+%    \begin{macrocode}
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set:N } #1
+   { \keys_variable_set:NnN #1 { tl } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set:c } #1
+  { \keys_variable_set:cnN {#1} { tl } n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set_x:N } #1
+  { \keys_variable_set:NnN #1 { tl } x }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_set_x:c } #1
+  { \keys_variable_set:cnN {#1} { tl } x }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset:N } #1
+  { \keys_variable_set:NnNN #1 { tl } g n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset:c } #1
+  { \keys_variable_set:cnNN {#1} { tl } g n }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset_x:N } #1
+  { \keys_variable_set:NnNN #1 { tl } g x }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .tl_gset_x:c } #1
+  { \keys_variable_set:cnNN {#1} { tl } g x }
+%    \end{macrocode}
+% \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}
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_forbidden: }
+  { \keys_value_requirement:n { forbidden } }
+\cs_new_protected_nopar:cpn { \c_keys_props_root_tl .value_required: }
+  { \keys_value_requirement:n { required } }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Setting keys}
+%
+% \begin{macro}{\keys_set:nn, \keys_set:nV, \keys_set:nv, \keys_set:no}
+% \begin{macro}[aux]{\keys_set_aux:nnn, \keys_set_aux:onn}
+%   A simple wrapper again.
+%    \begin{macrocode}
+\cs_new_protected:Npn \keys_set:nn
+  { \keys_set_aux:onn { \l_keys_module_tl } }
+\cs_new_protected:Npn \keys_set_aux:nnn #1#2#3
+  {
+    \tl_set:Nn \l_keys_module_tl {#2}
+    \keyval_parse:NNn \keys_set_elt:n \keys_set_elt:nn {#3}
+    \tl_set:Nn \l_keys_module_tl {#1}
+  }
+\cs_generate_variant:Nn \keys_set:nn { nV , nv , no }
+\cs_generate_variant:Nn \keys_set_aux:nnn { o }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_set_elt:n, \keys_set_elt:nn}
+% \begin{macro}[aux]{\keys_set_elt_aux:nn}
+%   A shared system once again. 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_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}
+  }
+\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}
+    \bool_if:nTF
+      {
+        \keys_if_value_p:n { required } &&
+        \l_keys_no_value_bool
+      }
+      {
+        \msg_kernel_error:nnx { keys } { value-required }
+          { \l_keys_path_tl }
+      }
+      {
+        \bool_if:nTF
+          {
+              \keys_if_value_p:n { forbidden } &&
+            ! \l_keys_no_value_bool
+          }
+          {
+            \msg_kernel_error:nnxx { keys } { value-forbidden }
+              { \l_keys_path_tl } { \l_keys_value_tl }
+          }
+          { \keys_execute: }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\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
+      {
+        \quark_if_no_value:cF { \c_keys_vars_root_tl \l_keys_path_tl .default }
+          {
+            \tl_set_eq:Nc \l_keys_value_tl
+              { \c_keys_vars_root_tl \l_keys_path_tl .default }
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_if_value_p:n}
+%   To test if a value is required or forbidden. A simple check for
+%   the existence of the appropriate marker.
+%    \begin{macrocode}
+\prg_new_conditional:Npnn \keys_if_value:n #1 { p }
+  {
+    \tl_if_eq:ccTF { c_keys_value_ #1 _tl }
+      { \c_keys_vars_root_tl \l_keys_path_tl .req }
+      { \prg_return_true: }
+      { \prg_return_false: }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\keys_execute:}
+% \begin{macro}[aux]{\keys_execute_unknown:}
+% \begin{macro}[aux]{\keys_execute: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_nopar:Npn \keys_execute:
+  { \keys_execute:nn { \l_keys_path_tl } { \keys_execute_unknown: } }
+\cs_new_nopar:Npn \keys_execute_unknown:
+  {
+    \keys_execute:nn { \l_keys_module_tl / unknown }
+      {
+        \msg_kernel_error:nnxx { keys } { key-unknown }
+          { \l_keys_path_tl } { \l_keys_module_tl }
+      }
+  }
+\cs_new_nopar:Npn \keys_execute:nn #1#2
+  {
+    \cs_if_exist:cTF { \c_keys_code_root_tl #1 }
+      {
+        \exp_args:Nno \use:c { \c_keys_code_root_tl #1 }
+          \l_keys_value_tl
+      }
+      {#2}
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \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_nopar:Npn \keys_choice_find:n #1
+  {
+    \keys_execute:nn { \l_keys_path_tl / \tl_to_str:n {#1} }
+      { \keys_execute:nn { \l_keys_path_tl / unknown } { } }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsection{Utilities}
+%
+% \begin{macro}[pTF]{\keys_if_exist:nn}
+% A utility for others to see if a key exists.
+%    \begin{macrocode}
+\prg_new_conditional:Npnn \keys_if_exist:nn #1#2 { p , T , F , TF }
+  {
+    \cs_if_exist:cTF { \c_keys_code_root_tl #1 / #2 }
+      { \prg_return_true:}
+      { \prg_return_false:}
+  }
+%    \end{macrocode}
+% \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_code_root_tl #1 / \tl_to_str:n {#2} } }
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsection{Messages}
+%
+% For when there is a need to complain.
+%    \begin{macrocode}
+\msg_kernel_new:nnnn { keys } { boolean-values-only }
+  { Key~'#1'~accepts~boolean~values~only. }
+  { The~key~'#1'~only~accepts~the~values~'true'~and~'false'. }
+\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'. }
+  {
+    \c_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~\keys_define:nn 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 } { 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.
+  }
+\msg_kernel_new:nnnn { keys } { property-requires-value }
+  { The~property~'#1'~requires~a~value. }
+  {
+    \c_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. }
+  {
+    \c_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}
+%
+%\PrintIndex
\ No newline at end of file
-- 
cgit v1.2.3

