% \iffalse meta-comment
%
%% File: l3candidates.dtx Copyright (C) 2012-2016 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 "l3kernel 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>
\documentclass[full]{l3doc}
%</driver>
%<*driver|package>
\GetIdInfo$Id: l3candidates.dtx 6688 2016-08-19 19:21:48Z bruno $
  {L3 Experimental additions to l3kernel}
%</driver|package>
%<*driver>
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \textsf{l3candidates} package\\ Experimental additions to
%   \pkg{l3kernel}^^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}
%
% \section{Important notice}
%
% This module provides a space in which functions can be added to
% \pkg{l3kernel} (\pkg{expl3}) while still being experimental.
% \begin{quote}
%  \bfseries
% As such, the
% functions here may not remain in their current form, or indeed at all,
% in \pkg{l3kernel} in the future.
% \end{quote}
%  In contrast to the material in
% \pkg{l3experimental}, the functions here are all \emph{small} additions to
% the kernel. We encourage programmers to test them out and report back on
% the \texttt{LaTeX-L} mailing list.
%
% \medskip
%
%   Thus, if you intend to use any of these functions from the candidate module in a public package
%  offered to others for productive use (e.g., being placed on CTAN) please consider the following points carefully:
% \begin{itemize}
% \item Be prepared that your public packages might require updating when such functions
%        are being finalized.
% \item Consider informing us that you use a particular function in your public package, e.g., by
%         discussing this on the \texttt{LaTeX-L}
%    mailing list. This way it becomes easier to coordinate any updates necessary without issues
%    for the users of your package.
% \item Discussing and understanding use cases for a particular addition or concept also helps to
%         ensure that we provide the right interfaces in the final version so please give us feedback
%         if you consider a certain candidate function useful (or not).
% \end{itemize}
% We only add functions in this space if we consider them being serious candidates for a final inclusion
% into the kernel. However, real use sometimes leads to better ideas, so functions from this module are
% \textbf{not necessarily stable} and we may have to adjust them!
%
% \section{Additions to \pkg{l3basics}}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\cs_log:N, \cs_log:c}
%   \begin{syntax}
%     \cs{cs_log:N} \meta{control sequence}
%   \end{syntax}
%   Writes the definition of the \meta{control sequence} in the log
%   file.  See also \cs{cs_show:N} which displays the result in the
%   terminal.
% \end{function}
%
% \begin{function}[updated = 2015-08-03]
%   {\__kernel_register_log:N, \__kernel_register_log:c}
%   \begin{syntax}
%     \cs{__kernel_register_log:N} \meta{register}
%   \end{syntax}
%   Used to write the contents of a \TeX{} register to the log file in a
%   form similar to \cs{__kernel_register_show:N}.
% \end{function}
%
% \section{Additions to \pkg{l3box}}
%
% \subsection{Affine transformations}
%
% Affine transformations are changes which (informally) preserve straight
% lines. Simple translations are affine transformations, but are better handled
% in \TeX{} by doing the translation first, then inserting an unmodified box.
% On the other hand, rotation and resizing of boxed material can best be
% handled by modifying boxes. These transformations are described here.
%
% \begin{function}{\box_resize:Nnn, \box_resize:cnn}
%   \begin{syntax}
%     \cs{box_resize:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
%   \end{syntax}
%   Resize the \meta{box} to \meta{x-size} horizontally and \meta{y-size}
%   vertically (both of the sizes are dimension expressions).
%   The \meta{y-size} is the vertical size (height plus depth) of
%   the box. The updated \meta{box} will be an hbox, irrespective of the nature
%   of the \meta{box}  before the resizing is applied. Negative sizes will
%   cause the material in the \meta{box} to be reversed in direction, but the
%   reference point of the \meta{box} will be unchanged.
%   Thus negative $y$-sizes will result in a box a depth dependent on the
%   height of the original box a height dependent on the depth.
%   The resizing applies within the current \TeX{} group level.
% \end{function}
%
% \begin{function}
%   {\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn}
%   \begin{syntax}
%     \cs{box_resize_to_ht_plus_dp:Nn} \meta{box} \Arg{y-size}
%   \end{syntax}
%   Resize the \meta{box} to \meta{y-size} vertically, scaling the horizontal
%   size by the same amount (\meta{y-size} is a dimension expression).
%   The \meta{y-size} is the vertical size (height plus depth) of
%   the box.
%   The updated \meta{box} will be an hbox, irrespective of the nature
%   of the \meta{box}  before the resizing is applied. A negative size will
%   cause the material in the \meta{box} to be reversed in direction, but the
%   reference point of the \meta{box} will be unchanged.
%   Thus negative $y$-sizes will result in a box with depth dependent on the
%   height of the original box and height dependent on the depth of the original.
%   The resizing applies within the current \TeX{} group level.
% \end{function}
%
% \begin{function}
%   {\box_resize_to_ht:Nn, \box_resize_to_ht:cn}
%   \begin{syntax}
%     \cs{box_resize_to_ht:Nn} \meta{box} \Arg{y-size}
%   \end{syntax}
%   Resize the \meta{box} to \meta{y-size} vertically, scaling the horizontal
%   size by the same amount (\meta{y-size} is a dimension expression).
%   The \meta{y-size} is the height only, not including depth, of
%   the box.
%   The updated \meta{box} will be an hbox, irrespective of the nature
%   of the \meta{box}  before the resizing is applied.
%   A negative size will
%   cause the material in the \meta{box} to be reversed in direction, but the
%   reference point of the \meta{box} will be unchanged.
%   Thus negative $y$-sizes will result in a box with depth dependent on the
%   height of the original box and height dependent on the depth of the original.
%   The resizing applies within the current \TeX{} group level.
% \end{function}
%
% \begin{function}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn}
%   \begin{syntax}
%     \cs{box_resize_to_wd:Nn} \meta{box} \Arg{x-size}
%   \end{syntax}
%   Resize the \meta{box} to \meta{x-size} horizontally, scaling the vertical
%   size by the same amount (\meta{x-size} is a dimension expression).
%   The updated \meta{box} will be an hbox, irrespective of the nature
%   of the \meta{box}  before the resizing is applied. A negative size will
%   cause the material in the \meta{box} to be reversed in direction, but the
%   reference point of the \meta{box} will be unchanged.
%   Thus negative $y$-sizes will result in a box a depth dependent on the
%   height of the original box a height dependent on the depth.
%   The resizing applies within the current \TeX{} group level.
% \end{function}
%
% \begin{function}[added = 2014-07-03]
%   {\box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn}
%   \begin{syntax}
%     \cs{box_resize_to_wd_and_ht:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
%   \end{syntax}
%   Resize the \meta{box} to a \emph{height} of
%   \meta{x-size} horizontally and \meta{y-size}
%   vertically (both of the sizes are dimension expressions).
%   The \meta{y-size} is the \emph{height} of the box, ignoring any depth.
%   The updated \meta{box} will be an hbox, irrespective of the nature
%   of the \meta{box}  before the resizing is applied. Negative sizes will
%   cause the material in the \meta{box} to be reversed in direction, but the
%   reference point of the \meta{box} will be unchanged.
% \end{function}
%
% \begin{function}{\box_rotate:Nn, \box_rotate:cn}
%   \begin{syntax}
%     \cs{box_rotate:Nn} \meta{box} \Arg{angle}
%   \end{syntax}
%   Rotates the \meta{box} by \meta{angle} (in degrees) anti-clockwise about
%   its reference point. The reference point of the updated box will be moved
%   horizontally such that it is at the left side of the smallest rectangle
%   enclosing the rotated material.
%   The updated \meta{box} will be an hbox, irrespective of the nature
%   of the \meta{box} before the rotation is applied. The rotation applies
%   within the current \TeX{} group level.
% \end{function}
%
% \begin{function}{\box_scale:Nnn, \box_scale:cnn}
%   \begin{syntax}
%     \cs{box_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale}
%   \end{syntax}
%   Scales the \meta{box} by factors \meta{x-scale} and \meta{y-scale} in
%   the horizontal and vertical directions, respectively (both scales are
%   integer expressions). The updated \meta{box} will be an hbox, irrespective
%   of the nature of the \meta{box} before the scaling is applied. Negative
%   scalings will cause the material in the \meta{box} to be reversed in
%   direction, but the reference point of the \meta{box} will be unchanged.
%   Thus negative $y$-scales will result in a box a depth dependent on the
%   height of the original box a height dependent on the depth.
%   The resizing applies within the current \TeX{} group level.
% \end{function}
%
% \subsection{Viewing part of a box}
%
% \begin{function}{\box_clip:N, \box_clip:c}
%   \begin{syntax}
%     \cs{box_clip:N} \meta{box}
%   \end{syntax}
%   Clips the \meta{box} in the output so that only material inside the
%   bounding box is displayed in the output. The updated \meta{box} will be an
%   hbox, irrespective of the nature of the \meta{box} before the clipping is
%   applied. The clipping applies within the current \TeX{} group level.
%
%   \textbf{These functions require the \LaTeX3 native drivers: they will
%   not work with the \LaTeXe{} \pkg{graphics} drivers!}
%
%   \begin{texnote}
%     Clipping is implemented by the driver, and as such the full content of
%     the box is placed in the output file. Thus clipping does not remove
%     any information from the raw output, and hidden material can therefore
%     be viewed by direct examination of the file.
%   \end{texnote}
% \end{function}
%
% \begin{function}{\box_trim:Nnnnn, \box_trim:cnnnn}
%   \begin{syntax}
%     \cs{box_trim:Nnnnn} \meta{box} \Arg{left} \Arg{bottom} \Arg{right} \Arg{top}
%   \end{syntax}
%   Adjusts the bounding box of the \meta{box} \meta{left} is removed from
%   the left-hand edge of the bounding box, \meta{right} from the right-hand
%   edge and so fourth. All adjustments are \meta{dimension expressions}.
%   Material output of the bounding box will still be displayed in the output
%   unless \cs{box_clip:N} is subsequently applied.
%   The updated \meta{box} will be an
%   hbox, irrespective of the nature of the \meta{box} before the trim
%   operation is applied. The adjustment applies within the current \TeX{}
%   group level. The behavior of the operation where the trims requested is
%   greater than the size of the box is undefined.
% \end{function}
%
% \begin{function}{\box_viewport:Nnnnn, \box_viewport:cnnnn}
%   \begin{syntax}
%     \cs{box_viewport:Nnnnn} \meta{box} \Arg{llx} \Arg{lly} \Arg{urx} \Arg{ury}
%   \end{syntax}
%   Adjusts the bounding box of the \meta{box} such that it has lower-left
%   co-ordinates (\meta{llx}, \meta{lly}) and upper-right co-ordinates
%   (\meta{urx}, \meta{ury}). All four co-ordinate positions are
%   \meta{dimension expressions}. Material output of the bounding box will
%   still be displayed in the output unless \cs{box_clip:N} is
%   subsequently applied.
%   The updated \meta{box} will be an
%   hbox, irrespective of the nature of the \meta{box} before the viewport
%   operation is applied. The adjustment applies within the current \TeX{}
%   group level.
% \end{function}
%
% \section{Additions to \pkg{l3clist}}
%
% \begin{function}[added = 2014-08-22]{\clist_log:N, \clist_log:c}
%   \begin{syntax}
%     \cs{clist_log:N} \meta{comma list}
%   \end{syntax}
%   Writes the entries in the \meta{comma list} in the log file.  See
%   also \cs{clist_show:N} which displays the result in the terminal.
% \end{function}
%
% \begin{function}[added = 2014-08-22]{\clist_log:n}
%   \begin{syntax}
%     \cs{clist_log:n} \Arg{tokens}
%   \end{syntax}
%   Writes the entries in the comma list in the log file.  See also
%   \cs{clist_show:n} which displays the result in the terminal.
% \end{function}
%
% \section{Additions to \pkg{l3coffins}}
%
% \begin{function}{\coffin_resize:Nnn, \coffin_resize:cnn}
%   \begin{syntax}
%     \cs{coffin_resize:Nnn} \meta{coffin} \Arg{width} \Arg{total-height}
%   \end{syntax}
%   Resized the \meta{coffin} to \meta{width} and \meta{total-height},
%   both of which should be given as dimension expressions.
% \end{function}
%
% \begin{function}{\coffin_rotate:Nn, \coffin_rotate:cn}
%   \begin{syntax}
%     \cs{coffin_rotate:Nn} \meta{coffin} \Arg{angle}
%   \end{syntax}
%   Rotates the \meta{coffin} by the given \meta{angle} (given in
%   degrees counter-clockwise). This process will rotate both the
%   coffin content and poles. Multiple rotations will not result in
%   the bounding box of the coffin growing unnecessarily.
% \end{function}
%
% \begin{function}{\coffin_scale:Nnn, \coffin_scale:cnn}
%   \begin{syntax}
%     \cs{coffin_scale:Nnn} \meta{coffin} \Arg{x-scale} \Arg{y-scale}
%   \end{syntax}
%   Scales the \meta{coffin} by a factors \meta{x-scale} and
%   \meta{y-scale} in the horizontal and vertical directions,
%   respectively. The two scale factors should be given as real numbers.
% \end{function}
%
% \begin{function}[added = 2014-08-22]
%   {\coffin_log_structure:N, \coffin_log_structure:c}
%   \begin{syntax}
%     \cs{coffin_log_structure:N} \meta{coffin}
%   \end{syntax}
%   This function writes the structural information about the
%   \meta{coffin} in the log file. The width, height and depth of the
%   typeset material are given, along with the location of all of the
%   poles of the coffin. See also \cs{coffin_show_structure:N} which
%   displays the result in the terminal.
% \end{function}
%
% \section{Additions to \pkg{l3file}}
%
% \begin{function}[TF, added = 2014-07-02]{\file_if_exist_input:n}
%   \begin{syntax}
%     \cs{file_if_exist_input:n} \Arg{file name}
%     \cs{file_if_exist_input:nTF} \Arg{file name} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Searches for \meta{file name} using the current \TeX{} search
%   path and the additional paths controlled by
%   \cs{file_path_include:n}). If found, inserts the \meta{true code} then
%   reads in the file as additional \LaTeX{} source as described for
%   \cs{file_input:n}. Note that \cs{file_if_exist_input:n} does not raise
%   an error if the file is not found, in contrast to \cs{file_input:n}.
% \end{function}
%
% \begin{function}[added = 2012-02-11]{\ior_map_inline:Nn}
%   \begin{syntax}
%     \cs{ior_map_inline:Nn} \meta{stream} \Arg{inline function}
%   \end{syntax}
%   Applies the \meta{inline function} to \meta{lines} obtained by
%   reading one or more lines (until an equal number of left and right
%   braces are found) from the \meta{stream}. The \meta{inline function}
%   should consist of code which will receive the \meta{line} as |#1|.
%   Note that \TeX{} removes trailing space and tab characters
%   (character codes 32 and 9) from every line upon input.  \TeX{} also
%   ignores any trailing new-line marker from the file it reads.
% \end{function}
%
% \begin{function}[added = 2012-02-11]{\ior_str_map_inline:Nn}
%   \begin{syntax}
%     \cs{ior_str_map_inline:Nn} \Arg{stream} \Arg{inline function}
%   \end{syntax}
%   Applies the \meta{inline function} to every \meta{line}
%   in the \meta{stream}. The material is read from the \meta{stream}
%   as a series of tokens with category code $12$ (other), with the
%   exception of space characters which are given category code $10$
%   (space). The \meta{inline function} should consist of code which
%   will receive the \meta{line} as |#1|.
%   Note that \TeX{} removes trailing space and tab characters
%   (character codes 32 and 9) from every line upon input.  \TeX{} also
%   ignores any trailing new-line marker from the file it reads.
% \end{function}
%
% \begin{function}[added = 2012-06-29]{\ior_map_break:}
%   \begin{syntax}
%     \cs{ior_map_break:}
%   \end{syntax}
%   Used to terminate a \cs[no-index]{ior_map_\ldots} function before all
%   lines from the \meta{stream} have been processed. This will
%   normally take place within a conditional statement, for example
%   \begin{verbatim}
%     \ior_map_inline:Nn \l_my_ior
%       {
%         \str_if_eq:nnTF { #1 } { bingo }
%           { \ior_map_break: }
%           {
%             % Do something useful
%           }
%       }
%   \end{verbatim}
%   Use outside of a \cs[no-index]{ior_map_\ldots} scenario will lead to low
%   level \TeX{} errors.
%   \begin{texnote}
%     When the mapping is broken, additional tokens may be inserted by the
%     internal macro \cs{__prg_break_point:Nn} before further items are taken
%     from the input stream. This will depend on the design of the mapping
%     function.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2012-06-29]{\ior_map_break:n}
%   \begin{syntax}
%     \cs{ior_map_break:n} \Arg{tokens}
%   \end{syntax}
%   Used to terminate a \cs[no-index]{ior_map_\ldots} function before all
%   lines in the \meta{stream} have been processed, inserting
%   the \meta{tokens} after the mapping has ended. This will
%   normally take place within a conditional statement, for example
%   \begin{verbatim}
%     \ior_map_inline:Nn \l_my_ior
%       {
%         \str_if_eq:nnTF { #1 } { bingo }
%           { \ior_map_break:n { <tokens> } }
%           {
%             % Do something useful
%           }
%       }
%   \end{verbatim}
%   Use outside of a \cs[no-index]{ior_map_\ldots} scenario will lead to low
%   level \TeX{} errors.
%   \begin{texnote}
%     When the mapping is broken, additional tokens may be inserted by the
%     internal macro \cs{__prg_break_point:Nn} before the \meta{tokens} are
%     inserted into the input stream.
%     This will depend on the design of the mapping function.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2014-08-22]
%   {\ior_log_streams:, \iow_log_streams:}
%   \begin{syntax}
%     \cs{ior_log_streams:}
%     \cs{iow_log_streams:}
%   \end{syntax}
%   Writes in the log file a list of the file names associated with each
%   open stream: intended for tracking down problems.
% \end{function}
%
% \section{Additions to \pkg{l3fp}}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-07]
%   {\fp_log:N, \fp_log:c, \fp_log:n}
%   \begin{syntax}
%     \cs{fp_log:N} \meta{fp~var}
%     \cs{fp_log:n} \Arg{floating point expression}
%   \end{syntax}
%   Evaluates the \meta{floating point expression} and writes the
%   result in the log file.
% \end{function}
%
% \section{Additions to \pkg{l3int}}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\int_log:N, \int_log:c}
%   \begin{syntax}
%     \cs{int_log:N} \meta{integer}
%   \end{syntax}
%   Writes the value of the \meta{integer} in the log file.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\int_log:n}
%   \begin{syntax}
%     \cs{int_log:n} \Arg{integer expression}
%   \end{syntax}
%   Writes the result of evaluating the \meta{integer expression}
%   in the log file.
% \end{function}
%
% \section{Additions to \pkg{l3keys}}
%
% \begin{function}[added = 2014-08-22]{\keys_log:nn}
%   \begin{syntax}
%     \cs{keys_log:nn} \Arg{module} \Arg{key}
%   \end{syntax}
%   Writes in the log file the function which is used to actually
%   implement a \meta{key} for a \meta{module}.
% \end{function}
%
% \section{Additions to \pkg{l3msg}}
%
% In very rare cases it may be necessary to produce errors in an
% expansion-only context.  The functions in this section should only be
% used if there is no alternative approach using \cs{msg_error:nnnnnn}
% or other non-expandable commands from the previous section.  Despite
% having a similar interface as non-expandable messages, expandable
% errors must be handled internally very differently from normal error
% messages, as none of the tools to print to the terminal or the log
% file are expandable.  As a result, the message text and arguments are
% not expanded, and messages must be very short (with default settings,
% they are truncated after approximately 50 characters).  It is
% advisable to ensure that the message is understandable even when
% truncated.  Another particularity of expandable messages is that they
% cannot be redirected or turned off by the user.
%
% \begin{function}[EXP, added = 2015-08-06]
%   {
%     \msg_expandable_error:nnnnnn ,
%     \msg_expandable_error:nnnnn  ,
%     \msg_expandable_error:nnnn   ,
%     \msg_expandable_error:nnn    ,
%     \msg_expandable_error:nn     ,
%     \msg_expandable_error:nnffff ,
%     \msg_expandable_error:nnfff  ,
%     \msg_expandable_error:nnff   ,
%     \msg_expandable_error:nnf    ,
%   }
%   \begin{syntax}
%     \cs{msg_expandable_error:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
%   \end{syntax}
%   Issues an \enquote{Undefined error} message from \TeX{} itself
%   using the undefined control sequence \cs{::error} then prints
%   \enquote{! \meta{module}: }\meta{error message}, which should be
%   short.  With default settings, anything beyond approximately $60$
%   characters long (or bytes in some engines) is cropped.  A leading
%   space might be removed as well.
% \end{function}
%
% \section{Additions to \pkg{l3prg}}
%
% Minimal (lazy) evaluation can be obtained using the conditionals
% \cs{bool_lazy_all:nTF}, \cs{bool_lazy_and:nnTF}, \cs{bool_lazy_any:nTF}, or
% \cs{bool_lazy_or:nnTF}, which only evaluate their boolean expression
% arguments when they are needed to determine the resulting truth
% value.  For example, when evaluating the boolean expression
% \begin{verbatim}
%     \bool_lazy_and_p:nn
%       {
%         \bool_lazy_any_p:n
%           {
%             { \int_compare_p:n { 2 = 3 } }
%             { \int_compare_p:n { 4 <= 4 } }
%             { \int_compare_p:n { 1 = \error } } % is skipped
%           }
%       }
%       { ! \int_compare_p:n { 2 = 4 } }
% \end{verbatim}
% the line marked with |is skipped| is not expanded because the result
% of \cs{bool_lazy_any_p:n} is known once the second boolean expression is
% found to be logically \texttt{true}.  On the other hand, the last
% line is expanded because its logical value is needed to determine the
% result of \cs{bool_lazy_and_p:nn}.
%   
% \begin{function}[EXP, pTF, added = 2015-11-15]{\bool_lazy_all:n}
%   \begin{syntax}
%     \cs{bool_lazy_all_p:n} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \}
%     \cs{bool_lazy_all:nTF} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements the \enquote{And} operation on the \meta{boolean
%   expressions}, hence is \texttt{true} if all of them are
%   \texttt{true} and \texttt{false} if any of them is \texttt{false}.
%   Contrarily to the infix operator |&&|, only the \meta{boolean
%   expressions} which are needed to determine the result of
%   \cs{bool_lazy_all:nTF} will be evaluated.  See also \cs{bool_lazy_and:nnTF}
%   when there are only two \meta{boolean expressions}.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2015-11-15]{\bool_lazy_and:nn}
%   \begin{syntax}
%     \cs{bool_lazy_and_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2}
%     \cs{bool_lazy_and:nnTF} \Arg{boolexpr_1} \Arg{boolexpr_2} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements the \enquote{And} operation between two boolean
%   expressions, hence is \texttt{true} if both are \texttt{true}.
%   Contrarily to the infix operator |&&|, the \meta{boolexpr_2} will
%   only be evaluated if it is needed to determine the result of
%   \cs{bool_lazy_and:nnTF}.  See also \cs{bool_lazy_all:nTF} when there are more
%   than two \meta{boolean expressions}.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2015-11-15]{\bool_lazy_any:n}
%   \begin{syntax}
%     \cs{bool_lazy_any_p:n} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \}
%     \cs{bool_lazy_any:nTF} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements the \enquote{Or} operation on the \meta{boolean
%   expressions}, hence is \texttt{true} if any of them is
%   \texttt{true} and \texttt{false} if all of them are \texttt{false}.
%   Contrarily to the infix operator \verb"||", only the \meta{boolean
%   expressions} which are needed to determine the result of
%   \cs{bool_lazy_any:nTF} will be evaluated.  See also \cs{bool_lazy_or:nnTF}
%   when there are only two \meta{boolean expressions}.
% \end{function}
%
% \begin{function}[EXP, pTF, added = 2015-11-15]{\bool_lazy_or:nn}
%   \begin{syntax}
%     \cs{bool_lazy_or_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2}
%     \cs{bool_lazy_or:nnTF} \Arg{boolexpr_1} \Arg{boolexpr_2} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Implements the \enquote{Or} operation between two boolean
%   expressions, hence is \texttt{true} if either one is \texttt{true}.
%   Contrarily to the infix operator \verb"||", the \meta{boolexpr_2}
%   will only be evaluated if it is needed to determine the result of
%   \cs{bool_lazy_or:nnTF}.  See also \cs{bool_lazy_any:nTF} when there are more
%   than two \meta{boolean expressions}.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\bool_log:N, \bool_log:c}
%   \begin{syntax}
%     \cs{bool_log:N} \meta{boolean}
%   \end{syntax}
%   Writes the logical truth of the \meta{boolean} in the log file.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\bool_log:n}
%   \begin{syntax}
%     \cs{bool_log:n} \Arg{boolean expression}
%   \end{syntax}
%   Writes the logical truth of the \meta{boolean expression} in the log
%   file.
% \end{function}
%
% \section{Additions to \pkg{l3prop}}
%
% \begin{function}[EXP]{\prop_count:N, \prop_count:c}
%   \begin{syntax}
%     \cs{prop_count:N} \meta{property list}
%   \end{syntax}
%   Leaves the number of key--value pairs in the \meta{property list} in
%   the input stream as an \meta{integer denotation}.
% \end{function}
%
% \begin{function}[rEXP]
%   {\prop_map_tokens:Nn, \prop_map_tokens:cn}
%   \begin{syntax}
%     \cs{prop_map_tokens:Nn} \meta{property list} \Arg{code}
%   \end{syntax}
%   Analogue of \cs{prop_map_function:NN} which maps several tokens
%   instead of a single function.  The \meta{code} receives each
%   key--value pair in the \meta{property list} as two trailing brace
%   groups. For instance,
%   \begin{verbatim}
%     \prop_map_tokens:Nn \l_my_prop { \str_if_eq:nnT { mykey } }
%   \end{verbatim}
%   will expand to the value corresponding to \texttt{mykey}: for each
%   pair in |\l_my_prop| the function \cs{str_if_eq:nnT} receives
%   \texttt{mykey}, the \meta{key} and the \meta{value} as its three
%   arguments.  For that specific task, \cs{prop_item:Nn} is faster.
% \end{function}
%
% \begin{function}[added = 2014-08-12]{\prop_log:N, \prop_log:c}
%   \begin{syntax}
%     \cs{prop_log:N} \meta{property list}
%   \end{syntax}
%   Writes the entries in the \meta{property list} in the log file.
% \end{function}
%
% \section{Additions to \pkg{l3seq}}
%
% \begin{function}[rEXP]
%   {
%     \seq_mapthread_function:NNN, \seq_mapthread_function:NcN,
%     \seq_mapthread_function:cNN, \seq_mapthread_function:ccN
%   }
%   \begin{syntax}
%     \cs{seq_mapthread_function:NNN} \meta{seq_1} \meta{seq_2} \meta{function}
%   \end{syntax}
%   Applies \meta{function} to every pair of items
%   \meta{seq_1-item}--\meta{seq_2-item} from the two sequences, returning
%   items from both sequences from left to right.   The \meta{function} will
%   receive two \texttt{n}-type arguments for each iteration. The  mapping
%   will terminate when
%   the end of either sequence is reached (\emph{i.e.}~whichever sequence has
%   fewer items determines how many iterations
%   occur).
% \end{function}
%
% \begin{function}{\seq_set_filter:NNn, \seq_gset_filter:NNn}
%   \begin{syntax}
%     \cs{seq_set_filter:NNn} \meta{sequence_1} \meta{sequence_2} \Arg{inline boolexpr}
%   \end{syntax}
%   Evaluates the \meta{inline boolexpr} for every \meta{item} stored
%   within the \meta{sequence_2}. The \meta{inline boolexpr} will
%   receive the \meta{item} as |#1|. The sequence of all \meta{items}
%   for which the \meta{inline boolexpr} evaluated to \texttt{true}
%   is assigned to \meta{sequence_1}.
%   \begin{texnote}
%     Contrarily to other mapping functions, \cs{seq_map_break:} cannot
%     be used in this function, and will lead to low-level \TeX{} errors.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2011-12-22]
%   {\seq_set_map:NNn, \seq_gset_map:NNn}
%   \begin{syntax}
%     \cs{seq_set_map:NNn} \meta{sequence_1} \meta{sequence_2} \Arg{inline function}
%   \end{syntax}
%   Applies \meta{inline function} to every \meta{item} stored
%   within the \meta{sequence_2}. The \meta{inline function} should
%   consist of code which will receive the \meta{item} as |#1|.
%   The sequence resulting from \texttt{x}-expanding
%   \meta{inline function} applied to each \meta{item}
%   is assigned to \meta{sequence_1}. As such, the code
%   in \meta{inline function} should be expandable.
%   \begin{texnote}
%     Contrarily to other mapping functions, \cs{seq_map_break:} cannot
%     be used in this function, and will lead to low-level \TeX{} errors.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2014-08-12]{\seq_log:N, \seq_log:c}
%   \begin{syntax}
%     \cs{seq_log:N} \meta{sequence}
%   \end{syntax}
%   Writes the entries in the \meta{sequence} in the log file.
% \end{function}
%
% \section{Additions to \pkg{l3skip}}
%
% \begin{function}{\skip_split_finite_else_action:nnNN}
%   \begin{syntax}
%     \cs{skip_split_finite_else_action:nnNN} \Arg{skipexpr} \Arg{action}
%     ~~\meta{dimen_1} \meta{dimen_2}
%   \end{syntax}
%   Checks if the \meta{skipexpr} contains finite glue. If it does then it
%   assigns
%   \meta{dimen_1} the stretch component and \meta{dimen_2} the shrink
%   component. If
%   it contains infinite glue set \meta{dimen_1} and \meta{dimen_2} to $0$\,pt
%   and place |#2| into the input stream: this is usually an error or
%   warning message of some sort.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\dim_log:N, \dim_log:c}
%   \begin{syntax}
%     \cs{dim_log:N} \meta{dimension}
%    \end{syntax}
%   Writes the value of the \meta{dimension} in the log file.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\dim_log:n}
%   \begin{syntax}
%     \cs{dim_log:n} \Arg{dimension expression}
%    \end{syntax}
%   Writes the result of evaluating the \meta{dimension expression}
%   in the log file.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\skip_log:N, \skip_log:c}
%   \begin{syntax}
%     \cs{skip_log:N} \meta{skip}
%    \end{syntax}
%   Writes the value of the \meta{skip} in the log file.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\skip_log:n}
%   \begin{syntax}
%     \cs{skip_log:n} \Arg{skip expression}
%    \end{syntax}
%   Writes the result of evaluating the \meta{skip expression}
%   in the log file.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-03]{\muskip_log:N, \muskip_log:c}
%   \begin{syntax}
%     \cs{muskip_log:N} \meta{muskip}
%    \end{syntax}
%   Writes the value of the \meta{muskip} in the log file.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\muskip_log:n}
%   \begin{syntax}
%     \cs{muskip_log:n} \Arg{muskip expression}
%    \end{syntax}
%   Writes the result of evaluating the \meta{muskip expression}
%   in the log file.
% \end{function}
%
% \section{Additions to \pkg{l3tl}}
%
% \begin{function}[EXP,pTF]{\tl_if_single_token:n}
%   \begin{syntax}
%   \cs{tl_if_single_token_p:n} \Arg{token list}
%   \cs{tl_if_single_token:nTF} \Arg{token list} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the token list consists of exactly one token, \emph{i.e.}~is
%   either a single space character or a single \enquote{normal} token.
%   Token groups (|{|\ldots|}|) are not single tokens.
% \end{function}
%
% \begin{function}[EXP]{\tl_reverse_tokens:n}
%   \begin{syntax}
%     \cs{tl_reverse_tokens:n} \Arg{tokens}
%   \end{syntax}
%   This function, which works directly on \TeX{} tokens, reverses
%   the order of the \meta{tokens}: the first will be the last and
%   the last will become first. Spaces are preserved. The reversal
%   also operates within brace groups, but the braces themselves
%   are not exchanged, as this would lead to an unbalanced token
%   list. For instance, \cs{tl_reverse_tokens:n} |{a~{b()}}|
%   leaves |{)(b}~a| in the input stream. This function requires
%   two steps of expansion.
%   \begin{texnote}
%     The result is returned within the \tn{unexpanded}
%     primitive (\cs{exp_not:n}), which means that the token
%     list will not expand further when appearing in an \texttt{x}-type
%     argument expansion.
%   \end{texnote}
% \end{function}
%
% \begin{function}[EXP]{\tl_count_tokens:n}
%   \begin{syntax}
%     \cs{tl_count_tokens:n} \Arg{tokens}
%   \end{syntax}
%   Counts the number of \TeX{} tokens in the \meta{tokens} and leaves
%   this information in the input stream. Every token, including spaces and
%   braces, contributes one to the total; thus for instance, the token count of
%   |a~{bc}| is $6$.
%   This function requires three expansions,
%   giving an \meta{integer denotation}.
% \end{function}
%
% \begin{function}[EXP, added = 2014-06-30, updated = 2016-01-12]
%   {
%     \tl_lower_case:n,  \tl_upper_case:n,  \tl_mixed_case:n,
%     \tl_lower_case:nn, \tl_upper_case:nn, \tl_mixed_case:nn
%   }
%   \begin{syntax}
%     \cs{tl_upper_case:n}  \Arg{tokens}
%     \cs{tl_upper_case:nn} \Arg{language} \Arg{tokens}
%   \end{syntax}
%   These functions are intended to be applied to input which may be
%   regarded broadly as \enquote{text}. They traverse the \meta{tokens} and
%   change the case of characters as discussed below. The character code of
%   the characters replaced may be arbitrary: the replacement characters will
%   have standard document-level category codes ($11$ for letters, $12$ for
%   letter-like characters which can also be case-changed).  Begin-group and
%   end-group characters in the \meta{tokens} are normalized and become |{|
%   and |}|, respectively.
%
%   Importantly, notice that these functions are intended for working with
%   user text for typesetting. For case changing programmatic data see the
%   \pkg{l3str} module and discussion there of \cs{str_lower_case:n},
%   \cs{str_upper_case:n} and \cs{str_fold_case:n}.
% \end{function}
%
% The functions perform expansion on the input in most cases. In particular,
% input in the form of token lists or expandable functions will be expanded
% \emph{unless} it falls within one of the special handling classes described
% below. This expansion approach means that in general the result of case
% changing will match the \enquote{natural} outcome expected from a
% \enquote{functional} approach to case modification. For example
% \begin{verbatim}
%   \tl_set:Nn \l_tmpa_tl { hello }
%   \tl_upper_case:n { \l_tmpa_tl \c_space_tl world }
% \end{verbatim}
% will produce
% \begin{verbatim}
%   HELLO WORLD
% \end{verbatim}
% The expansion approach taken means that in package mode any \LaTeXe{}
% \enquote{robust} commands which may appear in the input should be converted
% to engine-protected versions using for example the \tn{robustify} command
% from the \pkg{etoolbox} package.
%
% \begin{variable}{\l_tl_case_change_math_tl}
%   Case changing will not take place within math mode material so for example
%   \begin{verbatim}
%     \tl_upper_case:n { Some~text~$y = mx + c$~with~{Braces} }
%   \end{verbatim}
%   will become
%   \begin{verbatim}
%     SOME TEXT $y = mx + c$ WITH {BRACES}
%   \end{verbatim}
%   Material inside math mode is left entirely unchanged: in particular, no
%   expansion is undertaken.
%
%   Detection of math mode is controlled by the list of tokens in
%   \cs{l_tl_case_change_math_tl}, which should be in open--close pairs. In
%   package mode the standard settings is
%   \begin{verbatim}
%     $ $ \( \)
%   \end{verbatim}
%
%   Note that while expansion occurs when searching the text it does not
%   apply to math mode material (which should be unaffected by case changing).
%   As such, whilst the opening token for math mode may be \enquote{hidden}
%   inside a command/macro, the closing one cannot be as this is being
%   searched for in math mode. Typically, in the types of \enquote{text}
%   the case changing functions are intended to apply to this should not be
%   an issue.
% \end{variable}
%
% \begin{variable}{\l_tl_case_change_exclude_tl}
%   Case changing can be prevented by using any command on the list
%   \cs{l_tl_case_change_exclude_tl}. Each entry should be a function
%   to be followed by one argument: the latter will be preserved as-is
%   with no expansion. Thus for example following
%   \begin{verbatim}
%     \tl_put_right:Nn \l_tl_case_change_exclude_tl { \NoChangeCase }
%   \end{verbatim}
%   the input
%   \begin{verbatim}
%     \tl_upper_case:n
%       { Some~text~$y = mx + c$~with~\NoChangeCase {Protection} }
%   \end{verbatim}
%   will result in
%   \begin{verbatim}
%     SOME TEXT $y = mx + c$ WITH \NoChangeCase {Protection}
%   \end{verbatim}
%   Notice that the case changing mapping preserves the inclusion of
%   the escape functions: it is left to other code to provide suitable
%   definitions (typically equivalent to \cs{use:n}). In particular, the
%   result of case changing is returned protected by \cs{exp_not:n}.
%
%   When used with \LaTeXe{} the commands |\cite|, |\ensuremath|, |\label|
%   and |\ref| are automatically included in the list for exclusion from
%   case changing.
% \end{variable}
%
% \begin{variable}{\l_tl_case_change_accents_tl}
%   This list specifies accent commands which should be left unexpanded
%   in the output. This allows for example
%   \begin{verbatim}
%     \tl_upper_case:n { \" { a } }
%   \end{verbatim}
%   to yield
%   \begin{verbatim}
%     \" { A }
%   \end{verbatim}
%   irrespective of the expandability of |\"|.
%
%   The standard contents of this variable is |\"|, |\'|, |\.|, |\^|, |\`|,
%   |\~|, |\c|, |\H|, |\k|, |\r|, |\t|, |\u| and |\v|.
% \end{variable}
%
% \enquote{Mixed} case conversion may be regarded informally as converting the
% first character of the \meta{tokens} to upper case and the rest to lower
% case. However, the process is more complex than this as there are some
% situations where a single lower case character maps to a special form, for
% example \texttt{ij} in Dutch which becomes \texttt{IJ}. As such,
% \cs[index=tl_mixed_case:n]{tl_mixed_case:n(n)}
% implement a more sophisticated mapping which accounts
% for this and for modifying accents on the first letter. Spaces at the start
% of the \meta{tokens} are ignored when finding the first \enquote{letter} for
% conversion.
% \begin{verbatim}
%   \tl_mixed_case:n { hello~WORLD }   % => "Hello world"
%   \tl_mixed_case:n { ~hello~WORLD }  % => " Hello world"
%   \tl_mixed_case:n { {hello}~WORLD } % => "{Hello} world"
% \end{verbatim}
% When finding the first \enquote{letter} for this process, any content in
% math mode or covered by \cs{l_tl_case_change_exclude_tl} is ignored.
%
% (Note that the Unicode Consortium describe this as \enquote{title case}, but
% that in English title case applies on a word-by-word basis. The
% \enquote{mixed} case implemented here is a lower level concept needed for
% both \enquote{title} and \enquote{sentence} casing of text.)
%
% \begin{variable}{\l_tl_mixed_case_ignore_tl}
%   The list of characters to ignore when searching for the first
%   \enquote{letter} in mixed-casing is determined by
%   \cs{l_tl_mixed_change_ignore_tl}. This has the standard setting
%   \begin{verbatim}
%     ( [ { ` -
%   \end{verbatim}
%   where comparisons are made on a character basis.
% \end{variable}
%
%   As is generally true for \pkg{expl3}, these functions are designed to
%   work with Unicode input only. As such, UTF-8 input is assumed for
%   \emph{all} engines. When used with \XeTeX{} or \LuaTeX{} a full range of
%   Unicode transformations are enabled. Specifically, the standard mappings
%   here follow those defined by the \href{http://www.unicode.org}^^A
%   {Unicode Consortium} in \texttt{UnicodeData.txt} and
%   \texttt{SpecialCasing.txt}. In the case of $8$-bit engines, mappings
%   are provided for characters which can be represented in output typeset
%   using the |T1| font encoding. Thus for example |ä| can be case-changed
%   using \pdfTeX{}.  For \pTeX{} only the ASCII range is covered as the
%   engine treats input outside of this range as east Asian.
%
% Context-sensitive mappings are enabled: language-dependent cases are
% discussed below. Context detection will expand input but treats any
% unexpandable control sequences as \enquote{failures} to match a context.
%
%   Language-sensitive conversions are enabled using the \meta{language}
%   argument, and follow Unicode Consortium guidelines. Currently, the
%   languages recognised for special handling are as follows.
%   \begin{itemize}
%     \item Azeri and Turkish (\texttt{az} and \texttt{tr}).
%       The case pairs I/i-dotless and I-dot/i are activated for these
%       languages. The combining dot mark is removed when lower
%       casing I-dot and introduced when upper casing i-dotless.
%     \item German (\texttt{de-alt}).
%       An alternative mapping for German in which the lower case
%       \emph{Eszett} maps to a \emph{gro\ss{}es Eszett}.
%     \item Lithuanian (\texttt{lt}).
%       The lower case letters i and j should retain a dot above when the
%       accents grave, acute or tilde are present. This is implemented for
%       lower casing of the relevant upper case letters both when input as
%       single Unicode codepoints and when using combining accents. The
%       combining dot is removed when upper casing in these cases. Note that
%       \emph{only} the accents used in Lithuanian are covered: the behaviour
%       of other accents are not modified.
%     \item Dutch (\texttt{nl}).
%       Capitalisation of \texttt{ij} at the beginning of mixed cased
%       input produces \texttt{IJ} rather than \texttt{Ij}. The output
%       retains two separate letters, thus this transformation \emph{is}
%       available using \pdfTeX{}.
%   \end{itemize}
%
%   Creating additional context-sensitive mappings requires knowledge
%   of the underlying mapping implementation used here. The team are happy
%   to add these to the kernel where they are well-documented
%   (\emph{e.g.}~in Unicode Consortium or relevant government publications).
%
% \begin{function}[added = 2014-06-25]
%   {
%     \tl_set_from_file:Nnn,  \tl_set_from_file:cnn,
%     \tl_gset_from_file:Nnn, \tl_gset_from_file:cnn
%   }
%   \begin{syntax}
%     \cs{tl_set_from_file:Nnn} \meta{tl} \Arg{setup} \Arg{filename}
%   \end{syntax}
%   Defines \meta{tl} to the contents of \meta{filename}.
%   Category codes may need to be set appropriately via the \meta{setup}
%   argument.
% \end{function}
%
% \begin{function}[added = 2014-06-25]
%   {
%     \tl_set_from_file_x:Nnn,  \tl_set_from_file_x:cnn,
%     \tl_gset_from_file_x:Nnn, \tl_gset_from_file_x:cnn
%   }
%   \begin{syntax}
%     \cs{tl_set_from_file_x:Nnn} \meta{tl} \Arg{setup} \Arg{filename}
%   \end{syntax}
%   Defines \meta{tl} to the contents of \meta{filename}, expanding
%   the contents of the file as it is read. Category codes and other
%   definitions may need to be set appropriately via the \meta{setup}
%   argument.
% \end{function}
%
% \begin{function}[added = 2014-08-22, updated = 2015-08-01]{\tl_log:N, \tl_log:c}
%   \begin{syntax}
%     \cs{tl_log:N} \meta{tl~var}
%   \end{syntax}
%   Writes the content of the \meta{tl~var} in the log file.  See also
%   \cs{tl_show:N} which displays the result in the terminal.
% \end{function}
%
% \begin{function}[added = 2014-08-22]{\tl_log:n}
%   \begin{syntax}
%     \cs{tl_log:n} \meta{token list}
%   \end{syntax}
%   Writes the \meta{token list} in the log file.  See also
%   \cs{tl_show:n} which displays the result in the terminal.
% \end{function}
%
% \section{Additions to \pkg{l3tokens}}
%
% \begin{function}[TF, updated = 2012-12-20]{\peek_N_type:}
%   \begin{syntax}
%     \cs{peek_N_type:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the next \meta{token} in the input stream can be safely
%   grabbed as an \texttt{N}-type argument. The test will be \meta{false}
%   if the next \meta{token} is either an explicit or implicit
%   begin-group or end-group token (with any character code), or
%   an explicit or implicit space character (with character code $32$
%   and category code $10$), or an outer token (never used in \LaTeX3)
%   and \meta{true} in all other cases.
%   Note that a \meta{true} result ensures that the next \meta{token} is
%   a valid \texttt{N}-type argument. However, if the next \meta{token}
%   is for instance \cs{c_space_token}, the test will take the
%   \meta{false} branch, even though the next \meta{token} is in fact
%   a valid \texttt{N}-type argument. The \meta{token} will be left
%   in the input stream after the \meta{true code} or \meta{false code}
%   (as appropriate to the result of the test).
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3candidates} Implementation}
%
%    \begin{macrocode}
%<*initex|package>
%    \end{macrocode}
%
% \subsection{Additions to \pkg{l3basics}}
%
%    \begin{macrocode}
%<@@=cs>
%    \end{macrocode}
%
% \begin{macro}{\cs_log:N, \cs_log:c}
%   Use \cs{cs_show:N} or \cs{cs_show:c} after calling
%   \cs{__msg_log_next:} to redirect their output to the log file only.
%   Note that \cs{cs_log:c} is not just a variant of \cs{cs_log:N} as
%   the csname should be turned to a control sequence within a group
%   (see \cs{cs_show:c}).
%    \begin{macrocode}
\cs_new_protected:Npn \cs_log:N
  { \__msg_log_next: \cs_show:N }
\cs_new_protected:Npn \cs_log:c
  { \__msg_log_next: \cs_show:c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\__kernel_register_log:N, \__kernel_register_log:c}
%   Redirect the output of \cs{__kernel_register_show:N} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \__kernel_register_log:N
  { \__msg_log_next: \__kernel_register_show:N }
\cs_generate_variant:Nn \__kernel_register_log:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3box}}
%
%    \begin{macrocode}
%<@@=box>
%    \end{macrocode}
%
% \subsection{Affine transformations}
%
% \begin{variable}{\l_@@_angle_fp}
%   When rotating boxes, the angle itself may be needed by the
%   engine-dependent code. This is done using the \pkg{fp} module so
%   that the value is tidied up properly.
%    \begin{macrocode}
\fp_new:N \l_@@_angle_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
%   These are used to hold the calculated sine and cosine values while
%   carrying out a rotation.
%    \begin{macrocode}
\fp_new:N \l_@@_cos_fp
\fp_new:N \l_@@_sin_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\l_@@_top_dim, \l_@@_bottom_dim, \l_@@_left_dim, \l_@@_right_dim}
%   These are the positions of the four edges of a box before
%   manipulation.
%    \begin{macrocode}
\dim_new:N \l_@@_top_dim
\dim_new:N \l_@@_bottom_dim
\dim_new:N \l_@@_left_dim
\dim_new:N \l_@@_right_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%  {
%    \l_@@_top_new_dim,  \l_@@_bottom_new_dim ,
%    \l_@@_left_new_dim, \l_@@_right_new_dim
%  }
%   These are the positions of the four edges of a box after
%   manipulation.
%    \begin{macrocode}
\dim_new:N \l_@@_top_new_dim
\dim_new:N \l_@@_bottom_new_dim
\dim_new:N \l_@@_left_new_dim
\dim_new:N \l_@@_right_new_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_internal_box}
%   Scratch space, but also needed by some parts of the driver.
%    \begin{macrocode}
\box_new:N \l_@@_internal_box
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\box_rotate:Nn}
% \begin{macro}[aux]{\@@_rotate:N}
% \begin{macro}[aux]{\@@_rotate_x:nnN, \@@_rotate_y:nnN}
% \begin{macro}[aux]
%   {
%     \@@_rotate_quadrant_one:,   \@@_rotate_quadrant_two:,
%     \@@_rotate_quadrant_three:, \@@_rotate_quadrant_four:
%   }
%   Rotation of a box starts with working out the relevant sine and
%   cosine. The actual rotation is in an auxiliary to keep the flow slightly
%   clearer
%    \begin{macrocode}
\cs_new_protected:Npn \box_rotate:Nn #1#2
  {
    \hbox_set:Nn #1
      {
        \group_begin:
          \fp_set:Nn \l_@@_angle_fp {#2}
          \fp_set:Nn \l_@@_sin_fp { sind ( \l_@@_angle_fp ) }
          \fp_set:Nn \l_@@_cos_fp { cosd ( \l_@@_angle_fp ) }
          \@@_rotate:N #1
        \group_end:
    }
  }
%    \end{macrocode}
%   The edges of the box are then recorded: the left edge will
%   always be at zero. Rotation of the four edges then takes place: this is
%   most efficiently done on a quadrant by quadrant basis.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate:N #1
  {
    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
    \dim_zero:N \l_@@_left_dim
%    \end{macrocode}
%   The next step is to work out the $x$ and $y$ coordinates of vertices of
%   the rotated box in relation to its original coordinates. The box can be
%   visualized with vertices $B$, $C$, $D$ and $E$ is illustrated
%   (Figure~\ref{fig:l3candidates:rotation}). The vertex $O$ is the reference point
%   on the baseline, and in this implementation is also the centre of rotation.
%   \begin{figure}
%     \centering
%     \setlength{\unitlength}{3pt}^^A
%     \begin{picture}(34,36)(12,44)
%       \thicklines
%       \put(20,52){\dashbox{1}(20,21){}}
%       \put(20,80){\line(0,-1){36}}
%       \put(12,58){\line(1, 0){34}}
%       \put(41,59){A}
%       \put(40,74){B}
%       \put(21,74){C}
%       \put(21,49){D}
%       \put(40,49){E}
%       \put(21,59){O}
%     \end{picture}
%     \caption{Co-ordinates of a box prior to rotation.}
%     \label{fig:l3candidates:rotation}
%   \end{figure}
%   The formulae are, for a point $P$ and angle $\alpha$:
%   \[
%     \begin{array}{l}
%       P'_x = P_x - O_x \\
%       P'_y = P_y - O_y \\
%       P''_x =  ( P'_x \cos(\alpha)) - ( P'_y \sin(\alpha) ) \\
%       P''_y =  ( P'_x \sin(\alpha)) + ( P'_y \cos(\alpha) ) \\
%       P'''_x = P''_x + O_x + L_x \\
%       P'''_y = P''_y + O_y
%    \end{array}
%   \]
%   The \enquote{extra} horizontal translation $L_x$ at the end is calculated
%   so that the leftmost point of the resulting box has $x$-coordinate $0$.
%   This is desirable as \TeX{} boxes must have the reference point at
%   the left edge of the box. (As $O$ is always $(0,0)$, this part of the
%   calculation is omitted here.)
%    \begin{macrocode}
    \fp_compare:nNnTF \l_@@_sin_fp > \c_zero_fp
      {
        \fp_compare:nNnTF \l_@@_cos_fp > \c_zero_fp
          { \@@_rotate_quadrant_one: }
          { \@@_rotate_quadrant_two: }
      }
      {
        \fp_compare:nNnTF \l_@@_cos_fp < \c_zero_fp
          { \@@_rotate_quadrant_three: }
          { \@@_rotate_quadrant_four: }
      }
%    \end{macrocode}
%   The position of the box edges are now known, but the box at this
%   stage be misplaced relative to the current \TeX{} reference point. So the
%   content of the box is moved such that the reference point of the
%   rotated box will be in the same place as the original.
%    \begin{macrocode}
    \hbox_set:Nn \l_@@_internal_box { \box_use:N #1 }
    \hbox_set:Nn \l_@@_internal_box
      {
        \tex_kern:D -\l_@@_left_new_dim
        \hbox:n
          {
            \__driver_box_use_rotate:Nn
              \l_@@_internal_box
              \l_@@_angle_fp
          }
      }
%    \end{macrocode}
%   Tidy up the size of the box so that the material is actually inside
%   the bounding box. The result can then be used to reset the original
%   box.
%    \begin{macrocode}
    \box_set_ht:Nn \l_@@_internal_box {  \l_@@_top_new_dim }
    \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
    \box_set_wd:Nn \l_@@_internal_box
      { \l_@@_right_new_dim - \l_@@_left_new_dim }
    \box_use:N \l_@@_internal_box
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%   These functions take a general point $(|#1|, |#2|)$ and rotate its
%   location about the origin, using the previously-set sine and cosine
%   values. Each function gives only one component of the location of the
%   updated point. This is because for rotation of a box each step needs
%   only one value, and so performance is gained by avoiding working
%   out both $x'$ and $y'$ at the same time. Contrast this with
%   the equivalent function in the \pkg{l3coffins} module, where both parts
%   are needed.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate_x:nnN #1#2#3
  {
    \dim_set:Nn #3
      {
        \fp_to_dim:n
          {
              \l_@@_cos_fp * \dim_to_fp:n {#1}
            - \l_@@_sin_fp * \dim_to_fp:n {#2}
          }
      }
  }
\cs_new_protected:Npn \@@_rotate_y:nnN #1#2#3
  {
    \dim_set:Nn #3
      {
        \fp_to_dim:n
          {
              \l_@@_sin_fp * \dim_to_fp:n {#1}
            + \l_@@_cos_fp * \dim_to_fp:n {#2}
          }
      }
  }
%    \end{macrocode}
%   Rotation of the edges is done using a different formula for each
%   quadrant. In every case, the top and bottom edges only need the
%   resulting $y$-values, whereas the left and right edges need the
%   $x$-values. Each case is a question of picking out which corner
%   ends up at with the maximum top, bottom, left and right value. Doing
%   this by hand means a lot less calculating and avoids lots of
%   comparisons.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate_quadrant_one:
  {
    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim
      \l_@@_top_new_dim
    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_bottom_dim
      \l_@@_bottom_new_dim
    \@@_rotate_x:nnN \l_@@_left_dim  \l_@@_top_dim
      \l_@@_left_new_dim
    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim
      \l_@@_right_new_dim
  }
\cs_new_protected:Npn \@@_rotate_quadrant_two:
  {
    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim
      \l_@@_top_new_dim
    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_top_dim
      \l_@@_bottom_new_dim
    \@@_rotate_x:nnN \l_@@_right_dim  \l_@@_top_dim
      \l_@@_left_new_dim
    \@@_rotate_x:nnN \l_@@_left_dim   \l_@@_bottom_dim
      \l_@@_right_new_dim
  }
\cs_new_protected:Npn \@@_rotate_quadrant_three:
  {
    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_bottom_dim
      \l_@@_top_new_dim
    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim
      \l_@@_bottom_new_dim
    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim
      \l_@@_left_new_dim
    \@@_rotate_x:nnN \l_@@_left_dim   \l_@@_top_dim
      \l_@@_right_new_dim
  }
\cs_new_protected:Npn \@@_rotate_quadrant_four:
  {
    \@@_rotate_y:nnN \l_@@_left_dim  \l_@@_top_dim
      \l_@@_top_new_dim
    \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim
      \l_@@_bottom_new_dim
    \@@_rotate_x:nnN \l_@@_left_dim  \l_@@_bottom_dim
      \l_@@_left_new_dim
    \@@_rotate_x:nnN \l_@@_right_dim \l_@@_top_dim
      \l_@@_right_new_dim
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{variable}{\l_@@_scale_x_fp, \l_@@_scale_y_fp}
%   Scaling is potentially-different in the two axes.
%    \begin{macrocode}
\fp_new:N \l_@@_scale_x_fp
\fp_new:N \l_@@_scale_y_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\box_resize:Nnn, \box_resize:cnn}
% \begin{macro}[aux]{\@@_resize_set_corners:N}
% \begin{macro}[aux]{\@@_resize:N}
% \begin{macro}[aux]{\@@_resize:NNN}
%   Resizing a box starts by working out the various dimensions of the
%   existing box.
%    \begin{macrocode}
\cs_new_protected:Npn \box_resize:Nnn #1#2#3
  {
    \hbox_set:Nn #1
      {
        \group_begin:
          \@@_resize_set_corners:N #1
%    \end{macrocode}
%   The $x$-scaling and resulting box size is easy enough to work
%   out: the dimension is that given as |#2|, and the scale is simply the
%   new width divided by the old one.
%    \begin{macrocode}
          \fp_set:Nn \l_@@_scale_x_fp
            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
%    \end{macrocode}
%   The $y$-scaling needs both the height and the depth of the current box.
%    \begin{macrocode}
          \fp_set:Nn \l_@@_scale_y_fp
            {
                \dim_to_fp:n {#3}
              / \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim }
            }
%    \end{macrocode}
%   Hand off to the auxiliary which does the rest of the work.
%    \begin{macrocode}
          \@@_resize:N #1
        \group_end:
      }
  }
\cs_generate_variant:Nn \box_resize:Nnn { c }
\cs_new_protected:Npn \@@_resize_set_corners:N #1
  {
    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
    \dim_zero:N \l_@@_left_dim
  }
%    \end{macrocode}
%   With at least one real scaling to do, the next phase is to find the new
%   edge co-ordinates. In the $x$~direction this is relatively easy: just
%   scale the right edge. In the $y$~direction, both dimensions have to be
%   scaled, and this again needs the absolute scale value.
%   Once that is all done, the common resize/rescale code can be employed.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_resize:N #1
  {
    \@@_resize:NNN \l_@@_right_new_dim
      \l_@@_scale_x_fp \l_@@_right_dim
    \@@_resize:NNN \l_@@_bottom_new_dim
      \l_@@_scale_y_fp \l_@@_bottom_dim
    \@@_resize:NNN \l_@@_top_new_dim
      \l_@@_scale_y_fp \l_@@_top_dim
    \@@_resize_common:N #1
  }
\cs_new_protected:Npn \@@_resize:NNN #1#2#3
  {
    \dim_set:Nn #1
      { \fp_to_dim:n { \fp_abs:n { #2 } * \dim_to_fp:n { #3 } } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\box_resize_to_ht:Nn, \box_resize_to_ht:cn}
% \begin{macro}{\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn}
% \begin{macro}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn}
% \begin{macro}{\box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn}
%   Scaling to a (total) height or to a width is a simplified version of the main
%   resizing operation, with the scale simply copied between the two parts. The
%   internal auxiliary is called using the scaling value twice, as the sign for
%   both parts is needed (as this allows the same internal code to be used as
%   for the general case).
%    \begin{macrocode}
\cs_new_protected:Npn \box_resize_to_ht:Nn #1#2
  {
    \hbox_set:Nn #1
      {
        \group_begin:
          \@@_resize_set_corners:N #1
          \fp_set:Nn \l_@@_scale_y_fp
            {
                \dim_to_fp:n {#2}
              / \dim_to_fp:n { \l_@@_top_dim }
            }
          \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp
          \@@_resize:N #1
        \group_end:
      }
  }
\cs_generate_variant:Nn \box_resize_to_ht:Nn { c }
\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2
  {
    \hbox_set:Nn #1
      {
        \group_begin:
          \@@_resize_set_corners:N #1
          \fp_set:Nn \l_@@_scale_y_fp
            {
                \dim_to_fp:n {#2}
              / \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim }
            }
          \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp
          \@@_resize:N #1
        \group_end:
      }
  }
\cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c }
\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2
  {
    \hbox_set:Nn #1
      {
        \group_begin:
          \@@_resize_set_corners:N #1
          \fp_set:Nn \l_@@_scale_x_fp
            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
          \fp_set_eq:NN \l_@@_scale_y_fp \l_@@_scale_x_fp
          \@@_resize:N #1
        \group_end:
      }
  }
\cs_generate_variant:Nn \box_resize_to_wd:Nn { c }
\cs_new_protected:Npn \box_resize_to_wd_and_ht:Nnn #1#2#3
  {
    \hbox_set:Nn #1
      {
        \group_begin:
          \@@_resize_set_corners:N #1
          \fp_set:Nn \l_@@_scale_x_fp
            { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
          \fp_set:Nn \l_@@_scale_y_fp
            {
                \dim_to_fp:n {#3}
              / \dim_to_fp:n { \l_@@_top_dim }
            }
          \@@_resize:N #1
        \group_end:
      }
  }
\cs_generate_variant:Nn \box_resize_to_wd_and_ht:Nnn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\box_scale:Nnn, \box_scale:cnn}
%   When scaling a box, setting the scaling itself is easy enough. The
%   new dimensions are also relatively easy to find, allowing only for
%   the need to keep them positive in all cases. Once that is done then
%   after a check for the trivial scaling a hand-off can be made to the
%   common code. The dimension scaling operations are carried out using
%   the \TeX{} mechanism as it avoids needing to use too many \texttt{fp}
%   operations.
%    \begin{macrocode}
\cs_new_protected:Npn \box_scale:Nnn #1#2#3
  {
    \hbox_set:Nn #1
      {
        \group_begin:
          \fp_set:Nn \l_@@_scale_x_fp {#2}
          \fp_set:Nn \l_@@_scale_y_fp {#3}
          \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
          \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
          \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
          \dim_zero:N \l_@@_left_dim
          \dim_set:Nn \l_@@_top_new_dim
            { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_top_dim }
          \dim_set:Nn \l_@@_bottom_new_dim
            { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_bottom_dim }
          \dim_set:Nn \l_@@_right_new_dim
              { \fp_abs:n { \l_@@_scale_x_fp } \l_@@_right_dim }
           \@@_resize_common:N #1
        \group_end:
      }
  }
\cs_generate_variant:Nn \box_scale:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_resize_common:N}
%   The main resize function places in input into a box which will start
%   of with zero width, and includes the handles for engine rescaling.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_resize_common:N #1
  {
    \hbox_set:Nn \l_@@_internal_box
      {
        \__driver_box_use_scale:Nnn
          #1
          \l_@@_scale_x_fp
          \l_@@_scale_y_fp
      }
%    \end{macrocode}
%   The new height and depth can be applied directly.
%    \begin{macrocode}
    \fp_compare:nNnTF \l_@@_scale_y_fp > \c_zero_fp
      {
        \box_set_ht:Nn \l_@@_internal_box { \l_@@_top_new_dim }
        \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
      }
      {
        \box_set_dp:Nn \l_@@_internal_box { \l_@@_top_new_dim }
        \box_set_ht:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
      }
%    \end{macrocode}
%   Things are not quite as obvious for the width, as the reference point
%   needs to remain unchanged. For positive scaling factors resizing the
%   box is all that is needed. However, for case of a negative scaling
%   the material must be shifted such that the reference point ends up in
%   the right place.
%    \begin{macrocode}
    \fp_compare:nNnTF \l_@@_scale_x_fp < \c_zero_fp
      {
        \hbox_to_wd:nn { \l_@@_right_new_dim }
          {
            \tex_kern:D \l_@@_right_new_dim
            \box_use:N \l_@@_internal_box
            \tex_hss:D
          }
      }
      {
        \box_set_wd:Nn \l_@@_internal_box { \l_@@_right_new_dim }
        \hbox:n
          {
            \tex_kern:D \c_zero_dim
            \box_use:N \l_@@_internal_box
            \tex_hss:D
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Viewing part of a box}
%
% \begin{macro}{\box_clip:N, \box_clip:c}
%   A wrapper around the driver-dependent code.
%    \begin{macrocode}
\cs_new_protected:Npn \box_clip:N #1
  { \hbox_set:Nn #1 { \__driver_box_use_clip:N #1 } }
\cs_generate_variant:Nn \box_clip:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\box_trim:Nnnnn, \box_trim:cnnnn}
%   Trimming from the left- and right-hand edges of the box is easy: kern the
%   appropriate parts off each side.
%    \begin{macrocode}
\cs_new_protected:Npn \box_trim:Nnnnn #1#2#3#4#5
  {
    \hbox_set:Nn \l_@@_internal_box
      {
        \tex_kern:D -\__dim_eval:w #2 \__dim_eval_end:
        \box_use:N #1
        \tex_kern:D -\__dim_eval:w #4 \__dim_eval_end:
      }
%    \end{macrocode}
%   For the height and depth, there is a need to watch the baseline is
%   respected. Material always has to stay on the correct side, so trimming
%   has to check that there is enough material to trim. First, the bottom
%   edge. If there is enough depth, simply set the depth, or if not move
%   down so the result is zero depth. \cs{box_move_down:nn} is used in both
%   cases so the resulting box always contains a \tn{lower} primitive.
%   The internal box is used here as it allows safe use of \cs{box_set_dp:Nn}.
%    \begin{macrocode}
    \dim_compare:nNnTF { \box_dp:N #1 } > {#3}
      {
        \hbox_set:Nn \l_@@_internal_box
          {
            \box_move_down:nn \c_zero_dim
              { \box_use:N \l_@@_internal_box }
          }
        \box_set_dp:Nn \l_@@_internal_box { \box_dp:N #1 - (#3) }
      }
      {
        \hbox_set:Nn \l_@@_internal_box
          {
            \box_move_down:nn { #3 - \box_dp:N #1 }
              { \box_use:N \l_@@_internal_box }
          }
        \box_set_dp:Nn \l_@@_internal_box \c_zero_dim
      }
%    \end{macrocode}
%   Same thing, this time from the top of the box.
%    \begin{macrocode}
    \dim_compare:nNnTF { \box_ht:N \l_@@_internal_box } > {#5}
      {
        \hbox_set:Nn \l_@@_internal_box
          {
            \box_move_up:nn \c_zero_dim
              { \box_use:N \l_@@_internal_box }
          }
        \box_set_ht:Nn \l_@@_internal_box
          { \box_ht:N \l_@@_internal_box - (#5) }
      }
      {
        \hbox_set:Nn \l_@@_internal_box
          {
            \box_move_up:nn { #5 - \box_ht:N \l_@@_internal_box }
              { \box_use:N \l_@@_internal_box }
          }
        \box_set_ht:Nn \l_@@_internal_box \c_zero_dim
      }
    \box_set_eq:NN #1 \l_@@_internal_box
  }
\cs_generate_variant:Nn \box_trim:Nnnnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\box_viewport:Nnnnn, \box_viewport:cnnnn}
%   The same general logic as for the trim operation, but with absolute
%   dimensions. As a result, there are some things to watch out for in the
%   vertical direction.
%    \begin{macrocode}
\cs_new_protected:Npn \box_viewport:Nnnnn #1#2#3#4#5
  {
    \hbox_set:Nn \l_@@_internal_box
      {
        \tex_kern:D -\__dim_eval:w #2 \__dim_eval_end:
        \box_use:N #1
        \tex_kern:D \__dim_eval:w #4 - \box_wd:N #1 \__dim_eval_end:
      }
    \dim_compare:nNnTF {#3} < \c_zero_dim
      {
        \hbox_set:Nn \l_@@_internal_box
          {
            \box_move_down:nn \c_zero_dim
              { \box_use:N \l_@@_internal_box }
          }
        \box_set_dp:Nn \l_@@_internal_box { -\dim_eval:n {#3} }
      }
      {
        \hbox_set:Nn \l_@@_internal_box
          { \box_move_down:nn {#3} { \box_use:N \l_@@_internal_box } }
        \box_set_dp:Nn \l_@@_internal_box \c_zero_dim
      }
    \dim_compare:nNnTF {#5} > \c_zero_dim
      {
        \hbox_set:Nn \l_@@_internal_box
          {
            \box_move_up:nn \c_zero_dim
              { \box_use:N \l_@@_internal_box }
          }
        \box_set_ht:Nn \l_@@_internal_box
          {
            #5
            \dim_compare:nNnT {#3} > \c_zero_dim
              { - (#3) }
          }
      }
      {
        \hbox_set:Nn \l_@@_internal_box
          {
            \box_move_up:nn { -\dim_eval:n {#5} }
              { \box_use:N \l_@@_internal_box }
          }
        \box_set_ht:Nn \l_@@_internal_box \c_zero_dim
      }
    \box_set_eq:NN #1 \l_@@_internal_box
  }
\cs_generate_variant:Nn \box_viewport:Nnnnn { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3clist}}
%
%    \begin{macrocode}
%<@@=clist>
%    \end{macrocode}
%
% \begin{macro}{\clist_log:N, \clist_log:c, \clist_log:n}
%   Redirect output of \cs{clist_show:N} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \clist_log:N
  { \__msg_log_next: \clist_show:N }
\cs_new_protected:Npn \clist_log:n
  { \__msg_log_next: \clist_show:n }
\cs_generate_variant:Nn \clist_log:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3coffins}}
%
%    \begin{macrocode}
%<@@=coffin>
%    \end{macrocode}
%
% \subsection{Rotating coffins}
%
% \begin{variable}{\l_@@_sin_fp}
% \begin{variable}{\l_@@_cos_fp}
%   Used for rotations to get the sine and cosine values.
%    \begin{macrocode}
\fp_new:N \l_@@_sin_fp
\fp_new:N \l_@@_cos_fp
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \begin{variable}{\l_@@_bounding_prop}
%   A property list for the bounding box of a coffin. This is only needed
%   during the rotation, so there is just the one.
%    \begin{macrocode}
\prop_new:N \l_@@_bounding_prop
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_bounding_shift_dim}
%   The shift of the bounding box of a coffin from the real content.
%    \begin{macrocode}
\dim_new:N \l_@@_bounding_shift_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_left_corner_dim}
% \begin{variable}{\l_@@_right_corner_dim}
% \begin{variable}{\l_@@_bottom_corner_dim}
% \begin{variable}{\l_@@_top_corner_dim}
%   These are used to hold maxima for the various corner values: these
%   thus define the minimum size of the bounding box after rotation.
%    \begin{macrocode}
\dim_new:N \l_@@_left_corner_dim
\dim_new:N \l_@@_right_corner_dim
\dim_new:N \l_@@_bottom_corner_dim
\dim_new:N \l_@@_top_corner_dim
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{variable}
% \end{variable}
%
% \begin{macro}{\coffin_rotate:Nn, \coffin_rotate:cn}
%   Rotating a coffin requires several steps which can be conveniently
%   run together. The sine and cosine of the angle in degrees are
%   computed.  This is then used to set \cs{l_@@_sin_fp} and
%   \cs{l_@@_cos_fp}, which are carried through unchanged for the rest
%   of the procedure.
%    \begin{macrocode}
\cs_new_protected:Npn \coffin_rotate:Nn #1#2
  {
    \fp_set:Nn \l_@@_sin_fp { sind ( #2 ) }
    \fp_set:Nn \l_@@_cos_fp { cosd ( #2 ) }
%    \end{macrocode}
%   The corners and poles of the coffin can now be rotated around the
%    origin. This is best achieved using mapping functions.
%    \begin{macrocode}
    \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
      { \@@_rotate_corner:Nnnn #1 {##1} ##2 }
    \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
      { \@@_rotate_pole:Nnnnnn #1 {##1} ##2 }
%    \end{macrocode}
%   The bounding box of the coffin needs to be rotated, and to do this
%   the corners have to be found first. They are then rotated in the same
%   way as the corners of the coffin material itself.
%    \begin{macrocode}
    \@@_set_bounding:N #1
    \prop_map_inline:Nn \l_@@_bounding_prop
      { \@@_rotate_bounding:nnn {##1} ##2 }
%    \end{macrocode}
%   At this stage, there needs to be a calculation to find where the
%   corners of the content and the box itself will end up.
%    \begin{macrocode}
    \@@_find_corner_maxima:N #1
    \@@_find_bounding_shift:
    \box_rotate:Nn #1 {#2}
%    \end{macrocode}
%   The correction of the box position itself takes place here. The idea
%   is that the bounding box for a coffin is tight up to the content, and
%   has the reference point at the bottom-left. The $x$-direction is
%   handled by moving the content by the difference in the positions of
%   the bounding box and the content left edge. The $y$-direction is
%   dealt with by moving the box down by any depth it has acquired. The
%   internal box is used here to allow for the next step.
%    \begin{macrocode}
    \hbox_set:Nn \l_@@_internal_box
      {
        \tex_kern:D
          \__dim_eval:w
            \l_@@_bounding_shift_dim - \l_@@_left_corner_dim
          \__dim_eval_end:
        \box_move_down:nn { \l_@@_bottom_corner_dim }
          { \box_use:N #1 }
      }
%    \end{macrocode}
%   If there have been any previous rotations then the size of the
%   bounding box will be bigger than the contents. This can be corrected
%   easily by setting the size of the box to the height and width of the
%   content. As this operation requires setting box dimensions and these
%   transcend grouping, the safe way to do this is to use the internal box
%   and to reset the result into the target box.
%    \begin{macrocode}
    \box_set_ht:Nn \l_@@_internal_box
      { \l_@@_top_corner_dim - \l_@@_bottom_corner_dim }
    \box_set_dp:Nn \l_@@_internal_box { 0 pt }
    \box_set_wd:Nn \l_@@_internal_box
      { \l_@@_right_corner_dim - \l_@@_left_corner_dim }
    \hbox_set:Nn #1 { \box_use:N \l_@@_internal_box }
%    \end{macrocode}
%   The final task is to move the poles and corners such that they are
%   back in alignment with the box reference point.
%    \begin{macrocode}
    \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
      { \@@_shift_corner:Nnnn #1 {##1} ##2 }
    \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
      { \@@_shift_pole:Nnnnnn #1 {##1} ##2 }
  }
\cs_generate_variant:Nn \coffin_rotate:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_bounding:N}
%   The bounding box corners for a coffin are easy enough to find: this
%   is the same code as for the corners of the material itself, but
%   using a dedicated property list.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_bounding:N #1
  {
    \prop_put:Nnx \l_@@_bounding_prop { tl }
      { { 0 pt } { \dim_eval:n { \box_ht:N #1 } } }
    \prop_put:Nnx \l_@@_bounding_prop { tr }
      { { \dim_eval:n { \box_wd:N #1 } } { \dim_eval:n { \box_ht:N #1 } } }
    \dim_set:Nn \l_@@_internal_dim { -\box_dp:N #1 }
    \prop_put:Nnx \l_@@_bounding_prop { bl }
      { { 0 pt } { \dim_use:N \l_@@_internal_dim } }
    \prop_put:Nnx \l_@@_bounding_prop { br }
      { { \dim_eval:n { \box_wd:N #1 } } { \dim_use:N \l_@@_internal_dim } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_rotate_bounding:nnn}
% \begin{macro}{\@@_rotate_corner:Nnnn}
%   Rotating the position of the corner of the coffin is just a case
%   of treating this as a vector from the reference point. The same
%   treatment is used for the corners of the material itself and the
%   bounding box.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate_bounding:nnn #1#2#3
  {
    \@@_rotate_vector:nnNN {#2} {#3} \l_@@_x_dim \l_@@_y_dim
    \prop_put:Nnx \l_@@_bounding_prop {#1}
      { { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } }
  }
\cs_new_protected:Npn \@@_rotate_corner:Nnnn #1#2#3#4
  {
    \@@_rotate_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim
    \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2}
      { { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_rotate_pole:Nnnnnn}
%   Rotating a single pole simply means shifting the co-ordinate of
%   the pole and its direction. The rotation here is about the bottom-left
%   corner of the coffin.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate_pole:Nnnnnn #1#2#3#4#5#6
  {
    \@@_rotate_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim
    \@@_rotate_vector:nnNN {#5} {#6}
      \l_@@_x_prime_dim \l_@@_y_prime_dim
    \@@_set_pole:Nnx #1 {#2}
      {
        { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim }
        { \dim_use:N \l_@@_x_prime_dim }
        { \dim_use:N \l_@@_y_prime_dim }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_rotate_vector:nnNN}
%   A rotation function, which needs only an input vector (as dimensions)
%   and an output space. The values \cs{l_@@_cos_fp} and
%   \cs{l_@@_sin_fp} should previously have been set up correctly.
%   Working this way means that the floating point work is kept to a
%   minimum: for any given rotation the sin and cosine values do no
%   change, after all.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate_vector:nnNN #1#2#3#4
  {
    \dim_set:Nn #3
      {
        \fp_to_dim:n
          {
              \dim_to_fp:n {#1} * \l_@@_cos_fp
            - \dim_to_fp:n {#2} * \l_@@_sin_fp
          }
      }
    \dim_set:Nn #4
      {
        \fp_to_dim:n
          {
              \dim_to_fp:n {#1} * \l_@@_sin_fp
            + \dim_to_fp:n {#2} * \l_@@_cos_fp
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_find_corner_maxima:N}
% \begin{macro}[aux]{\@@_find_corner_maxima_aux:nn}
%   The idea here is to find the extremities of the content of the
%   coffin. This is done by looking for the smallest values for the bottom
%   and left corners, and the largest values for the top and right
%   corners. The values start at the maximum dimensions so that the
%   case where all are positive or all are negative works out correctly.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_find_corner_maxima:N #1
  {
    \dim_set:Nn \l_@@_top_corner_dim   { -\c_max_dim }
    \dim_set:Nn \l_@@_right_corner_dim { -\c_max_dim }
    \dim_set:Nn \l_@@_bottom_corner_dim { \c_max_dim }
    \dim_set:Nn \l_@@_left_corner_dim   { \c_max_dim }
    \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
      { \@@_find_corner_maxima_aux:nn ##2 }
  }
\cs_new_protected:Npn \@@_find_corner_maxima_aux:nn #1#2
  {
    \dim_set:Nn \l_@@_left_corner_dim
     { \dim_min:nn { \l_@@_left_corner_dim } {#1} }
    \dim_set:Nn \l_@@_right_corner_dim
     { \dim_max:nn { \l_@@_right_corner_dim } {#1} }
    \dim_set:Nn \l_@@_bottom_corner_dim
     { \dim_min:nn { \l_@@_bottom_corner_dim } {#2} }
    \dim_set:Nn \l_@@_top_corner_dim
     { \dim_max:nn { \l_@@_top_corner_dim } {#2} }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_find_bounding_shift:}
% \begin{macro}[aux]{\@@_find_bounding_shift_aux:nn}
%   The approach to finding the shift for the bounding box is similar to
%   that for the corners. However, there is only one value needed here and
%   a fixed input property list, so things are a bit clearer.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_find_bounding_shift:
  {
    \dim_set:Nn \l_@@_bounding_shift_dim { \c_max_dim }
    \prop_map_inline:Nn \l_@@_bounding_prop
      { \@@_find_bounding_shift_aux:nn ##2 }
  }
\cs_new_protected:Npn \@@_find_bounding_shift_aux:nn #1#2
  {
    \dim_set:Nn \l_@@_bounding_shift_dim
      { \dim_min:nn { \l_@@_bounding_shift_dim } {#1} }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_shift_corner:Nnnn}
% \begin{macro}{\@@_shift_pole:Nnnnnn}
%   Shifting the corners and poles of a coffin means subtracting the
%   appropriate values from the $x$- and $y$-components. For
%   the poles, this means that the direction vector is unchanged.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_shift_corner:Nnnn #1#2#3#4
  {
    \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _ prop } {#2}
      {
        { \dim_eval:n { #3 - \l_@@_left_corner_dim } }
        { \dim_eval:n { #4 - \l_@@_bottom_corner_dim } }
      }
  }
\cs_new_protected:Npn \@@_shift_pole:Nnnnnn #1#2#3#4#5#6
  {
    \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _ prop } {#2}
      {
        { \dim_eval:n { #3 - \l_@@_left_corner_dim } }
        { \dim_eval:n { #4 - \l_@@_bottom_corner_dim } }
        {#5} {#6}
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Resizing coffins}
%
% \begin{variable}{\l_@@_scale_x_fp}
% \begin{variable}{\l_@@_scale_y_fp}
%   Storage for the scaling factors in $x$ and $y$, respectively.
%    \begin{macrocode}
\fp_new:N \l_@@_scale_x_fp
\fp_new:N \l_@@_scale_y_fp
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \begin{variable}{\l_@@_scaled_total_height_dim}
% \begin{variable}{\l_@@_scaled_width_dim}
%   When scaling, the values given have to be turned into absolute values.
%    \begin{macrocode}
\dim_new:N \l_@@_scaled_total_height_dim
\dim_new:N \l_@@_scaled_width_dim
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \begin{macro}{\coffin_resize:Nnn, \coffin_resize:cnn}
%   Resizing a coffin begins by setting up the user-friendly names for
%   the dimensions of the coffin box. The new sizes are then turned into
%   scale factor. This is the same operation as takes place for the
%   underlying box, but that operation is grouped and so the same
%   calculation is done here.
%    \begin{macrocode}
\cs_new_protected:Npn \coffin_resize:Nnn #1#2#3
  {
    \fp_set:Nn \l_@@_scale_x_fp
      { \dim_to_fp:n {#2} / \dim_to_fp:n { \coffin_wd:N #1 } }
    \fp_set:Nn \l_@@_scale_y_fp
      {
          \dim_to_fp:n {#3}
        / \dim_to_fp:n { \coffin_ht:N #1 + \coffin_dp:N #1 }
      }
    \box_resize:Nnn #1 {#2} {#3}
    \@@_resize_common:Nnn #1 {#2} {#3}
  }
\cs_generate_variant:Nn \coffin_resize:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_resize_common:Nnn}
%   The poles and corners of the coffin are scaled to the appropriate
%   places before actually resizing the underlying box.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_resize_common:Nnn #1#2#3
  {
    \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
      { \@@_scale_corner:Nnnn #1 {##1} ##2 }
    \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
      { \@@_scale_pole:Nnnnnn #1 {##1} ##2 }
%    \end{macrocode}
%   Negative $x$-scaling values will place the poles in the wrong
%   location: this is corrected here.
%    \begin{macrocode}
    \fp_compare:nNnT \l_@@_scale_x_fp < \c_zero_fp
      {
        \prop_map_inline:cn { l_@@_corners_ \__int_value:w #1 _prop }
          { \@@_x_shift_corner:Nnnn #1 {##1} ##2 }
        \prop_map_inline:cn { l_@@_poles_ \__int_value:w #1 _prop }
          { \@@_x_shift_pole:Nnnnnn #1 {##1} ##2 }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\coffin_scale:Nnn, \coffin_scale:cnn}
%   For scaling, the opposite calculation is done to find the new
%   dimensions for the coffin. Only the total height is needed, as this
%   is the shift required for corners and poles. The scaling is done
%   the \TeX{} way as this works properly with floating point values
%   without needing to use the \texttt{fp} module.
%    \begin{macrocode}
\cs_new_protected:Npn \coffin_scale:Nnn #1#2#3
  {
    \fp_set:Nn \l_@@_scale_x_fp {#2}
    \fp_set:Nn \l_@@_scale_y_fp {#3}
    \box_scale:Nnn #1 { \l_@@_scale_x_fp } { \l_@@_scale_y_fp }
    \dim_set:Nn \l_@@_internal_dim
      { \coffin_ht:N #1 + \coffin_dp:N #1 }
    \dim_set:Nn \l_@@_scaled_total_height_dim
      { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_internal_dim }
    \dim_set:Nn \l_@@_scaled_width_dim
      { -\fp_abs:n { \l_@@_scale_x_fp  } \coffin_wd:N #1 }
    \@@_resize_common:Nnn #1
      { \l_@@_scaled_width_dim } { \l_@@_scaled_total_height_dim }
  }
\cs_generate_variant:Nn \coffin_scale:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_scale_vector:nnNN}
%   This functions scales a vector from the origin using the pre-set scale
%   factors in $x$ and $y$. This is a much less complex operation
%   than rotation, and as a result the code is a lot clearer.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_scale_vector:nnNN #1#2#3#4
  {
    \dim_set:Nn #3
      { \fp_to_dim:n { \dim_to_fp:n {#1} * \l_@@_scale_x_fp } }
    \dim_set:Nn #4
      { \fp_to_dim:n { \dim_to_fp:n {#2} * \l_@@_scale_y_fp } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_scale_corner:Nnnn}
% \begin{macro}{\@@_scale_pole:Nnnnnn}
%   Scaling both corners and poles is a simple calculation using the
%   preceding vector scaling.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_scale_corner:Nnnn #1#2#3#4
  {
    \@@_scale_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim
    \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2}
      { { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim } }
  }
\cs_new_protected:Npn \@@_scale_pole:Nnnnnn #1#2#3#4#5#6
  {
    \@@_scale_vector:nnNN {#3} {#4} \l_@@_x_dim \l_@@_y_dim
    \@@_set_pole:Nnx #1 {#2}
      {
        { \dim_use:N \l_@@_x_dim } { \dim_use:N \l_@@_y_dim }
        {#5} {#6}
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_x_shift_corner:Nnnn}
% \begin{macro}{\@@_x_shift_pole:Nnnnnn}
%   These functions correct for the $x$ displacement that takes
%   place with a negative horizontal scaling.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_x_shift_corner:Nnnn #1#2#3#4
  {
    \prop_put:cnx { l_@@_corners_ \__int_value:w #1 _prop } {#2}
      {
        { \dim_eval:n { #3 + \box_wd:N #1 } } {#4}
      }
  }
\cs_new_protected:Npn \@@_x_shift_pole:Nnnnnn #1#2#3#4#5#6
  {
    \prop_put:cnx { l_@@_poles_ \__int_value:w #1 _prop } {#2}
      {
        { \dim_eval:n #3 + \box_wd:N #1 } {#4}
        {#5} {#6}
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Coffin diagnostics}
%
% \begin{macro}{\coffin_log_structure:N, \coffin_log_structure:c}
%   Redirect output of \cs{coffin_show_structure:N} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \coffin_log_structure:N
  { \__msg_log_next: \coffin_show_structure:N }
\cs_generate_variant:Nn \coffin_log_structure:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3file}}
%
%    \begin{macrocode}
%<@@=file>
%    \end{macrocode}
%
% \begin{macro}[TF]{\file_if_exist_input:n}
%   Input of a file with a test for existence cannot be done the usual
%   way as the tokens to insert are in an odd place.
%    \begin{macrocode}
\cs_new_protected:Npn \file_if_exist_input:n #1
  {
    \file_if_exist:nT {#1}
      { \@@_input:V \l_@@_internal_name_tl }
  }
\cs_new_protected:Npn \file_if_exist_input:nT #1#2
  {
    \file_if_exist:nT {#1}
      {
        #2
        \@@_input:V \l_@@_internal_name_tl
      }
  }
\cs_new_protected:Npn \file_if_exist_input:nF #1
  {
    \file_if_exist:nTF {#1}
      { \@@_input:V \l_@@_internal_name_tl }
  }
\cs_new_protected:Npn \file_if_exist_input:nTF #1#2
  {
    \file_if_exist:nTF {#1}
      {
        #2
        \@@_input:V \l_@@_internal_name_tl
      }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%<@@=ior>
%    \end{macrocode}
%
% \begin{macro}[EXP]{\ior_map_break:, \ior_map_break:n}
%   Usual map breaking functions.  Those are not yet in \pkg{l3kernel}
%   proper since the mapping below is the first of its kind.
%    \begin{macrocode}
\cs_new:Npn \ior_map_break:
  { \__prg_map_break:Nn \ior_map_break: { } }
\cs_new:Npn \ior_map_break:n
  { \__prg_map_break:Nn \ior_map_break: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ior_map_inline:Nn, \ior_str_map_inline:Nn}
% \begin{macro}[aux]{\@@_map_inline:NNn}
% \begin{macro}[aux]{\@@_map_inline:NNNn}
% \begin{macro}[aux]{\@@_map_inline_loop:NNN}
% \begin{variable}{\l_@@_internal_tl}
%   Mapping to an input stream can be done on either a token or a string
%   basis, hence the set up. Within that, there is a check to avoid reading
%   past the end of a file, hence the two applications of \cs{ior_if_eof:N}.
%   This mapping cannot be nested as the stream has only one \enquote{current
%   line}.
%    \begin{macrocode}
\cs_new_protected:Npn \ior_map_inline:Nn
  { \@@_map_inline:NNn \ior_get:NN }
\cs_new_protected:Npn \ior_str_map_inline:Nn
  { \@@_map_inline:NNn \ior_get_str:NN }
\cs_new_protected:Npn \@@_map_inline:NNn
  {
    \int_gincr:N \g__prg_map_int
    \exp_args:Nc \@@_map_inline:NNNn
      { __prg_map_ \int_use:N \g__prg_map_int :n }
  }
\cs_new_protected:Npn \@@_map_inline:NNNn #1#2#3#4
  {
    \cs_set:Npn #1 ##1 {#4}
    \ior_if_eof:NF #3 { \@@_map_inline_loop:NNN #1#2#3 }
    \__prg_break_point:Nn \ior_map_break:
      { \int_gdecr:N \g__prg_map_int }
  }
\cs_new_protected:Npn \@@_map_inline_loop:NNN #1#2#3
  {
    #2 #3 \l_@@_internal_tl
    \ior_if_eof:NF #3
      {
        \exp_args:No #1 \l_@@_internal_tl
        \@@_map_inline_loop:NNN #1#2#3
      }
  }
\tl_new:N  \l_@@_internal_tl
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ior_log_streams:}
%   Redirect output of \cs{ior_list_streams:} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \ior_log_streams:
  { \__msg_log_next: \ior_list_streams: }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%<@@=iow>
%    \end{macrocode}
%
% \begin{macro}{\iow_log_streams:}
%   Redirect output of \cs{iow_list_streams:} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \iow_log_streams:
  { \__msg_log_next: \iow_list_streams: }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3fp-assign}}
%
%    \begin{macrocode}
%<@@=fp>
%    \end{macrocode}
%
% \begin{macro}{\fp_log:N, \fp_log:c, \fp_log:n}
%   Redirect output of \cs{fp_show:N} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \fp_log:N
  { \__msg_log_next: \fp_show:N }
\cs_new_protected:Npn \fp_log:n
  { \__msg_log_next: \fp_show:n }
\cs_generate_variant:Nn \fp_log:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3int}}
%
% \begin{macro}{\int_log:N, \int_log:c}
%   Redirect output of \cs{int_show:N} to the log.  This is not just a
%   copy of \cs{__kernel_register_log:N} because of subtleties
%   involving \tn{currentgrouplevel} and \tn{currentgrouptype}.  See
%   \cs{int_show:N} for details.
%    \begin{macrocode}
\cs_new_protected:Npn \int_log:N
  { \__msg_log_next: \int_show:N }
\cs_generate_variant:Nn \int_log:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\int_log:n}
%   Redirect output of \cs{int_show:n} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \int_log:n
  { \__msg_log_next: \int_show:n }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3keys}}
%
%    \begin{macrocode}
%<@@=keys>
%    \end{macrocode}
%
% \begin{macro}{\keys_log:nn}
%   Redirect output of \cs{keys_show:nn} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \keys_log:nn
  { \__msg_log_next: \keys_show:nn }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3msg}}
%
%    \begin{macrocode}
%<@@=msg>
%    \end{macrocode}
%
% \begin{macro}[EXP]
%   {
%     \msg_expandable_error:nnnnnn ,
%     \msg_expandable_error:nnnnn  ,
%     \msg_expandable_error:nnnn   ,
%     \msg_expandable_error:nnn    ,
%     \msg_expandable_error:nn     ,
%     \msg_expandable_error:nnffff ,
%     \msg_expandable_error:nnfff  ,
%     \msg_expandable_error:nnff   ,
%     \msg_expandable_error:nnf
%   }
% \begin{macro}[aux]{\__msg_expandable_error_module:nn}
%   Pass to an auxiliary the message to display and the module name
%    \begin{macrocode}
\cs_new:Npn \msg_expandable_error:nnnnnn #1#2#3#4#5#6
  {
    \exp_args:Nf \@@_expandable_error_module:nn
      {
        \exp_args:Nf \tl_to_str:n
          { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} }
      }
      {#1}
  }
\cs_new:Npn \msg_expandable_error:nnnnn #1#2#3#4#5
  { \msg_expandable_error:nnnnnn {#1} {#2} {#3} {#4} {#5} { } }
\cs_new:Npn \msg_expandable_error:nnnn #1#2#3#4
  { \msg_expandable_error:nnnnnn {#1} {#2} {#3} {#4} { } { } }
\cs_new:Npn \msg_expandable_error:nnn #1#2#3
  { \msg_expandable_error:nnnnnn {#1} {#2} {#3} { } { } { } }
\cs_new:Npn \msg_expandable_error:nn #1#2
  { \msg_expandable_error:nnnnnn {#1} {#2} { } { } { } { } }
\cs_generate_variant:Nn \msg_expandable_error:nnnnnn { nnffff }
\cs_generate_variant:Nn \msg_expandable_error:nnnnn  { nnfff }
\cs_generate_variant:Nn \msg_expandable_error:nnnn   { nnff }
\cs_generate_variant:Nn \msg_expandable_error:nnn    { nnf }
\cs_new:Npn \@@_expandable_error_module:nn #1#2
  {
    \exp_after:wN \exp_after:wN
    \exp_after:wN \use_none_delimit_by_q_stop:w
    \use:n { \::error ! ~ #2 : ~ #1 } \q_stop
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Additions to \pkg{l3prg}}
%
%    \begin{macrocode}
%<@@=bool>
%    \end{macrocode}
%
% \begin{macro}[pTF]{\bool_lazy_all:n}
% \begin{macro}[aux]{\@@_lazy_all:n}
%   Go through the list of expressions, stopping whenever an expression
%   is \texttt{false}.  If the end is reached without finding any
%   \texttt{false} expression, then the result is \texttt{true}.
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_lazy_all:n #1 { p , T , F , TF }
  { \@@_lazy_all:n #1 \q_recursion_tail \q_recursion_stop }
\cs_new:Npn \@@_lazy_all:n #1
  {
    \quark_if_recursion_tail_stop_do:nn {#1} { \prg_return_true: }
    \bool_if:nF {#1}
      { \use_i_delimit_by_q_recursion_stop:nw { \prg_return_false: } }
    \@@_lazy_all:n
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_lazy_and:nn}
%   Only evaluate the second expression if the first is \texttt{true}.
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_lazy_and:nn #1#2 { p , T , F , TF }
  {
    \bool_if:nTF {#1}
      { \bool_if:nTF {#2} { \prg_return_true: } { \prg_return_false: } }
      { \prg_return_false: }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_lazy_any:n}
% \begin{macro}[aux]{\@@_lazy_any:n}
%   Go through the list of expressions, stopping whenever an expression
%   is \texttt{true}.  If the end is reached without finding any
%   \texttt{true} expression, then the result is \texttt{false}.
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_lazy_any:n #1 { p , T , F , TF }
  { \@@_lazy_any:n #1 \q_recursion_tail \q_recursion_stop }
\cs_new:Npn \@@_lazy_any:n #1
  {
    \quark_if_recursion_tail_stop_do:nn {#1} { \prg_return_false: }
    \bool_if:nT {#1}
      { \use_i_delimit_by_q_recursion_stop:nw { \prg_return_true: } }
    \@@_lazy_any:n
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\bool_lazy_or:nn}
%   Only evaluate the second expression if the first is \texttt{false}.
%    \begin{macrocode}
\prg_new_conditional:Npnn \bool_lazy_or:nn #1#2 { p , T , F , TF }
  {
    \bool_if:nTF {#1}
      { \prg_return_true: }
      { \bool_if:nTF {#2} { \prg_return_true: } { \prg_return_false: } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\bool_log:N, \bool_log:c, \bool_log:n}
%   Redirect output of \cs{bool_show:N} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_log:N
  { \__msg_log_next: \bool_show:N }
\cs_new_protected:Npn \bool_log:n
  { \__msg_log_next: \bool_show:n }
\cs_generate_variant:Nn \bool_log:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3prop}}
%
%    \begin{macrocode}
%<@@=prop>
%    \end{macrocode}
%
% \begin{macro}[EXP]{\prop_count:N, \prop_count:c}
% \begin{macro}[aux,EXP]{\@@_count:nn}
%   Counting the key--value pairs in a property list is done using the
%   same approach as for other count functions: turn each entry into a
%   \texttt{+1} then use integer evaluation to actually do the
%   mathematics.
%    \begin{macrocode}
\cs_new:Npn \prop_count:N #1
  {
    \int_eval:n
      {
        \c_zero
        \prop_map_function:NN #1 \@@_count:nn
      }
  }
\cs_new:Npn \@@_count:nn #1#2 { + \c_one }
\cs_generate_variant:Nn \prop_count:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[rEXP]{\prop_map_tokens:Nn, \prop_map_tokens:cn}
% \begin{macro}[aux]{\@@_map_tokens:nwwn}
%   The mapping is very similar to \cs{prop_map_function:NN}.  It grabs
%   one key--value pair at a time, and stops when reaching the marker
%   key \cs{q_recursion_tail}, which cannot appear in normal keys since
%   those are strings.  The odd construction |\use:n {#1}| allows |#1|
%   to contain any token without interfering with \cs{prop_map_break:}.
%   Argument |#2| of \cs{@@_map_tokens:nwwn} is \cs{s_@@} the first
%   time, and is otherwise empty.
%    \begin{macrocode}
\cs_new:Npn \prop_map_tokens:Nn #1#2
  {
    \exp_last_unbraced:Nno \@@_map_tokens:nwwn {#2} #1
      \@@_pair:wn \q_recursion_tail \s_@@ { }
    \__prg_break_point:Nn \prop_map_break: { }
  }
\cs_new:Npn \@@_map_tokens:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
  {
    \if_meaning:w \q_recursion_tail #3
      \exp_after:wN \prop_map_break:
    \fi:
    \use:n {#1} {#3} {#4}
    \@@_map_tokens:nwwn {#1}
  }
\cs_generate_variant:Nn \prop_map_tokens:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_log:N, \prop_log:c}
%   Redirect output of \cs{prop_show:N} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_log:N
  { \__msg_log_next: \prop_show:N }
\cs_generate_variant:Nn \prop_log:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3seq}}
%
%    \begin{macrocode}
%<@@=seq>
%    \end{macrocode}
%
% \begin{macro}
%   {
%     \seq_mapthread_function:NNN, \seq_mapthread_function:NcN,
%     \seq_mapthread_function:cNN, \seq_mapthread_function:ccN
%   }
% \begin{macro}[aux]
%   {
%     \@@_mapthread_function:wNN, \@@_mapthread_function:wNw,
%     \@@_mapthread_function:Nnnwnn
%   }
%   The idea is to first expand both sequences, adding the
%   usual |{ ? \__prg_break: } { }| to the end of each one.  This is
%   most conveniently done in two steps using an auxiliary function.
%   The mapping then throws away the first tokens of |#2| and |#5|,
%   which for items in the sequences will both be \cs{s_@@}
%   \cs{@@_item:n}.  The function to be mapped will then be applied to
%   the two entries.  When the code hits the end of one of the
%   sequences, the break material will stop the entire loop and tidy up.
%   This avoids needing to find the count of the two sequences, or
%   worrying about which is longer.
%    \begin{macrocode}
\cs_new:Npn \seq_mapthread_function:NNN #1#2#3
  { \exp_after:wN \@@_mapthread_function:wNN #2 \q_stop #1 #3 }
\cs_new:Npn \@@_mapthread_function:wNN \s_@@ #1 \q_stop #2#3
  {
    \exp_after:wN \@@_mapthread_function:wNw #2 \q_stop #3
      #1 { ? \__prg_break: } { }
    \__prg_break_point:
  }
\cs_new:Npn \@@_mapthread_function:wNw \s_@@ #1 \q_stop #2
  {
    \@@_mapthread_function:Nnnwnn #2
      #1 { ? \__prg_break: } { }
    \q_stop
  }
\cs_new:Npn \@@_mapthread_function:Nnnwnn #1#2#3#4 \q_stop #5#6
  {
    \use_none:n #2
    \use_none:n #5
    #1 {#3} {#6}
    \@@_mapthread_function:Nnnwnn #1 #4 \q_stop
  }
\cs_generate_variant:Nn \seq_mapthread_function:NNN {     Nc }
\cs_generate_variant:Nn \seq_mapthread_function:NNN { c , cc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_set_filter:NNn, \seq_gset_filter:NNn}
% \begin{macro}[aux]{\@@_set_filter:NNNn}
%   Similar to \cs{seq_map_inline:Nn}, without a
%   \cs{__prg_break_point:} because the user's code
%   is performed within the evaluation of a boolean expression,
%   and skipping out of that would break horribly.
%   The \cs{@@_wrap_item:n} function inserts the relevant
%   \cs{@@_item:n} without expansion in the input stream,
%   hence in the \texttt{x}-expanding assignment.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_filter:NNn
  { \@@_set_filter:NNNn \tl_set:Nx }
\cs_new_protected:Npn \seq_gset_filter:NNn
  { \@@_set_filter:NNNn \tl_gset:Nx }
\cs_new_protected:Npn \@@_set_filter:NNNn #1#2#3#4
  {
    \@@_push_item_def:n { \bool_if:nT {#4} { \@@_wrap_item:n {##1} } }
    #1 #2 { #3 }
    \@@_pop_item_def:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_set_map:NNn, \seq_gset_map:NNn}
% \begin{macro}[aux]{\@@_set_map:NNNn}
%   Very similar to \cs{seq_set_filter:NNn}. We could actually
%   merge the two within a single function, but it would have weird
%   semantics.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_map:NNn
  { \@@_set_map:NNNn \tl_set:Nx }
\cs_new_protected:Npn \seq_gset_map:NNn
  { \@@_set_map:NNNn \tl_gset:Nx }
\cs_new_protected:Npn \@@_set_map:NNNn #1#2#3#4
  {
    \@@_push_item_def:n { \exp_not:N \@@_item:n {#4} }
    #1 #2 { #3 }
    \@@_pop_item_def:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_log:N, \seq_log:c}
%   Redirect output of \cs{seq_show:N} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_log:N
  { \__msg_log_next: \seq_show:N }
\cs_generate_variant:Nn \seq_log:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3skip}}
%
%    \begin{macrocode}
%<@@=skip>
%    \end{macrocode}
%
% \begin{macro}{\skip_split_finite_else_action:nnNN}
%   This macro is useful when performing error checking in certain
%   circumstances. If the \meta{skip} register holds finite glue it sets
%   |#3| and |#4| to the stretch and shrink component, resp. If it holds
%   infinite glue set |#3| and |#4| to zero and issue the special action
%   |#2| which is probably an error message.
%   Assignments are local.
%    \begin{macrocode}
\cs_new:Npn \skip_split_finite_else_action:nnNN #1#2#3#4
  {
    \skip_if_finite:nTF {#1}
      {
        #3 = \etex_gluestretch:D #1 \scan_stop:
        #4 = \etex_glueshrink:D  #1 \scan_stop:
      }
      {
        #3 = \c_zero_skip
        #4 = \c_zero_skip
        #2
      }
  }
%    \end{macrocode}
%  \end{macro}
%
% \begin{macro}{\dim_log:N, \dim_log:c, \dim_log:n}
%   Diagnostics.  Redirect output of \cs{dim_show:n} to the log.
%    \begin{macrocode}
\cs_new_eq:NN \dim_log:N \__kernel_register_log:N
\cs_new_eq:NN \dim_log:c \__kernel_register_log:c
\cs_new_protected:Npn \dim_log:n
  { \__msg_log_next: \dim_show:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\skip_log:N, \skip_log:c, \skip_log:n}
%   Diagnostics.  Redirect output of \cs{skip_show:n} to the log.
%    \begin{macrocode}
\cs_new_eq:NN \skip_log:N \__kernel_register_log:N
\cs_new_eq:NN \skip_log:c \__kernel_register_log:c
\cs_new_protected:Npn \skip_log:n
  { \__msg_log_next: \skip_show:n }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\muskip_log:N, \muskip_log:c, \muskip_log:n}
%   Diagnostics.  Redirect output of \cs{muskip_show:n} to the log.
%    \begin{macrocode}
\cs_new_eq:NN \muskip_log:N \__kernel_register_log:N
\cs_new_eq:NN \muskip_log:c \__kernel_register_log:c
\cs_new_protected:Npn \muskip_log:n
  { \__msg_log_next: \muskip_show:n }
%    \end{macrocode}
% \end{macro}
%
%  \subsection{Additions to \pkg{l3tl}}
%
%    \begin{macrocode}
%<@@=tl>
%    \end{macrocode}
%
% \begin{macro}[EXP,pTF]{\tl_if_single_token:n}
%   There are four cases: empty token list, token list starting with a
%   normal token, with a brace group, or with a space token.  If the
%   token list starts with a normal token, remove it and check for
%   emptiness.  For the next case, an empty token list is not a single
%   token.  Finally, we have a non-empty token list starting with a
%   space or a brace group.  Applying \texttt{f}-expansion yields an
%   empty result if and only if the token list is a single space.
%    \begin{macrocode}
\prg_new_conditional:Npnn \tl_if_single_token:n #1 { p , T , F , TF }
  {
    \tl_if_head_is_N_type:nTF {#1}
      { \@@_if_empty_return:o { \use_none:n #1 } }
      {
        \tl_if_empty:nTF {#1}
          { \prg_return_false: }
          { \@@_if_empty_return:o { \exp:w \exp_end_continue_f:w #1 } }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\tl_reverse_tokens:n}
% \begin{macro}[EXP,aux]{\@@_reverse_group:nn}
%   The same as \cs{tl_reverse:n} but with recursion within brace groups.
%    \begin{macrocode}
\cs_new:Npn \tl_reverse_tokens:n #1
  {
    \etex_unexpanded:D \exp_after:wN
      {
        \exp:w
        \@@_act:NNNnn
          \@@_reverse_normal:nN
          \@@_reverse_group:nn
          \@@_reverse_space:n
          { }
          {#1}
      }
  }
\cs_new:Npn \@@_reverse_group:nn #1
  {
    \@@_act_group_recurse:Nnn
      \@@_act_reverse_output:n
      { \tl_reverse_tokens:n }
  }
%    \end{macrocode}
% \end{macro}
% \begin{macro}[EXP,aux]{\@@_act_group_recurse:Nnn}
%   In many applications of \cs{@@_act:NNNnn}, we need to recursively
%   apply some transformation within brace groups, then output. In this
%   code, |#1| is the output function, |#2| is the transformation,
%   which should expand in two steps, and |#3| is the group.
%    \begin{macrocode}
\cs_new:Npn \@@_act_group_recurse:Nnn #1#2#3
  {
    \exp_args:Nf #1
      { \exp_after:wN \exp_after:wN \exp_after:wN { #2 {#3} } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\tl_count_tokens:n}
% \begin{macro}[EXP,aux]{\@@_act_count_normal:nN,
%     \@@_act_count_group:nn, \@@_act_count_space:n}
%   The token count is computed through an \cs{int_eval:n} construction.
%   Each \texttt{1+} is output to the \emph{left}, into the integer
%   expression, and the sum is ended by the \cs{exp_end:} inserted by
%   \cs{@@_act_end:wn} (which is technically implemented as  \cs{c_zero}).
%   Somewhat a hack!
%    \begin{macrocode}
\cs_new:Npn \tl_count_tokens:n #1
  {
    \int_eval:n
      {
        \@@_act:NNNnn
          \@@_act_count_normal:nN
          \@@_act_count_group:nn
          \@@_act_count_space:n
          { }
          {#1}
      }
  }
\cs_new:Npn \@@_act_count_normal:nN #1 #2 { 1 + }
\cs_new:Npn \@@_act_count_space:n #1 { 1 + }
\cs_new:Npn \@@_act_count_group:nn #1 #2
  { 2 + \tl_count_tokens:n {#2} + }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \tl_set_from_file:Nnn,  \tl_set_from_file:cnn,
%     \tl_gset_from_file:Nnn, \tl_gset_from_file:cnn
%   }
% \begin{macro}[aux]{\@@_set_from_file:NNnn}
% \begin{macro}[aux]{\@@_from_file_do:w}
%   The approach here is similar to that for doing a rescan, and so the same
%   internals can be reused. Thus the plan is to insert a pair of tokens of
%   the same charcode but different catcodes after the file has been read.
%   This plus \cs{exp_not:N} allows the primitive to be used to carry out
%   a set operation.
%    \begin{macrocode}
\cs_new_protected:Npn \tl_set_from_file:Nnn
  { \@@_set_from_file:NNnn \tl_set:Nn }
\cs_new_protected:Npn \tl_gset_from_file:Nnn
  { \@@_set_from_file:NNnn \tl_gset:Nn }
\cs_generate_variant:Nn \tl_set_from_file:Nnn  { c }
\cs_generate_variant:Nn \tl_gset_from_file:Nnn { c }
\cs_new_protected:Npn \@@_set_from_file:NNnn #1#2#3#4
  {
    \__file_if_exist:nT {#4}
      {
        \group_begin:
          \exp_args:No \etex_everyeof:D
            { \c_@@_rescan_marker_tl \exp_not:N }
          #3 \scan_stop:
          \exp_after:wN \@@_from_file_do:w
          \exp_after:wN \prg_do_nothing:
            \tex_input:D \l__file_internal_name_tl \scan_stop:
        \exp_args:NNNo \group_end:
        #1 #2 \l_@@_internal_a_tl
      }
  }
\exp_args:Nno \use:nn
  { \cs_set_protected:Npn \@@_from_file_do:w #1 }
  { \c_@@_rescan_marker_tl }
  { \tl_set:No \l_@@_internal_a_tl {#1} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \tl_set_from_file_x:Nnn,  \tl_set_from_file_x:cnn,
%     \tl_gset_from_file_x:Nnn, \tl_gset_from_file_x:cnn
%   }
% \begin{macro}[aux]{\@@_set_from_file_x:NNnn}
%   When reading a file and allowing expansion of the content, the set up
%   only needs to prevent \TeX{} complaining about the end of the file. That
%   is done simply, with a group then used to trap the definition needed.
%   Once the business is done using some scratch space, the tokens can be
%   transferred to the real target.
%    \begin{macrocode}
\cs_new_protected:Npn \tl_set_from_file_x:Nnn
  { \@@_set_from_file_x:NNnn \tl_set:Nn }
\cs_new_protected:Npn \tl_gset_from_file_x:Nnn
  { \@@_set_from_file_x:NNnn \tl_gset:Nn }
\cs_generate_variant:Nn \tl_set_from_file_x:Nnn  { c }
\cs_generate_variant:Nn \tl_gset_from_file_x:Nnn { c }
\cs_new_protected:Npn \@@_set_from_file_x:NNnn #1#2#3#4
  {
    \__file_if_exist:nT {#4}
      {
        \group_begin:
          \etex_everyeof:D { \exp_not:N }
          #3 \scan_stop:
          \tl_set:Nx \l_@@_internal_a_tl
            { \tex_input:D \l__file_internal_name_tl \c_space_token }
        \exp_args:NNNo \group_end:
        #1 #2 \l_@@_internal_a_tl
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsubsection{Unicode case changing}
%
% The mechanisms needed for case changing are somewhat involved, particularly
% to allow for all of the special cases. These functions also require the
% appropriate data extracted from the Unicode documentation (either manually
% or automatically).
%
% \begin{macro}[EXP, documented-as=\tl_if_head_eq_catcode:nNTF]
%   {\tl_if_head_eq_catcode:oNTF}
%   Extra variants.
%    \begin{macrocode}
\cs_generate_variant:Nn \tl_if_head_eq_catcode:nNTF { o }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\tl_lower_case:n, \tl_upper_case:n, \tl_mixed_case:n}
% \begin{macro}[EXP]{\tl_lower_case:nn, \tl_upper_case:nn, \tl_mixed_case:nn}
%   The user level functions here are all wrappers around the internal
%   functions for case changing. Note that \cs{tl_mixed_case:nn} could be
%   done without an internal, but this way the logic is slightly clearer as
%   everything essentially follows the same path.
%    \begin{macrocode}
\cs_new:Npn \tl_lower_case:n { \@@_change_case:nnn { lower } { } }
\cs_new:Npn \tl_upper_case:n { \@@_change_case:nnn { upper } { } }
\cs_new:Npn \tl_mixed_case:n { \@@_mixed_case:nn { } }
\cs_new:Npn \tl_lower_case:nn { \@@_change_case:nnn { lower } }
\cs_new:Npn \tl_upper_case:nn { \@@_change_case:nnn { upper } }
\cs_new:Npn \tl_mixed_case:nn { \@@_mixed_case:nn }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[aux, EXP]{\@@_change_case:nnn}
% \begin{macro}[aux, EXP]{\@@_change_case_aux:nnn}
% \begin{macro}[aux, EXP]{\@@_change_case_loop:wnn}
% \begin{macro}[aux, EXP]
%   {
%     \@@_change_case_output:nwn ,
%     \@@_change_case_output:Vwn ,
%     \@@_change_case_output:own ,
%     \@@_change_case_output:vwn ,
%     \@@_change_case_output:fwn ,
%   }
% \begin{macro}[aux, EXP]{\@@_change_case_end:wn}
% \begin{macro}[aux, EXP]{\@@_change_case_group:nwnn}
% \begin{macro}[aux, EXP]{\@@_change_case_space:wnn}
% \begin{macro}[aux, EXP]{\@@_change_case_N_type:Nwnn}
% \begin{macro}[aux, EXP]{\@@_change_case_N_type:NNNnnn}
% \begin{macro}[aux, EXP]{\@@_change_case_math:NNNnnn}
% \begin{macro}[aux, EXP]{\@@_change_case_math_loop:wNNnn}
% \begin{macro}[aux, EXP]{\@@_change_case_math:NwNNnn}
% \begin{macro}[aux, EXP]{\@@_change_case_math_group:nwNNnn}
% \begin{macro}[aux, EXP]{\@@_change_case_math_space:wNNnn}
% \begin{macro}[aux, EXP]{\@@_change_case_N_type:Nnnn}
% \begin{macro}[aux, EXP]{\@@_change_case_char:Nnn}
% \begin{macro}[aux, EXP]{\@@_change_case_char:nN}
% \begin{macro}[aux, EXP]
%   {\@@_change_case_char_auxi:nN, \@@_change_case_char_auxii:nN}
% \begin{macro}[aux]
%   {\@@_lookup_lower:N, \@@_lookup_upper:N, \@@_lookup_title:N}
% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFviii:nNN}
% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFviii:nNNN}
% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFviii:nNNNN}
% \begin{macro}[aux, EXP]{\@@_change_case_char_UTFviii:nn}
% \begin{macro}[aux, EXP]{\@@_change_case_cs_letterlike:Nnn}
% \begin{macro}[aux, EXP]{\@@_change_case_cs_accents:NN}
% \begin{macro}[aux, EXP]{\@@_change_case_cs:N}
% \begin{macro}[aux, EXP]{\@@_change_case_cs:NN}
% \begin{macro}[aux, EXP]{\@@_change_case_cs:NNn}
% \begin{macro}[aux, EXP]{\@@_change_case_protect:wNN}
% \begin{macro}[aux, EXP]{\@@_change_case_if_expandable:NTF}
% \begin{macro}[aux, EXP]{\@@_change_case_cs_expand:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_cs_expand:NN}
%   The mechanism for the core conversion of case is based on the idea that
%   we can use a loop to grab the entire token list plus a quark: the latter is
%   used as an end marker and to avoid any brace stripping. Depending on the
%   nature of the first item in the grabbed argument, it can either processed
%   as a single token, treated as a group or treated as a space. These
%   different cases all work by re-reading |#1| in the appropriate way, hence
%   the repetition of |#1 \q_recursion_stop|.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case:nnn #1#2#3
  {
    \etex_unexpanded:D \exp_after:wN
      {
        \exp:w
        \@@_change_case_aux:nnn {#1} {#2} {#3}
      }
  }
\cs_new:Npn \@@_change_case_aux:nnn #1#2#3
  {
    \group_align_safe_begin:
    \@@_change_case_loop:wnn
      #3 \q_recursion_tail \q_recursion_stop {#1} {#2}
    \@@_change_case_result:n { }
  }
\cs_new:Npn \@@_change_case_loop:wnn #1 \q_recursion_stop
  {
    \tl_if_head_is_N_type:nTF {#1}
      { \@@_change_case_N_type:Nwnn }
      {
        \tl_if_head_is_group:nTF {#1}
          { \@@_change_case_group:nwnn }
          { \@@_change_case_space:wnn }
      }
    #1 \q_recursion_stop
  }
%    \end{macrocode}
%   Earlier versions of the code where only \texttt{x}-type expandable rather
%   than \texttt{f}-type: this causes issues with nesting and so the slight
%   performance hit is taken for a better outcome in usability terms. Setting
%   up for \texttt{f}-type expandability has two requirements: a marker
%   token after the main loop (see above) and a mechanism to \enquote{load}
%   and finalise the result. That is handled in the code below, which includes
%   the necessary material to end the \cs{exp:w} expansion.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_output:nwn #1#2 \@@_change_case_result:n #3
  { #2 \@@_change_case_result:n { #3 #1 } }
\cs_generate_variant:Nn \@@_change_case_output:nwn { V , o , v , f }
\cs_new:Npn \@@_change_case_end:wn #1 \@@_change_case_result:n #2
  {
    \group_align_safe_end:
    \exp_end:
    #2
  }
%    \end{macrocode}
%   Handling for the cases where the current argument is a brace group or
%   a space is relatively easy. For the brace case, the routine works
%   recursively, using the expandability of the mechanism to ensure that the
%   result is finalised before storage. For the space case it is simply a
%   question of removing the space in the input and storing it in the output.
%   In both cases, and indeed for the \texttt{N}-type grabber, after removing
%   the current item from the input \cs{@@_change_case_loop:wnn} is inserted
%   in front of the remaining tokens.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_group:nwnn #1#2 \q_recursion_stop #3#4
  {
    \@@_change_case_output:own
      {
        \exp_after:wN
          {
            \exp:w
            \@@_change_case_aux:nnn {#3} {#4} {#1}
          }
      }
    \@@_change_case_loop:wnn #2 \q_recursion_stop {#3} {#4}
  }
\exp_last_unbraced:NNo \cs_new:Npn \@@_change_case_space:wnn \c_space_tl
  {
    \@@_change_case_output:nwn { ~ }
    \@@_change_case_loop:wnn
  }
%    \end{macrocode}
%   For \texttt{N}-type arguments there are several stages to the approach.
%   First, a simply check for the end-of-input marker, which if found triggers
%   the final clean up and output step. Assuming that is not the case, the
%   first check is for math-mode escaping: this test can encompass control
%   sequences or other \texttt{N}-type tokens so is handled up front.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_N_type:Nwnn #1#2 \q_recursion_stop
  {
    \quark_if_recursion_tail_stop_do:Nn #1
      { \@@_change_case_end:wn }
    \exp_after:wN \@@_change_case_N_type:NNNnnn
      \exp_after:wN #1 \l_tl_case_change_math_tl
      \q_recursion_tail ? \q_recursion_stop {#2}
  }
%    \end{macrocode}
%   Looking for math mode escape first requires a loop over the possible
%   token pairs to see if the current input (|#1|) matches an open-math case
%   (|#2|). If if does then this test loop is ended and a new input-gathering
%   one is begun. The latter simply transfers material from the input to the
%   output without any expansion, testing each \texttt{N}-type token to see
%   if it matches the close-math case required. If that is the situation then
%   the \enquote{math loop} stops and resumes the main loop: as that might
%   be either the standard case-changing one or the mixed-case alternative,
%   it is not hard-coded into the math loop but is rather passed as argument
%   |#3| to \cs{@@_change_case_math:NNNnnn}. If no close-math token is found
%   then the final clean-up will be forced (\emph{i.e.}~there is no assumption
%   of \enquote{well-behaved} code in terms of math mode).
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_N_type:NNNnnn #1#2#3
  {
    \quark_if_recursion_tail_stop_do:Nn #2
     { \@@_change_case_N_type:Nnnn #1 }
    \token_if_eq_meaning:NNTF #1 #2
      {
        \use_i_delimit_by_q_recursion_stop:nw
           {
             \@@_change_case_math:NNNnnn
               #1 #3 \@@_change_case_loop:wnn
           }
      }
      { \@@_change_case_N_type:NNNnnn #1 }
  }
\cs_new:Npn \@@_change_case_math:NNNnnn #1#2#3#4
  {
    \@@_change_case_output:nwn {#1}
    \@@_change_case_math_loop:wNNnn #4 \q_recursion_stop #2 #3
  }
\cs_new:Npn \@@_change_case_math_loop:wNNnn #1 \q_recursion_stop
  {
    \tl_if_head_is_N_type:nTF {#1}
      { \@@_change_case_math:NwNNnn }
      {
        \tl_if_head_is_group:nTF {#1}
          { \@@_change_case_math_group:nwNNnn }
          { \@@_change_case_math_space:wNNnn }
      }
    #1 \q_recursion_stop
  }
\cs_new:Npn \@@_change_case_math:NwNNnn #1#2 \q_recursion_stop #3#4
  {
    \token_if_eq_meaning:NNTF \q_recursion_tail #1
      { \@@_change_case_end:wn }
      {
        \@@_change_case_output:nwn {#1}
        \token_if_eq_meaning:NNTF #1 #3
          { #4 #2 \q_recursion_stop }
          { \@@_change_case_math_loop:wNNnn #2 \q_recursion_stop #3#4 }
      }
  }
\cs_new:Npn \@@_change_case_math_group:nwNNnn #1#2 \q_recursion_stop
  {
    \@@_change_case_output:nwn { {#1} }
    \@@_change_case_math_loop:wNNnn #2 \q_recursion_stop
  }
\exp_last_unbraced:NNo
  \cs_new:Npn \@@_change_case_math_space:wNNnn \c_space_tl
  {
    \@@_change_case_output:nwn { ~ }
    \@@_change_case_math_loop:wNNnn
  }
%    \end{macrocode}
%   Once potential math-mode cases are filtered out the next stage is to
%   test if the token grabbed is a control sequence: they cannot be used in
%   the lookup table and also may require expansion. At this stage the loop
%   code starting \cs{@@_change_case_loop:wnn} is inserted: all subsequent
%   steps in the code which need a look-ahead are coded to rely on this and
%   thus have \texttt{w}-type arguments if they may do a look-ahead.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_N_type:Nnnn #1#2#3#4
  {
    \token_if_cs:NTF #1
      { \@@_change_case_cs_letterlike:Nnn #1 {#3} { } }
      { \@@_change_case_char:Nnn #1 {#3} {#4} }
    \@@_change_case_loop:wnn #2 \q_recursion_stop {#3} {#4}
  }
%    \end{macrocode}
%   For character tokens there are some special cases to deal with then
%   the majority of changes are covered by using the \TeX{} data as a lookup
%   along with expandable character generation. This avoids needing a very
%   large number of macros or (as seen in earlier versions) a somewhat tricky
%   split of the characters into various blocks. Notice that the special case
%   code may do a look-ahead so requires a final \texttt{w}-type argument
%   whereas the core lookup table does not and also guarantees an output so
%   \texttt{f}-type expansion may be used to obtain the case-changed result.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_char:Nnn #1#2#3
  {
    \cs_if_exist_use:cF { @@_change_case_ #2 _ #3 :Nnw }
      { \use_ii:nn }
        #1
        {
          \use:c { @@_change_case_ #2 _ sigma:Nnw } #1
            { \@@_change_case_char:nN {#2} #1 }
        }
  }
%    \end{macrocode}
%   For Unicode engines we can handle all characters directly. However, for
%   the $8$-bit engines the aim is to deal with (a subset of) Unicode (UTF-8)
%   input. They deal with that by making the upper half of the range active,
%   so we look for that and if found work out how many UTF-8 octets there
%   are to deal with. Those can then be grabbed to reconstruct the full
%   Unicode character, which is then used in a lookup. (As will become
%   obvious below, there is no intention here of covering all of Unicode.)
%    \begin{macrocode}
\cs_if_exist:NTF \utex_char:D
  {
    \cs_new:Npn \@@_change_case_char:nN #1#2
      { \@@_change_case_char_auxi:nN {#1} #2 }
  }
  {
    \cs_new:Npn \@@_change_case_char:nN #1#2
      {
        \int_compare:nNnTF { `#2 } > { "80 }
          {
            \int_compare:nNnTF { `#2 } < { "E0 }
              { \@@_change_case_char_UTFviii:nNNN {#1} #2 }
              {
                \int_compare:nNnTF { `#2 } < { "F0 }
                  { \@@_change_case_char_UTFviii:nNNNN {#1} #2 }
                  { \@@_change_case_char_UTFviii:nNNNNN {#1} #2 }
              }
          }
          { \@@_change_case_char_auxi:nN {#1} #2 }
       }
  }
\cs_new:Npn \@@_change_case_char_auxi:nN #1#2
  {
    \@@_change_case_output:fwn
      {
        \cs_if_exist_use:cF { c__unicode_ #1 _ \token_to_str:N #2 _tl }
          { \@@_change_case_char_auxii:nN {#1} #2 }
      }
  }
\cs_if_exist:NTF \utex_char:D
  {
    \cs_new:Npn \@@_change_case_char_auxii:nN #1#2
      {
        \int_compare:nNnTF { \use:c { @@_lookup_ #1 :N } #2 } = { 0 }
          { \exp_stop_f: #2 }
          {
            \char_generate:nn
              { \use:c { @@_lookup_ #1 :N } #2 }
              { \char_value_catcode:n { \use:c { @@_lookup_ #1 :N } #2 } }
          }
      }
    \cs_new_protected:Npn \@@_lookup_lower:N #1 { \tex_lccode:D `#1 }
    \cs_new_protected:Npn \@@_lookup_upper:N #1 { \tex_uccode:D `#1 }
    \cs_new_eq:NN \@@_lookup_title:N \@@_lookup_upper:N
  }
  {
    \cs_new:Npn \@@_change_case_char_auxii:nN #1#2 { \exp_stop_f: #2 }
    \cs_new:Npn \@@_change_case_char_UTFviii:nNNN #1#2#3#4
      { \@@_change_case_char_UTFviii:nnN {#1} {#2#4} #3 }
    \cs_new:Npn \@@_change_case_char_UTFviii:nNNNN #1#2#3#4#5
      { \@@_change_case_char_UTFviii:nnN {#1} {#2#4#5} #3 }
    \cs_new:Npn \@@_change_case_char_UTFviii:nNNNNN #1#2#3#4#5#6
      { \@@_change_case_char_UTFviii:nnN {#1} {#2#4#5#6} #3 }
    \cs_new:Npn \@@_change_case_char_UTFviii:nnN #1#2#3
      {
        \cs_if_exist:cTF { c__unicode_ #1 _ \tl_to_str:n {#2} _tl }
          {
            \@@_change_case_output:vwn
              { c__unicode_ #1 _ \tl_to_str:n {#2} _tl }
          }
          { \@@_change_case_output:nwn {#2} }
        #3
      }
  }
%    \end{macrocode}
%   Before dealing with general control sequences there are the special
%   ones to deal with. Letter-like control sequences are a simple look-up,
%   while for accents the loop is much as done elsewhere. Notice that
%   we have a no-op test to make sure there is no unexpected expansion of
%   letter-like input. The third argument here is needed for mixed casing,
%   where it if there is a hit there has to be a change-of-path.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_cs_letterlike:Nnn #1#2#3
  {
    \cs_if_exist:cTF { c_@@_change_case_ #2 _ \token_to_str:N #1 _tl }
      {
        \@@_change_case_output:vwn
          { c_@@_change_case_ #2 _ \token_to_str:N #1 _tl } 
        #3
      }
      {
        \cs_if_exist:cTF
          {
            c_@@_change_case_
            \str_if_eq:nnTF {#2} { lower } { upper } { lower }
            _ \token_to_str:N #1 _tl 
          }
          {
            \@@_change_case_output:nwn {#1}
            #3
          }
          {
            \exp_after:wN \@@_change_case_cs_accents:NN
              \exp_after:wN #1 \l_tl_case_change_accents_tl
              \q_recursion_tail \q_recursion_stop
          }
      }
  }
\cs_new:Npn \@@_change_case_cs_accents:NN #1#2
  {
    \quark_if_recursion_tail_stop_do:Nn #2
      { \@@_change_case_cs:N #1 }
    \str_if_eq:nnTF {#1} {#2}
      {
        \use_i_delimit_by_q_recursion_stop:nw
          { \@@_change_case_output:nwn {#1} }
      }
      { \@@_change_case_cs_accents:NN #1 }
  }
%    \end{macrocode}
%   To deal with a control sequence there is first a need to test if it is
%   on the list which indicate that case changing should be skipped. That's
%   done using a loop as for the other special cases. If a hit is found then
%   the argument is grabbed: that comes \emph{after} the loop function which
%   is therefore rearranged.  In a \LaTeXe{} context, \tn{protect} needs
%   to be treated specially, to prevent expansion of the next token but
%   output it without braces.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_cs:N #1
  {
%<*package>
    \str_if_eq:nnTF {#1} { \protect } { \@@_change_case_protect:wNN }
%</package>
    \exp_after:wN \@@_change_case_cs:NN
      \exp_after:wN #1 \l_tl_case_change_exclude_tl
      \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \@@_change_case_cs:NN #1#2
  {
    \quark_if_recursion_tail_stop_do:Nn #2
      {
        \@@_change_case_cs_expand:Nnw #1
          { \@@_change_case_output:nwn {#1} }
      }
    \str_if_eq:nnTF {#1} {#2}
      {
        \use_i_delimit_by_q_recursion_stop:nw
          { \@@_change_case_cs:NNn #1 }
      }
      { \@@_change_case_cs:NN #1 }
  }
\cs_new:Npn \@@_change_case_cs:NNn #1#2#3
  {
    \@@_change_case_output:nwn { #1 {#3} }
    #2
  }
%<*package>
\cs_new:Npn \@@_change_case_protect:wNN #1 \q_recursion_stop #2 #3
  { \@@_change_case_output:nwn { \protect #3 } #2 }
%</package>
%    \end{macrocode}
%   When a control sequence is not on the exclude list the other test if
%   to see if it is expandable. Once again, if there is a hit then the loop
%   function is grabbed as part of the clean-up and reinserted before the
%   now expanded material. The test for expandablity has to check for
%   end-of-recursion as it is needed by the look-ahead code which might hit
%   the end of the input. The test is done in two parts as \cs{bool_if:nTF}
%   will choke if |#1| is |(|!
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_if_expandable:NTF #1
  {
    \token_if_expandable:NTF #1
      {
        \bool_if:nTF
          {
               \token_if_protected_macro_p:N      #1
            || \token_if_protected_long_macro_p:N #1
            || \token_if_eq_meaning_p:NN \q_recursion_tail #1
          }
          { \use_ii:nn }
          { \use_i:nn }
      }
      { \use_ii:nn }
  }
\cs_new:Npn \@@_change_case_cs_expand:Nnw #1#2
  {
    \@@_change_case_if_expandable:NTF #1
      { \@@_change_case_cs_expand:NN #1 }
      { #2 }
  }
\cs_new:Npn \@@_change_case_cs_expand:NN #1#2
  { \exp_after:wN #2 #1 }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[aux, EXP]{\@@_change_case_lower_sigma:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_sigma:w}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_sigma:Nw}
% \begin{macro}[aux, EXP]{\@@_change_case_upper_sigma:Nnw}
%   If the current char is an upper case sigma, the a check is made on the next
%   item in the input.  If it is \texttt{N}-type and not a control sequence
%   then there is a look-ahead phase.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_lower_sigma:Nnw #1#2#3#4 \q_recursion_stop
  {
    \int_compare:nNnTF { `#1 } = { "03A3 }
      {
        \@@_change_case_output:fwn
          { \@@_change_case_lower_sigma:w #4 \q_recursion_stop }
      }
      {#2}
    #3 #4 \q_recursion_stop
  }
\cs_new:Npn \@@_change_case_lower_sigma:w #1 \q_recursion_stop
  {
    \tl_if_head_is_N_type:nTF {#1}
      { \@@_change_case_lower_sigma:Nw #1 \q_recursion_stop }
      { \c__unicode_final_sigma_tl }
  }
\cs_new:Npn \@@_change_case_lower_sigma:Nw #1#2 \q_recursion_stop
  {
    \@@_change_case_if_expandable:NTF #1
      {
        \exp_after:wN \@@_change_case_lower_sigma:w #1
          #2 \q_recursion_stop
      }
      {
        \token_if_letter:NTF #1
          { \c__unicode_std_sigma_tl }
          { \c__unicode_final_sigma_tl }
      }
  }
%    \end{macrocode}
%   Simply skip to the final step for upper casing.
%    \begin{macrocode}
\cs_new_eq:NN \@@_change_case_upper_sigma:Nnw \use_ii:nn
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[aux, EXP]{\@@_change_case_lower_tr:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_tr_auxi:Nw}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_tr_auxii:Nw}
% \begin{macro}[aux, EXP]{\@@_change_case_upper_tr:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_az:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_upper_az:Nnw}
%   The Turkic languages need special treatment for dotted-i and dotless-i.
%   The lower casing rule can be expressed in terms of searching first for
%   either a dotless-I or a dotted-I. In the latter case the mapping is
%   easy, but in the former there is a second stage search.
%    \begin{macrocode}
\cs_if_exist:NTF \utex_char:D
  {
    \cs_new:Npn \@@_change_case_lower_tr:Nnw #1#2
      {
        \int_compare:nNnTF { `#1 } = { "0049 }
          { \@@_change_case_lower_tr_auxi:Nw }
          {
            \int_compare:nNnTF { `#1 } = { "0130 }
              { \@@_change_case_output:nwn { i } }
              {#2}
          }
      }
%    \end{macrocode}
%   After a dotless-I there may be a dot-above character. If there is then
%   a dotted-i should be produced, otherwise output a dotless-i. When the
%   combination is found both the dotless-I and the dot-above char have to
%   be removed from the input, which is done by the \cs{use_i:nn}
%   (it grabs \cs{@@_change_case_loop:wn} and the dot-above char and
%   discards the latter).
%    \begin{macrocode}
    \cs_new:Npn \@@_change_case_lower_tr_auxi:Nw #1#2 \q_recursion_stop
      {
        \tl_if_head_is_N_type:nTF {#2}
          { \@@_change_case_lower_tr_auxii:Nw #2 \q_recursion_stop }
          { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl }
        #1 #2 \q_recursion_stop
      }
    \cs_new:Npn \@@_change_case_lower_tr_auxii:Nw #1#2 \q_recursion_stop
      {
        \@@_change_case_if_expandable:NTF #1
          {
            \exp_after:wN \@@_change_case_lower_tr_auxi:Nw #1
              #2 \q_recursion_stop
          }
          {
            \bool_if:nTF
              {
                   \token_if_cs_p:N #1
                || ! ( \int_compare_p:nNn { `#1 } = { "0307 } )
              }
              { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl }
              {
                \@@_change_case_output:nwn { i }
                \use_i:nn
              }
          }
      }
  }
%    \end{macrocode}
%   For $8$-bit engines, dot-above is not available so there is a simple
%   test for an upper-case I. Then we can look for the UTF-8 representation of
%   an upper case dotted-I without the combining char. If it's not there,
%   preserve the UTF-8 sequence as-is.
%    \begin{macrocode}
  {
    \cs_new:Npn \@@_change_case_lower_tr:Nnw #1#2
      {
        \int_compare:nNnTF { `#1 } = { "0049 }
          { \@@_change_case_output:Vwn \c__unicode_dotless_i_tl }
          {
            \int_compare:nNnTF { `#1 } = { 196 }
              { \@@_change_case_lower_tr_auxi:Nw #1 {#2} }
              {#2}
          }
      }
    \cs_new:Npn \@@_change_case_lower_tr_auxi:Nw #1#2#3#4
      {
        \int_compare:nNnTF { `#4 } = { 176 }
          {
            \@@_change_case_output:nwn { i }
            #3
          }
          {
            #2
            #3 #4
          }
      }
  }
%    \end{macrocode}
%   Upper casing is easier: just one exception with no context.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_upper_tr:Nnw #1#2
  {
    \int_compare:nNnTF { `#1 } = { "0069 }
      { \@@_change_case_output:Vwn \c__unicode_dotted_I_tl }
      {#2}
  }
%    \end{macrocode}
%   Straight copies.
%    \begin{macrocode}
\cs_new_eq:NN \@@_change_case_lower_az:Nnw \@@_change_case_lower_tr:Nnw
\cs_new_eq:NN \@@_change_case_upper_az:Nnw \@@_change_case_upper_tr:Nnw
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[aux, EXP]{\@@_change_case_lower_lt:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_lt:nNnw}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_lt:nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_lt:Nw}
% \begin{macro}[aux, EXP]{\@@_change_case_lower_lt:NNw}
% \begin{macro}[aux, EXP]{\@@_change_case_upper_lt:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_upper_lt:nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_upper_lt:Nw}
% \begin{macro}[aux, EXP]{\@@_change_case_upper_lt:NNw}
%   For  Lithuanian, the issue to be dealt with is dots over lower case
%   letters: these should be present if there is another accent. That means
%   that there is some work to do when lower casing I and J. The first step
%   is a simple match attempt: \cs{c_@@_accents_lt_tl} contains
%   accented upper case letters which should gain a dot-above char in their
%   lower case form. This is done using \texttt{f}-type expansion so only one
%   pass is needed to find if it works or not. If there was no hit, the second
%   stage is to check for I, J and I-ogonek, and if the current char is a
%   match to look for a following accent.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_lower_lt:Nnw #1
  {
    \exp_args:Nf \@@_change_case_lower_lt:nNnw
      { \str_case:nVF #1 \c__unicode_accents_lt_tl \exp_stop_f: }
      #1
  }
\cs_new:Npn \@@_change_case_lower_lt:nNnw #1#2
  {
    \tl_if_blank:nTF {#1}
      {
        \exp_args:Nf \@@_change_case_lower_lt:nnw
          {
            \int_case:nnF {`#2}
              {
                { "0049 } i
                { "004A } j
                { "012E } \c__unicode_i_ogonek_tl
              }
              \exp_stop_f:
          }
      }
      {
        \@@_change_case_output:nwn {#1}
        \use_none:n
      }
  }
\cs_new:Npn \@@_change_case_lower_lt:nnw #1#2
  {
    \tl_if_blank:nTF {#1}
      {#2}
      {
        \@@_change_case_output:nwn {#1}
        \@@_change_case_lower_lt:Nw
      }
  }
%    \end{macrocode}
%   Grab the next char and see if it is one of the accents used in Lithuanian:
%   if it is, add the dot-above char into the output.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_lower_lt:Nw #1#2 \q_recursion_stop
  {
    \tl_if_head_is_N_type:nT {#2}
      { \@@_change_case_lower_lt:NNw }
    #1 #2 \q_recursion_stop
  }
\cs_new:Npn \@@_change_case_lower_lt:NNw #1#2#3 \q_recursion_stop
  {
    \@@_change_case_if_expandable:NTF #2
      {
        \exp_after:wN \@@_change_case_lower_lt:Nw \exp_after:wN #1 #2
          #3 \q_recursion_stop
      }
      {
        \bool_if:nT
          {
            ! \token_if_cs_p:N #2
            &&
              (
                   \int_compare_p:nNn { `#2 } = { "0300 }
                || \int_compare_p:nNn { `#2 } = { "0301 }
                || \int_compare_p:nNn { `#2 } = { "0303 }
              )
          }
          { \@@_change_case_output:Vwn \c__unicode_dot_above_tl }
        #1 #2#3 \q_recursion_stop
      }
  }
%    \end{macrocode}
%   For upper casing, the test required is for a dot-above char after an I,
%   J or I-ogonek. First a test for the appropriate letter, and if found a
%   look-ahead and potentially one token dropped.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_upper_lt:Nnw #1
  {
    \exp_args:Nf \@@_change_case_upper_lt:nnw
      {
        \int_case:nnF {`#1}
          {
            { "0069 } I
            { "006A } J
            { "012F } \c__unicode_I_ogonek_tl
          }
          \exp_stop_f:
      }
  }
\cs_new:Npn \@@_change_case_upper_lt:nnw #1#2
  {
    \tl_if_blank:nTF {#1}
      {#2}
      {
        \@@_change_case_output:nwn {#1}
        \@@_change_case_upper_lt:Nw
      }
  }
\cs_new:Npn \@@_change_case_upper_lt:Nw #1#2 \q_recursion_stop
  {
    \tl_if_head_is_N_type:nT {#2}
      { \@@_change_case_upper_lt:NNw }
    #1 #2 \q_recursion_stop
  }
\cs_new:Npn \@@_change_case_upper_lt:NNw #1#2#3 \q_recursion_stop
  {
    \@@_change_case_if_expandable:NTF #2
      {
        \exp_after:wN \@@_change_case_upper_lt:Nw \exp_after:wN #1 #2
          #3 \q_recursion_stop
      }
      {
        \bool_if:nTF
          {
               ! \token_if_cs_p:N #2
            && \int_compare_p:nNn { `#2 } = { "0307 }
          }
          { #1 }
          { #1 #2 }
        #3 \q_recursion_stop
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_change_case_upper_de-alt:Nnw}
%   A simple alternative version for German.
%    \begin{macrocode}
\cs_new:cpn { @@_change_case_upper_de-alt:Nnw } #1#2
  {
    \int_compare:nNnTF { `#1 } = { 223 }
      { \@@_change_case_output:Vwn \c__unicode_upper_Eszett_tl }
      {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP, int]{\__unicode_codepoint_to_UTFviii:n}
% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFviii_auxi:n}
% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFviii_auxii:Nnn}
% \begin{macro}[EXP, aux]{\__unicode_codepoint_to_UTFviii_auxiii:n}
%   This code will convert a codepoint into the correct UTF-8 representation.
%   As there are a variable number of octets, the result starts with the
%   numeral |1|--|4| to indicate the nature of the returned value. Note that
%   this code will cover the full range even though at this stage it is not
%   required here. Also note that longer-term this is likely to need a public
%   interface and/or moving to \pkg{l3str} (see experimental string
%   conversions). In terms of the algorithm itself, see
%   \url{https://en.wikipedia.org/wiki/UTF-8} for the octet pattern.
%    \begin{macrocode}
\cs_new:Npn \__unicode_codepoint_to_UTFviii:n #1
  {
    \exp_args:Nf \__unicode_codepoint_to_UTFviii_auxi:n
      { \int_eval:n {#1} }
  }
\cs_new:Npn \__unicode_codepoint_to_UTFviii_auxi:n #1
  {
    \if_int_compare:w #1 > "80 ~
      \if_int_compare:w #1 < "800 ~
        2
        \__unicode_codepoint_to_UTFviii_auxii:Nnn C {#1} { 64 }
        \__unicode_codepoint_to_UTFviii_auxiii:n {#1}
      \else:
        \if_int_compare:w #1 < "10000 ~
          3
          \__unicode_codepoint_to_UTFviii_auxii:Nnn E {#1} { 64 * 64 }
          \__unicode_codepoint_to_UTFviii_auxiii:n {#1}
          \__unicode_codepoint_to_UTFviii_auxiii:n
            { \int_div_truncate:nn {#1} { 64 } }
        \else:
          4
          \__unicode_codepoint_to_UTFviii_auxii:Nnn F
            {#1} { 64 * 64 * 64 }
          \__unicode_codepoint_to_UTFviii_auxiii:n
            { \int_div_truncate:nn {#1} { 64 * 64 } }
          \__unicode_codepoint_to_UTFviii_auxiii:n
            { \int_div_truncate:nn {#1} { 64 } }
          \__unicode_codepoint_to_UTFviii_auxiii:n {#1}

        \fi:
      \fi:
    \else:
      1 {#1}
    \fi:
  }
\cs_new:Npn \__unicode_codepoint_to_UTFviii_auxii:Nnn #1#2#3
  { { \int_eval:n { "#10 + \int_div_truncate:nn {#2} {#3} } } }
\cs_new:Npn \__unicode_codepoint_to_UTFviii_auxiii:n #1
  { { \int_eval:n { \int_mod:nn {#1} { 64 } + 128 } } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{variable}
%   {
%     \c__unicode_std_sigma_tl    ,
%     \c__unicode_final_sigma_tl  ,
%     \c__unicode_accents_lt_tl   ,
%     \c__unicode_dot_above_tl    ,
%     \c__unicode_upper_Eszett_tl
%   }
%   The above needs various special token lists containg pre-formed characters.
%   This set are only available in Unicode engines, with no-op definitions
%   for $8$-bit use.
%    \begin{macrocode}
\cs_if_exist:NTF \utex_char:D
  {
    \tl_const:Nx \c__unicode_std_sigma_tl    { \utex_char:D "03C3 ~ }
    \tl_const:Nx \c__unicode_final_sigma_tl  { \utex_char:D "03C2 ~ }
    \tl_const:Nx \c__unicode_accents_lt_tl
      {
        \utex_char:D "00CC ~
          { \utex_char:D "0069 ~ \utex_char:D "0307 ~ \utex_char:D "0300 ~ }
        \utex_char:D "00CD ~
          { \utex_char:D "0069 ~ \utex_char:D "0307 ~ \utex_char:D "0301 ~ }
        \utex_char:D "0128 ~
          { \utex_char:D "0069 ~ \utex_char:D "0307 ~ \utex_char:D "0303 ~ }
      }
    \tl_const:Nx \c__unicode_dot_above_tl    { \utex_char:D "0307 ~ }
    \tl_const:Nx \c__unicode_upper_Eszett_tl { \utex_char:D "1E9E ~ }
  }
  {
      \tl_const:Nn \c__unicode_std_sigma_tl    { }
      \tl_const:Nn \c__unicode_final_sigma_tl  { }
      \tl_const:Nn \c__unicode_accents_lt_tl   { }
      \tl_const:Nn \c__unicode_dot_above_tl    { }
      \tl_const:Nn \c__unicode_upper_Eszett_tl { }
  }
%    \end{macrocode}
% \end{variable}
% \begin{variable}
%   {
%     \c__unicode_dotless_i_tl    ,
%     \c__unicode_dotted_I_tl     ,
%     \c__unicode_i_ogonek_tl     ,
%     \c__unicode_I_ogonek_tl     ,
%   }
%  For cases where there is an $8$-bit option in the |T1| font set up,
%  a variant is provided in both cases.
%    \begin{macrocode}
\group_begin:
  \cs_if_exist:NTF \utex_char:D
    {
      \cs_set_protected:Npn \@@_tmp:w #1#2
        { \tl_const:Nx #1 { \utex_char:D "#2 ~ } }
    }
    {
      \cs_set_protected:Npn \@@_tmp:w #1#2
        {
          \group_begin:
            \cs_set_protected:Npn \@@_tmp:w ##1##2##3
              {
                \tl_const:Nx #1
                  {
                    \exp_after:wN \exp_after:wN \exp_after:wN
                      \exp_not:N \__char_generate:nn {##2} { 13 }
                    \exp_after:wN \exp_after:wN \exp_after:wN
                      \exp_not:N \__char_generate:nn {##3} { 13 }
                  }
              }
            \tl_set:Nx \l_@@_internal_a_tl
              { \__unicode_codepoint_to_UTFviii:n {"#2} }
            \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
          \group_end:
        }
    }
  \@@_tmp:w \c__unicode_dotless_i_tl { 0131 }
  \@@_tmp:w \c__unicode_dotted_I_tl  { 0130 }
  \@@_tmp:w \c__unicode_i_ogonek_tl  { 012F }
  \@@_tmp:w \c__unicode_I_ogonek_tl  { 012E }  
\group_end:
%    \end{macrocode}
% \end{variable}
%
% For $8$-bit engines we now need to define the case-change data for
% the multi-octet mappings. These need a list of what code points are
% doable in |T1| so the list is hard coded (there's no saving in loading
% the mappings dynamically). All of the straight-forward ones have two
% octets, so that is taken as read.
%    \begin{macrocode}
\group_begin:
  \bool_if:nT
    {
      \sys_if_engine_pdftex_p: || \sys_if_engine_uptex_p:
    }
    {
      \cs_set_protected:Npn \@@_loop:nn #1#2
        {
          \quark_if_recursion_tail_stop:n {#1}
          \tl_set:Nx \l_@@_internal_a_tl
            {
              \__unicode_codepoint_to_UTFviii:n {"#1}
              \__unicode_codepoint_to_UTFviii:n {"#2}
            }
          \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
          \@@_loop:nn
        }
      \cs_set_protected:Npn \@@_tmp:w #1#2#3#4#5#6
        {
          \tl_const:cx
            {
              c__unicode_lower_
              \char_generate:nn {#2} { 12 }
              \char_generate:nn {#3} { 12 }
              _tl
            }
            {
              \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_not:N \__char_generate:nn {#5} { 13 }
              \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_not:N \__char_generate:nn {#6} { 13 }
            }
          \tl_const:cx
            {
              c__unicode_upper_
              \char_generate:nn {#5} { 12 }
              \char_generate:nn {#6} { 12 }
              _tl
            }
            {
              \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_not:N \__char_generate:nn {#2} { 13 }
              \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_not:N \__char_generate:nn {#3} { 13 }
            }
        }
      \@@_loop:nn
        { 00C0 } { 00E0 }
        { 00C2 } { 00E2 }
        { 00C3 } { 00E3 }
        { 00C4 } { 00E4 }
        { 00C5 } { 00E5 }
        { 00C6 } { 00E6 }
        { 00C7 } { 00E7 }
        { 00C8 } { 00E8 }
        { 00C9 } { 00E9 }
        { 00CA } { 00EA }
        { 00CB } { 00EB }
        { 00CC } { 00EC }
        { 00CD } { 00ED }
        { 00CE } { 00EE }
        { 00CF } { 00EF }
        { 00D0 } { 00F0 }
        { 00D1 } { 00F1 }
        { 00D2 } { 00F2 }
        { 00D3 } { 00F3 }
        { 00D4 } { 00F4 }
        { 00D5 } { 00F5 }
        { 00D6 } { 00F6 }
        { 00D8 } { 00F8 }
        { 00D9 } { 00F9 }
        { 00DA } { 00FA }
        { 00DB } { 00FB }
        { 00DC } { 00FC }
        { 00DD } { 00FD }
        { 00DE } { 00FE }
        { 0100 } { 0101 }
        { 0102 } { 0103 }
        { 0104 } { 0105 }
        { 0106 } { 0107 }
        { 0108 } { 0109 }
        { 010A } { 010B }
        { 010C } { 010D }
        { 010E } { 010F }
        { 0110 } { 0111 }
        { 0112 } { 0113 }
        { 0114 } { 0115 }
        { 0116 } { 0117 }
        { 0118 } { 0119 }
        { 011A } { 011B }
        { 011C } { 011D }
        { 011E } { 011F }
        { 0120 } { 0121 }
        { 0122 } { 0123 }
        { 0124 } { 0125 }
        { 0128 } { 0129 }
        { 012A } { 012B }
        { 012C } { 012D }
        { 012E } { 012F }
        { 0132 } { 0133 }
        { 0134 } { 0135 }
        { 0136 } { 0137 }
        { 0139 } { 013A }
        { 013B } { 013C }
        { 013E } { 013F }
        { 0141 } { 0142 }
        { 0143 } { 0144 }
        { 0145 } { 0146 }
        { 0147 } { 0148 }
        { 014A } { 014B }
        { 014C } { 014D }
        { 014E } { 014F }
        { 0150 } { 0151 }
        { 0152 } { 0153 }
        { 0154 } { 0155 }
        { 0156 } { 0157 }
        { 0158 } { 0159 }
        { 015A } { 015B }
        { 015C } { 015D }
        { 015E } { 015F }
        { 0160 } { 0161 }
        { 0162 } { 0163 }
        { 0164 } { 0165 }
        { 0168 } { 0169 }
        { 016A } { 016B }
        { 016C } { 016D }
        { 016E } { 016F }
        { 0170 } { 0171 }
        { 0172 } { 0173 }
        { 0174 } { 0175 }
        { 0176 } { 0177 }
        { 0178 } { 00FF }
        { 0179 } { 017A }
        { 017B } { 017C }
        { 017D } { 017E }
        { 01CD } { 01CE }
        { 01CF } { 01D0 }
        { 01D1 } { 01D2 }
        { 01D3 } { 01D4 }
        { 01E2 } { 01E3 }
        { 01E6 } { 01E7 }
        { 01E8 } { 01E9 }
        { 01EA } { 01EB }
        { 01F4 } { 01F5 }
        { 0218 } { 0219 }
        { 021A } { 021B }
        \q_recursion_tail ?
        \q_recursion_stop
      \cs_set_protected:Npn \@@_tmp:w #1#2#3
        {
          \group_begin:
            \cs_set_protected:Npn \@@_tmp:w ##1##2##3
              {
                \tl_const:cx
                  {
                    c__unicode_ #3 _
                    \char_generate:nn {##2} { 12 }
                    \char_generate:nn {##3} { 12 }
                    _tl
                  }
                    {#2}
              }
            \tl_set:Nx \l_@@_internal_a_tl
              { \__unicode_codepoint_to_UTFviii:n { "#1 } }
            \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
          \group_end:
        }
      \@@_tmp:w { 00DF } { SS } { upper }
      \@@_tmp:w { 00DF } { Ss } { title }
      \@@_tmp:w { 0131 } { I }  { upper }
    }
  \group_end:
%    \end{macrocode}
%
% The (fixed) look-up mappings for letter-like control sequences.
%    \begin{macrocode}
\group_begin:
  \cs_set_protected:Npn \@@_change_case_setup:NN #1#2
    {
      \quark_if_recursion_tail_stop:N #1
      \tl_const:cn { c_@@_change_case_lower_ \token_to_str:N #1 _tl } { #2 }
      \tl_const:cn { c_@@_change_case_upper_ \token_to_str:N #2 _tl } { #1 }
      \@@_change_case_setup:NN
    }
  \@@_change_case_setup:NN
  \AA \aa
  \AE \ae
  \DH \dh
  \DJ \dj
  \IJ \ij
  \L  \l
  \NG \ng
  \O  \o
  \OE \oe
  \SS \ss
  \TH \th
  \q_recursion_tail ?
  \q_recursion_stop
  \tl_const:cn { c_@@_change_case_upper_ \token_to_str:N \i _tl } { I }
  \tl_const:cn { c_@@_change_case_upper_ \token_to_str:N \j _tl } { J }
\group_end:
%    \end{macrocode}
%
% \begin{variable}{\l_tl_case_change_accents_tl}
%   A list of accents to leave alone.
%    \begin{macrocode}
\tl_new:N \l_tl_case_change_accents_tl
\tl_set:Nn \l_tl_case_change_accents_tl
  { \" \' \. \^ \` \~ \c \H \k \r \t \u \v }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[aux, EXP]{\@@_mixed_case:nn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_aux:nn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_loop:wn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_group:nwn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_space:wn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_N_type:Nwn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_N_type:NNNnn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_N_type:Nnn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_letterlike:Nw}
% \begin{macro}[aux, EXP]{\@@_mixed_case_char:N}
% \begin{macro}[aux, EXP]{\@@_mixed_case_skip:N}
% \begin{macro}[aux, EXP]{\@@_mixed_case_skip:NN}
% \begin{macro}[aux, EXP]{\@@_mixed_case_skip_tidy:Nwn}
% \begin{macro}[aux, EXP]{\@@_mixed_case_char:nN}
%   Mixed (title) casing requires some custom handling of the case changing
%   of the first letter in the input followed by a switch to the normal
%   lower casing routine. That could be covered by passing a set of functions
%   to generic routines, but at the cost of making the process rather opaque.
%   Instead, the approach taken here is to use a dedicated set of functions
%   which keep the different loop requirements clearly separate.
%
%   The main loop looks for the first \enquote{real} char in the input
%   (skipping any pre-letter chars). Once one is found, it is case changed to
%   upper case but first checking that there is not an entry in the exceptions
%   list. Note that simply grabbing the first token in the input is no good
%   here: it can't handle pre-letter tokens or any special treatment of the
%   first letter found (\emph{e.g.}~words starting with \texttt{i} in
%   Turkish). Spaces at the start of the input are passed through without
%   counting as being the \enquote{start} of the first word, while a brace
%   group is assumed to be contain the first char with everything after the
%   brace therefore lower cased.
%    \begin{macrocode}
\cs_new:Npn \@@_mixed_case:nn #1#2
  {
    \etex_unexpanded:D \exp_after:wN
      {
        \exp:w
        \@@_mixed_case_aux:nn {#1} {#2}
      }
  }
\cs_new:Npn \@@_mixed_case_aux:nn #1#2
  {
    \group_align_safe_begin:
    \@@_mixed_case_loop:wn
      #2 \q_recursion_tail \q_recursion_stop {#1}
    \@@_change_case_result:n { }
  }
\cs_new:Npn \@@_mixed_case_loop:wn #1 \q_recursion_stop
  {
    \tl_if_head_is_N_type:nTF {#1}
      { \@@_mixed_case_N_type:Nwn }
      {
        \tl_if_head_is_group:nTF {#1}
          { \@@_mixed_case_group:nwn }
          { \@@_mixed_case_space:wn }
      }
    #1 \q_recursion_stop
  }
\cs_new:Npn \@@_mixed_case_group:nwn #1#2 \q_recursion_stop #3
  {
    \@@_change_case_output:own
      {
        \exp_after:wN
          {
            \exp:w
            \@@_mixed_case_aux:nn {#3} {#1}
          }
      }
    \@@_change_case_loop:wnn #2 \q_recursion_stop { lower } {#3}
  }
\exp_last_unbraced:NNo \cs_new:Npn \@@_mixed_case_space:wn \c_space_tl
  {
    \@@_change_case_output:nwn { ~ }
    \@@_mixed_case_loop:wn
  }
\cs_new:Npn \@@_mixed_case_N_type:Nwn #1#2 \q_recursion_stop
  {
    \quark_if_recursion_tail_stop_do:Nn #1
      { \@@_change_case_end:wn }
    \exp_after:wN \@@_mixed_case_N_type:NNNnn
      \exp_after:wN #1 \l_tl_case_change_math_tl
      \q_recursion_tail ? \q_recursion_stop {#2}
  }
\cs_new:Npn \@@_mixed_case_N_type:NNNnn #1#2#3
  {
    \quark_if_recursion_tail_stop_do:Nn #2
      { \@@_mixed_case_N_type:Nnn #1 }
    \token_if_eq_meaning:NNTF #1 #2
      {
        \use_i_delimit_by_q_recursion_stop:nw
          {
            \@@_change_case_math:NNNnnn
              #1 #3 \@@_mixed_case_loop:wn
          }
      }
      { \@@_mixed_case_N_type:NNNnn #1 }
  }
%    \end{macrocode}
%   The business end of the loop is here: there is first a need to deal
%   with any control sequence cases before looking for characters to skip.
%   If there is a hit for a letter-like control sequence, switch to lower
%   casing.
%    \begin{macrocode}
\cs_new:Npn \@@_mixed_case_N_type:Nnn #1#2#3
  {
    \token_if_cs:NTF #1
      {
        \@@_change_case_cs_letterlike:Nnn #1 { upper }
          { \@@_mixed_case_letterlike:Nw }
        \@@_mixed_case_loop:wn #2 \q_recursion_stop {#3}
      }
      {
        \@@_mixed_case_char:Nn #1 {#3}
        \@@_change_case_loop:wnn #2 \q_recursion_stop { lower } {#3}
      }
  }
\cs_new:Npn \@@_mixed_case_letterlike:Nw #1#2 \q_recursion_stop
  { \@@_change_case_loop:wnn #2 \q_recursion_stop { lower } }
%    \end{macrocode}
%   As detailed above, handling a mixed case char means first looking for
%   exceptions then treating as an upper cased letter, but with a list of
%   tokens to skip over too.
%    \begin{macrocode}
\cs_new:Npn \@@_mixed_case_char:Nn #1#2
  {
    \cs_if_exist_use:cF { @@_change_case_mixed_ #2 :Nnw }
      {
        \cs_if_exist_use:cF { @@_change_case_upper_ #2 :Nnw }
          { \use_ii:nn }
      }
        #1
        { \@@_mixed_case_skip:N #1 }
  }
\cs_new:Npn \@@_mixed_case_skip:N #1
  {
    \exp_after:wN \@@_mixed_case_skip:NN
      \exp_after:wN #1 \l_tl_mixed_case_ignore_tl
      \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \@@_mixed_case_skip:NN #1#2
  {
    \quark_if_recursion_tail_stop_do:nn {#2}
      { \@@_mixed_case_char:N #1 }
    \int_compare:nNnT { `#1 }  = { `#2 }
      {
        \use_i_delimit_by_q_recursion_stop:nw
          {
            \@@_change_case_output:nwn {#1}
            \@@_mixed_case_skip_tidy:Nwn
          }
      }
    \@@_mixed_case_skip:NN #1
  }
\cs_new:Npn \@@_mixed_case_skip_tidy:Nwn #1#2 \q_recursion_stop #3
  {
    \@@_mixed_case_loop:wn #2 \q_recursion_stop
  }
\cs_new:Npn \@@_mixed_case_char:N #1
  {
    \cs_if_exist:cTF { c__unicode_title_  #1 _tl }
      {
        \@@_change_case_output:fwn
          { \tl_use:c { c__unicode_title_ #1 _tl } }
      }
      { \@@_change_case_char:nN { upper } #1 }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[aux, EXP]{\@@_change_case_mixed_nl:Nnw}
% \begin{macro}[aux, EXP]{\@@_change_case_mixed_nl:Nw}
% \begin{macro}[aux, EXP]{\@@_change_case_mixed_nl:NNw}
%   For Dutch, there is a single look-ahead test for \texttt{ij} when
%   title casing. If the appropriate letters are found, produce \texttt{IJ}
%   and gobble the \texttt{j}/\texttt{J}.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_mixed_nl:Nnw #1
  {
    \bool_if:nTF
      {
           \int_compare_p:nNn { `#1 } = { `i }
        || \int_compare_p:nNn { `#1 } = { `I }
      }
      {
        \@@_change_case_output:nwn { I }
        \@@_change_case_mixed_nl:Nw
      }
  }
\cs_new:Npn \@@_change_case_mixed_nl:Nw #1#2 \q_recursion_stop
  {
    \tl_if_head_is_N_type:nT {#2}
      { \@@_change_case_mixed_nl:NNw }
    #1 #2 \q_recursion_stop
  }
\cs_new:Npn \@@_change_case_mixed_nl:NNw #1#2#3 \q_recursion_stop
  {
    \@@_change_case_if_expandable:NTF #2
      {
        \exp_after:wN \@@_change_case_mixed_nl:Nw \exp_after:wN #1 #2
          #3 \q_recursion_stop
      }
      {
        \bool_if:nTF
          {
            ! ( \token_if_cs_p:N #2 )
            &&
              (
                   \int_compare_p:nNn { `#2 } = { `j }
                || \int_compare_p:nNn { `#2 } = { `J }
              )
          }
          {
            \@@_change_case_output:nwn { J }
            #1
          }
          { #1 #2 }
        #3 \q_recursion_stop
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{variable}{\l_tl_case_change_math_tl}
%   The list of token pairs which are treated as math mode and so
%   not case changed.
%    \begin{macrocode}
\tl_new:N \l_tl_case_change_math_tl
%<*package>
\tl_set:Nn \l_tl_case_change_math_tl
  { $ $ \( \) }
%</package>
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_tl_case_change_exclude_tl}
%   The list of commands for which an argument is not case changed.
%    \begin{macrocode}
\tl_new:N \l_tl_case_change_exclude_tl
%<*package>
\tl_set:Nn \l_tl_case_change_exclude_tl
  { \cite \ensuremath \label \ref }
%</package>
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_tl_mixed_case_ignore_tl}
%   Characters to skip over when finding the first letter in a word to be
%   mixed cased.
%    \begin{macrocode}
\tl_new:N \l_tl_mixed_case_ignore_tl
\tl_set:Nx \l_tl_mixed_case_ignore_tl
  {
    ( % )
    [ % ]
    \cs_to_str:N \{ % \}
    `
    -
  }
%    \end{macrocode}
% \end{variable}
%
%
% \begin{macro}{\tl_log:N, \tl_log:c}
%   Redirect output of \cs{tl_show:N} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \tl_log:N
  { \__msg_log_next: \tl_show:N }
\cs_generate_variant:Nn \tl_log:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tl_log:n}
%   Redirect output of \cs{tl_show:n} to the log.
%    \begin{macrocode}
\cs_new_protected:Npn \tl_log:n
  { \__msg_log_next: \tl_show:n }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3tokens}}
%
%    \begin{macrocode}
%<@@=peek>
%    \end{macrocode}
%
% \begin{macro}[TF]{\peek_N_type:}
% \begin{macro}[aux]
%   {\@@_execute_branches_N_type:, \@@_N_type:w, \@@_N_type_aux:nnw}
%   All tokens are \texttt{N}-type tokens, except in four cases:
%   begin-group tokens, end-group tokens, space tokens with character
%   code~$32$, and outer tokens.  Since \cs{l_peek_token} might be
%   outer, we cannot use the convenient \cs{bool_if:nTF} function, and
%   must resort to the old trick of using \tn{ifodd} to expand a set of
%   tests.  The \texttt{false} branch of this test is taken if the token
%   is one of the first three kinds of non-\texttt{N}-type tokens
%   (explicit or implicit), thus we call \cs{@@_false:w}.  In the
%   \texttt{true} branch, we must detect outer tokens, without impacting
%   performance too much for non-outer tokens.  The first filter is to
%   search for \texttt{outer} in the \tn{meaning} of \cs{l_peek_token}.
%   If that is absent, \cs{use_none_delimit_by_q_stop:w} cleans up, and
%   we call \cs{@@_true:w}.  Otherwise, the token can be a non-outer
%   macro or a primitive mark whose parameter or replacement text
%   contains \texttt{outer}, it can be the primitive \tn{outer}, or it
%   can be an outer token.  Macros and marks would have \texttt{ma} in
%   the part before the first occurrence of \texttt{outer}; the meaning
%   of \tn{outer} has nothing after \texttt{outer}, contrarily to outer
%   macros; and that covers all cases, calling \cs{@@_true:w} or
%   \cs{@@_false:w} as appropriate.  Here, there is no \meta{search
%     token}, so we feed a dummy \cs{scan_stop:} to the
%   \cs{@@_token_generic:NNTF} function.
%    \begin{macrocode}
\group_begin:
  \cs_set_protected:Npn \@@_tmp:w #1 \q_stop
    {
      \cs_new_protected:Npn \@@_execute_branches_N_type:
        {
          \if_int_odd:w
              \if_catcode:w \exp_not:N \l_peek_token {   \c_two \fi:
              \if_catcode:w \exp_not:N \l_peek_token }   \c_two \fi:
              \if_meaning:w \l_peek_token \c_space_token \c_two \fi:
              \c_one
            \exp_after:wN \@@_N_type:w
              \token_to_meaning:N \l_peek_token
              \q_mark \@@_N_type_aux:nnw
              #1 \q_mark \use_none_delimit_by_q_stop:w
              \q_stop
            \exp_after:wN \@@_true:w
          \else:
            \exp_after:wN \@@_false:w
          \fi:
        }
      \cs_new_protected:Npn \@@_N_type:w ##1 #1 ##2 \q_mark ##3
        { ##3 {##1} {##2} }
    }
  \exp_after:wN \@@_tmp:w \tl_to_str:n { outer } \q_stop
\group_end:
\cs_new_protected:Npn \@@_N_type_aux:nnw #1 #2 #3 \fi:
  {
    \fi:
    \tl_if_in:noTF {#1} { \tl_to_str:n {ma} }
      { \@@_true:w }
      { \tl_if_empty:nTF {#2} { \@@_true:w } { \@@_false:w } }
  }
\cs_new_protected:Npn \peek_N_type:TF
  { \@@_token_generic:NNTF \@@_execute_branches_N_type: \scan_stop: }
\cs_new_protected:Npn \peek_N_type:T
  { \@@_token_generic:NNT \@@_execute_branches_N_type: \scan_stop: }
\cs_new_protected:Npn \peek_N_type:F
  { \@@_token_generic:NNF \@@_execute_branches_N_type: \scan_stop: }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
