% \iffalse meta-comment
%
%% File: l3candidates.dtx
%
% Copyright (C) 2012-2019 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
%
%    https://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 development version of the bundle can be found at
%
%    https://github.com/latex3/latex3
%
% for those people who are interested.
%
%<*driver>
\documentclass[full,kernel]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \textsf{l3candidates} package\\ Experimental additions to
%   \pkg{l3kernel}^^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 2019-09-19}
%
% \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 = 2017-07-16, updated = 2017-08-02]{\debug_on:n, \debug_off:n}
%   \begin{syntax}
%     \cs{debug_on:n} |{| \meta{comma-separated list} |}|
%     \cs{debug_off:n} |{| \meta{comma-separated list} |}|
%   \end{syntax}
%   Turn on and off within a group various debugging code, some of which
%   is also available as \pkg{expl3} load-time options.  The items that
%   can be used in the \meta{list} are
%   \begin{itemize}
%     \item \texttt{check-declarations} that checks all \pkg{expl3}
%       variables used were previously declared and that local/global
%       variables (based on their name or on their first assignment) are
%       only locally/globally assigned;
%     \item \texttt{check-expressions} that checks integer, dimension,
%       skip, and muskip expressions are not terminated prematurely;
%     \item \texttt{deprecation} that makes soon-to-be-deprecated commands produce errors;
%     \item \texttt{log-functions} that logs function definitions;
%     \item \texttt{all} that does all of the above.
%   \end{itemize}
%   Providing these as switches rather than options allows testing code
%   even if it relies on other packages: load all other packages, call
%   \cs{debug_on:n}, and load the code that one is interested in
%   testing.  These functions can only be used in \LaTeXe{} package mode
%   loaded with \texttt{enable-debug} or another option implying it.
% \end{function}
%
% \begin{function}[added = 2017-11-28]{\debug_suspend:, \debug_resume:}
%   \begin{syntax}
%     \cs{debug_suspend:} \ldots{} \cs{debug_resume:}
%   \end{syntax}
%   Suppress (locally) errors and logging from \texttt{debug} commands,
%   except for the \texttt{deprecation} errors or warnings.  These pairs
%   of commands can be nested.  This can be used around pieces of code
%   that are known to fail checks, if such failures should be ignored.
%   See for instance \pkg{l3coffins}.
% \end{function}
%
% \begin{function}[added = 2017-07-04]{\mode_leave_vertical:}
%   \begin{syntax}
%     \cs{mode_leave_vertical:}
%   \end{syntax}
%   Ensures that \TeX{} is not in vertical (inter-paragraph) mode. In
%   horizontal or math mode this command has no effect, in vertical mode it
%   switches to horizontal mode, and inserts a box of width
%   \tn{parindent}, followed by the \tn{everypar} token list.
%   \begin{texnote}
%     This results in the contents of the \tn{everypar} token register being
%     inserted, after \cs{mode_leave_vertical:} is complete. Notice that in
%     contrast to the \LaTeXe{} \tn{leavevmode} approach, no box is used
%     by the method implemented here.
%   \end{texnote}
% \end{function}
%
% \section{Additions to \pkg{l3box}}
%
% \subsection{Viewing part of a box}
%
% \begin{function}[updated = 2019-01-23]
%   {\box_clip:N, \box_clip:c, \box_gclip:N, \box_gclip: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} is an
%   hbox, irrespective of the nature of the \meta{box} before the clipping is
%   applied.
%
%   \textbf{These functions require the \LaTeX3 native drivers: they do
%   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}[added = 2019-01-23]
%   {
%     \box_set_trim:Nnnnn, \box_set_trim:cnnnn,
%     \box_gset_trim:Nnnnn, \box_gset_trim:cnnnn
%   }
%   \begin{syntax}
%     \cs{box_set_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 outside of the bounding box is still displayed in the output
%   unless \cs{box_clip:N} is subsequently applied.
%   The updated \meta{box} is an
%   hbox, irrespective of the nature of the \meta{box} before the trim
%   operation is applied.
%   The behavior of the operation where the trims requested is
%   greater than the size of the box is undefined.
% \end{function}
%
% \begin{function}[added = 2019-01-23]
%   {
%     \box_set_viewport:Nnnnn, \box_set_viewport:cnnnn,
%     \box_gset_viewport:Nnnnn, \box_gset_viewport:cnnnn
%   }
%   \begin{syntax}
%     \cs{box_set_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 outside of the bounding box is
%   still displayed in the output unless \cs{box_clip:N} is
%   subsequently applied.
%   The updated \meta{box} is an
%   hbox, irrespective of the nature of the \meta{box} before the viewport
%   operation is applied.
% \end{function}
%
% \section{Additions to \pkg{l3expan}}
%
% \begin{function}[added = 2018-04-04, updated = 2019-02-08]
%   {\exp_args_generate:n}
%   \begin{syntax}
%     \cs{exp_args_generate:n} \Arg{variant argument specifiers}
%   \end{syntax}
%   Defines \cs[no-index]{exp_args:N\meta{variant}} functions for each
%   \meta{variant} given in the comma list \Arg{variant argument
%   specifiers}.  Each \meta{variant} should consist of the letters |N|,
%   |c|, |n|, |V|, |v|, |o|, |f|, |e|, |x|, |p| and the resulting function is
%   protected if the letter |x| appears in the \meta{variant}.  This is
%   only useful for cases where \cs{cs_generate_variant:Nn} is not
%   applicable.
% \end{function}
%
% \section{Additions to \pkg{l3fp}}
%
% \begin{function}[EXP, added = 2018-11-03]{logb}
%   \begin{syntax}
%     \cs{fp_eval:n} \{ |logb(| \meta{fpexpr} |)| \}
%   \end{syntax}
%   Determines the exponent of the \meta{fpexpr}, namely the floor of
%   the base-$10$ logarithm of its absolute value.  \enquote{Division by
%   zero} occurs when evaluating $\operatorname{logb}(\pm 0) = -\infty$.
%   Other special values are $\operatorname{logb}(\pm\infty)=+\infty$
%   and $\operatorname{logb}(\nan{})=\nan{}$.  If the operand is a tuple
%   or is \nan{}, then \enquote{invalid operation} occurs and the result
%   is \nan{}.
% \end{function}
%
% \begin{function}[EXP, added = 2018-11-03]{\fp_sign:n}
%   \begin{syntax}
%     \cs{fp_sign:n} \Arg{fpexpr}
%   \end{syntax}
%   Evaluates the \meta{fpexpr} and leaves its sign in the input stream
%   using \cs{fp_eval:n} |{sign(|\meta{result}|)}|: $+1$ for positive
%   numbers and for $+\infty$, $-1$ for negative numbers and for
%   $-\infty$, $\pm 0$ for $\pm 0$.  If the operand is a tuple or is
%   \nan{}, then \enquote{invalid operation} occurs and the result
%   is~$0$.
% \end{function}
%
% \begin{function}[pTF, added = 2019-08-25]{\fp_if_nan:n}
%   \begin{syntax}
%     \cs{fp_if_nan:n} \Arg{fpexpr}
%   \end{syntax}
%   Evaluates the \meta{fpexpr} and tests whether the result is exactly
%   \nan{}.  The test returns \texttt{false} for any other result, even
%   a tuple containing \nan{}.
% \end{function}
%
% \section{Additions to \pkg{l3fparray}}
%
% \begin{function}[added = 2018-05-05]{\fparray_new:Nn}
%   \begin{syntax}
%     \cs{fparray_new:Nn} \meta{fparray~var} \Arg{size}
%   \end{syntax}
%   Evaluates the integer expression \meta{size} and allocates an
%   \meta{floating point array variable} with that number of (zero)
%   entries.  The variable name should start with |\g_| because
%   assignments are always global.
% \end{function}
%
% \begin{function}[EXP, added = 2018-05-05]{\fparray_count:N}
%   \begin{syntax}
%     \cs{fparray_count:N} \meta{fparray~var}
%   \end{syntax}
%   Expands to the number of entries in the \meta{floating point array
%   variable}.  This is performed in constant time.
% \end{function}
%
% \begin{function}[added = 2018-05-05]{\fparray_gset:Nnn}
%   \begin{syntax}
%     \cs{fparray_gset:Nnn} \meta{fparray~var} \Arg{position} \Arg{value}
%   \end{syntax}
%   Stores the result of evaluating the floating point expression
%   \meta{value} into the \meta{floating point array variable} at the
%   (integer expression) \meta{position}.  If the \meta{position} is not
%   between $1$ and the \cs{fparray_count:N}, an error occurs.
%   Assignments are always global.
% \end{function}
%
% \begin{function}[added = 2018-05-05]{\fparray_gzero:N}
%   \begin{syntax}
%     \cs{fparray_gzero:N} \meta{fparray~var}
%   \end{syntax}
%   Sets all entries of the \meta{floating point array variable} to
%   $+0$.  Assignments are always global.
% \end{function}
%
% \begin{function}[EXP, added = 2018-05-05]
%   {\fparray_item:Nn, \fparray_item_to_tl:Nn}
%   \begin{syntax}
%     \cs{fparray_item:Nn} \meta{fparray~var} \Arg{position}
%   \end{syntax}
%   Applies \cs{fp_use:N} or \cs{fp_to_tl:N} (respectively) to the
%   floating point entry stored at the (integer expression)
%   \meta{position} in the \meta{floating point array variable}.  If the
%   \meta{position} is not between $1$ and the \cs{fparray_count:N}, an
%   error occurs.
% \end{function}
%
% \section{Additions to \pkg{l3file}}
%
% \begin{function}[added = 2019-05-13, TF]{\file_compare_timestamp:nNn}
%   \begin{syntax}
%     \cs{file_compare_timestamp:nNn} \Arg{file-1} \meta{comparator} \Arg{file-2} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Compares the file stamps on the two \meta{files} as indicated by
%   the \meta{comparator}, and inserts either the \meta{true code}
%   or \meta{false case} as required. A file which is not found
%   is treated as older than any file which is found.This allows for
%   example the construct
%   \begin{verbatim}
%     \file_compare_timestamp:nNnT { source-file } > { derived-file }
%       {
%         % Code to regenerate derived file
%       }
%   \end{verbatim}
%   to work when the derived file is entirely absent. The timestamp
%   of two absent files is regarded as different.
% \end{function}
%
% \begin{function}[added = 2019-01-13]{\ior_map_variable:NNn}
%   \begin{syntax}
%     \cs{ior_map_variable:NNn} \meta{stream} \meta{tl~var} \Arg{code}
%   \end{syntax}
%   For each set of \meta{lines} obtained by calling \cs{ior_get:NN}
%   until reaching the end of the file, stores the \meta{lines} in the
%   \meta{tl~var} then applies the \meta{code}.  The \meta{code} will
%   usually make use of the \meta{variable}, but this is not enforced.
%   The assignments to the \meta{variable} are local.
%   Its value after the loop is the last set of \meta{lines}, or its
%   original value if the \meta{stream} is empty.  \TeX{} ignores
%   any trailing new-line marker from the file it reads.
%   This function is typically faster than \cs{ior_map_inline:Nn}.
% \end{function}
%
% \begin{function}[added = 2019-01-13]{\ior_str_map_variable:NNn}
%   \begin{syntax}
%     \cs{ior_str_map_variable:NNn} \meta{stream} \meta{variable} \Arg{code}
%   \end{syntax}
%   For each \meta{line} in the \meta{stream}, stores the \meta{line} in
%   the \meta{variable} then applies the \meta{code}.  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{code} will usually make use
%   of the \meta{variable}, but this is not enforced.  The assignments
%   to the \meta{variable} are local.  Its value after the loop is the
%   last \meta{line}, or its original value if the \meta{stream} is
%   empty.  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.
%   This function is typically faster than \cs{ior_str_map_inline:Nn}.
% \end{function}
%
% \begin{function}[added = 2018-12-29]{\iow_allow_break:}
%   \begin{syntax}
%     \cs{iow_allow_break:}
%   \end{syntax}
%   In the first argument of \cs{iow_wrap:nnnN} (for instance in
%   messages), inserts a break-point that allows a line break.
%   In other words this is a zero-width breaking space.
% \end{function}
%
% \begin{function}[added = 2019-03-23]{\ior_get_term:nN, \ior_str_get_term:nN}
%   \begin{syntax}
%     \cs{ior_get_term:nN} \meta{prompt} \meta{token list variable}
%   \end{syntax}
%   Function that reads one or more lines (until an equal number of left
%   and right braces are found) from the terminal and stores
%   the result locally in the \meta{token list} variable. Tokenization
%   occurs as described for \cs{ior_get:NN} or \cs{ior_str_get:NN}, respectively.
%   When the \meta{prompt}
%   is empty, \TeX{} will wait for input without any other indication:
%   typically the programmer will have provided a suitable text using
%   e.g.~\cs{iow_term:n}. Where the \meta{prompt} is given, it will appear
%   in the terminal followed by an |=|, e.g.
%   \begin{verbatim}
%     prompt=
%   \end{verbatim}
% \end{function}
%
% \begin{function}[added = 2019-05-08]{\ior_shell_open:Nn}
%   \begin{syntax}
%     \cs{ior_shell_open:nN} \meta{stream} \Arg{shell~command}
%   \end{syntax}
%   Opens the \emph{pseudo}-file created by the output of the
%   \meta{shell command} for reading using \meta{stream} as the
%   control sequence for access. If the \meta{stream} was already
%   open it is closed before the new operation begins. The
%   \meta{stream} is available for access immediately and will remain
%   allocated to \meta{shell command} until a \cs{ior_close:N} instruction
%   is given or the \TeX{} run ends.
%   If piped system calls are disabled an error is raised.
%
%   For details of handling of the \meta{shell command}, see
%   \cs{sys_shell_get:nnN(TF)}.
% \end{function}
%
% \section{Additions to \pkg{l3flag}}
%
% \begin{function}[EXP, added = 2018-04-02]{\flag_raise_if_clear:n}
%   \begin{syntax}
%     \cs{flag_raise_if_clear:n} \Arg{flag name}
%   \end{syntax}
%   Ensures the \meta{flag} is raised by making its height at least~$1$,
%   locally.
% \end{function}
%
% \section{Additions to \pkg{l3int}}
%
% \begin{function}[EXP, added = 2018-11-03]{\int_sign:n}
%   \begin{syntax}
%     \cs{int_sign:n} \Arg{intexpr}
%   \end{syntax}
%   Evaluates the \meta{integer expression} then leaves $1$ or $0$ or
%   $-1$ in the input stream according to the sign of the result.
% \end{function}
%
% \section{Additions to \pkg{l3intarray}}
%
% \begin{function}[added = 2018-05-05]{\intarray_gset_rand:Nnn, \intarray_gset_rand:Nn}
%   \begin{syntax}
%     \cs{intarray_gset_rand:Nnn} \meta{intarray~var} \Arg{minimum} \Arg{maximum}
%     \cs{intarray_gset_rand:Nn} \meta{intarray~var} \Arg{maximum}
%   \end{syntax}
%   Evaluates the integer expressions \meta{minimum} and \meta{maximum}
%   then sets each entry (independently) of the \meta{integer array
%   variable} to a pseudo-random number between the two (with bounds
%   included).  If the absolute value of either bound is bigger than
%   $2^{30}-1$, an error occurs.  Entries are generated in the same way
%   as repeated calls to \cs{int_rand:nn} or \cs{int_rand:n}
%   respectively, in particular for the second function the
%   \meta{minimum} is $1$.
%   Assignments are always global.
%   This is not available in older versions of \XeTeX{}.
% \end{function}
%
% \subsection{Working with contents of integer arrays}
%
% \begin{function}[added = 2018-05-04, rEXP]{\intarray_const_from_clist:Nn}
%   \begin{syntax}
%     \cs{intarray_const_from_clist:Nn} \meta{intarray~var} \meta{intexpr clist}
%   \end{syntax}
%   Creates a new constant \meta{integer array variable} or raises an
%   error if the name is already taken.  The \meta{integer array
%   variable} is set (globally) to contain as its items the results of
%   evaluating each \meta{integer expression} in the \meta{comma list}.
% \end{function}
%
% \begin{function}[added = 2018-05-04, rEXP]{\intarray_to_clist:N}
%   \begin{syntax}
%     \cs{intarray_to_clist:N} \meta{intarray~var}
%   \end{syntax}
%   Converts the \meta{intarray} to integer denotations separated by
%   commas.  All tokens have category code other.  If the
%   \meta{intarray} has no entry the result is empty; otherwise the
%   result has one fewer comma than the number of items.
% \end{function}
%
% \begin{function}[added = 2018-05-04]{\intarray_show:N, \intarray_log:N}
%   \begin{syntax}
%     \cs{intarray_show:N} \meta{intarray~var}
%     \cs{intarray_log:N} \meta{intarray~var}
%   \end{syntax}
%   Displays the items in the \meta{integer array variable} in the
%   terminal or writes them in the log file.
% \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, short-hands such as |\{| or |\\| do
% not work, 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, by putting the most important information up front.
% Another particularity of expandable messages is that they
% cannot be redirected or turned off by the user.
%
% \begin{function}[EXP, added = 2015-08-06, updated = 2019-02-28]
%   {
%     \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}
%
% \begin{function}[added = 2017-12-04]{\msg_show_eval:Nn, \msg_log_eval:Nn}
%   \begin{syntax}
%     \cs{msg_show_eval:Nn} \meta{function} \Arg{expression}
%   \end{syntax}
%   Shows or logs the \meta{expression} (turned into a string), an equal
%   sign, and the result of applying the \meta{function} to the
%   \Arg{expression} (with \texttt{f}-expansion).  For instance, if the
%   \meta{function} is \cs{int_eval:n} and the \meta{expression} is
%   |1+2| then this logs |> 1+2=3.|
% \end{function}
%
% \begin{function}[added = 2017-12-04]
%   {
%     \msg_show:nnnnnn ,
%     \msg_show:nnnnn  ,
%     \msg_show:nnnn   ,
%     \msg_show:nnn    ,
%     \msg_show:nn     ,
%     \msg_show:nnxxxx ,
%     \msg_show:nnxxx  ,
%     \msg_show:nnxx   ,
%     \msg_show:nnx
%   }
%   \begin{syntax}
%     \cs{msg_show:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
%   \end{syntax}
%   Issues \meta{module} information \meta{message}, passing \meta{arg
%   one} to \meta{arg four} to the text-creating functions.  The
%   information text is shown on the terminal and the \TeX{} run is
%   interrupted in a manner similar to \cs{tl_show:n}.  This is used in
%   conjunction with \cs{msg_show_item:n} and similar functions to print
%   complex variable contents completely.  If the formatted text does
%   not contain |>~| at the start of a line, an additional line |>~.|
%   will be put at the end.  In addition, a final period is added if not
%   present.
% \end{function}
%
% \begin{function}[EXP, added = 2017-12-04]
%   {\msg_show_item:n, \msg_show_item_unbraced:n, \msg_show_item:nn, \msg_show_item_unbraced:nn}
%   \begin{syntax}
%     \cs{seq_map_function:NN} \meta{seq} \cs{msg_show_item:n}
%     \cs{prop_map_function:NN} \meta{prop} \cs{msg_show_item:nn}
%   \end{syntax}
%   Used in the text of messages for \cs{msg_show:nnxxxx} to show or log
%   a list of items or key--value pairs.  The one-argument functions are
%   used for sequences, clist or token lists and the others for property
%   lists.  These functions turn their arguments to strings.
% \end{function}
%
% \section{Additions to \pkg{l3prg}}
%
% \begin{function}[added = 2017-11-28]{\bool_const:Nn, \bool_const:cn}
%   \begin{syntax}
%     \cs{bool_const:Nn} \meta{boolean} \Arg{boolexpr}
%   \end{syntax}
%   Creates a new constant \meta{boolean} or raises an error if the name
%   is already taken. The value of the \meta{boolean} is set globally to
%   the result of evaluating the \meta{boolexpr}.
% \end{function}
%
% \begin{function}[added = 2018-05-10]
%   {
%     \bool_set_inverse:N , \bool_set_inverse:c ,
%     \bool_gset_inverse:N, \bool_gset_inverse:c
%   }
%   \begin{syntax}
%     \cs{bool_set_inverse:N} \meta{boolean}
%   \end{syntax}
%   Toggles the \meta{boolean} from \texttt{true} to \texttt{false} and
%   conversely: sets it to the inverse of its current value.
% \end{function}
%
% \section{Additions to \pkg{l3prop}}
%
% \begin{function}[EXP, added = 2016-12-06]
%   {\prop_rand_key_value:N, \prop_rand_key_value:c}
%   \begin{syntax}
%     \cs{prop_rand_key_value:N} \meta{prop~var}
%   \end{syntax}
%   Selects a pseudo-random key--value pair from the \meta{property list}
%   and returns \Arg{key} and \Arg{value}.  If the \meta{property list} is
%   empty the result is empty.
%   This is not available in older versions of \XeTeX{}.
%   \begin{texnote}
%     The result is returned within the \tn{unexpanded}
%     primitive (\cs{exp_not:n}), which means that the \meta{value}
%     does not expand further when appearing in an \texttt{x}-type
%     argument expansion.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2017-11-28, updated = 2019-08-25]
%   {
%     \prop_set_from_keyval:Nn, \prop_set_from_keyval:cn,
%     \prop_gset_from_keyval:Nn, \prop_gset_from_keyval:cn,
%   }
%   \begin{syntax}
%     \cs{prop_set_from_keyval:Nn} \meta{prop~var}
%       \{
%         \meta{key1} |=| \meta{value1} |,|
%         \meta{key2} |=| \meta{value2} |,| \ldots{}
%       \}
%   \end{syntax}
%   Sets \meta{prop~var} to contain key--value pairs given in the second
%   argument.  If duplicate keys appear only one of the values is kept.
% \end{function}
%
% \begin{function}[added = 2017-11-28, updated = 2019-08-25]
%   {\prop_const_from_keyval:Nn, \prop_const_from_keyval:cn}
%   \begin{syntax}
%     \cs{prop_const_from_keyval:Nn} \meta{prop~var}
%       \{
%         \meta{key1} |=| \meta{value1} |,|
%         \meta{key2} |=| \meta{value2} |,| \ldots{}
%       \}
%   \end{syntax}
%   Creates a new constant \meta{prop~var} or raises an error if the
%   name is already taken. The \meta{prop~var} is set globally to
%   contain key--value pairs given in the second argument.
%   If duplicate keys appear only one of the values is kept.
% \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}
%   receives two \texttt{n}-type arguments for each iteration. The  mapping
%   terminates 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}
%   receives 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 would 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 would lead to low-level \TeX{} errors.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2017-11-28]
%   {\seq_const_from_clist:Nn,  \seq_const_from_clist:cn}
%   \begin{syntax}
%     \cs{seq_const_from_clist:Nn} \meta{seq~var} \Arg{comma-list}
%   \end{syntax}
%   Creates a new constant \meta{seq~var} or raises an error if the name
%   is already taken. The \meta{seq~var} is set globally to contain the
%   items in the \meta{comma list}.
% \end{function}
%
% \begin{function}[added = 2018-04-06]
%   {\seq_set_from_function:NnN, \seq_gset_from_function:NnN}
%   \begin{syntax}
%     \cs{seq_set_from_function:NnN} \meta{seq~var} \Arg{loop~code} \meta{function}
%   \end{syntax}
%   Sets the \meta{seq~var} equal to a sequence whose items are obtained
%   by \texttt{x}-expanding \meta{loop~code} \meta{function}.  This
%   expansion must result in successive calls to the \meta{function}
%   with no nonexpandable tokens in between.  More precisely the
%   \meta{function} is replaced by a wrapper function that inserts the
%   appropriate separators between items in the sequence.  The
%   \meta{loop~code} must be expandable; it can be for example
%   \cs{tl_map_function:NN} \meta{tl~var} or \cs{clist_map_function:nN}
%   \Arg{clist} or \cs{int_step_function:nnnN} \Arg{initial value}
%   \Arg{step} \Arg{final value}.
% \end{function}
%
% \begin{function}[added = 2018-04-06]
%   {\seq_set_from_inline_x:Nnn, \seq_gset_from_inline_x:Nnn}
%   \begin{syntax}
%     \cs{seq_set_from_inline_x:Nnn} \meta{seq~var} \Arg{loop~code} \Arg{inline~code}
%   \end{syntax}
%   Sets the \meta{seq~var} equal to a sequence whose items are obtained
%   by \texttt{x}-expanding \meta{loop~code} applied to a
%   \meta{function} derived from the \meta{inline~code}.  A
%   \meta{function} is defined, that takes one argument,
%   \texttt{x}-expands the \meta{inline~code} with that argument
%   as~|#1|, then adds appropriate separators to turn the result into an
%   item of the sequence.  The \texttt{x}-expansion of \meta{loop~code}
%   \meta{function} must result in successive calls to the
%   \meta{function} with no nonexpandable tokens in between.  The
%   \meta{loop~code} must be expandable; it can be for example
%   \cs{tl_map_function:NN} \meta{tl~var} or \cs{clist_map_function:nN}
%   \Arg{clist} or \cs{int_step_function:nnnN} \Arg{initial value}
%   \Arg{step} \Arg{final value}, but not the analogous \enquote{inline}
%   mappings.
% \end{function}
%
% \begin{function}[added = 2018-04-29]{\seq_shuffle:N, \seq_gshuffle:N}
%   \begin{syntax}
%     \cs{seq_shuffle:N} \meta{seq~var}
%   \end{syntax}
%   Sets the \meta{seq~var} to the result of placing the items of the
%   \meta{seq~var} in a random order.  Each item is (roughly) as likely
%   to end up in any given position.
%   \begin{texnote}
%     For sequences with more than $13$ items or so, only a small
%     proportion of all possible permutations can be reached, because
%     the random seed \cs{sys_rand_seed:} only has $28$-bits.  The use
%     of \tn{toks} internally means that sequences with more than
%     $32767$ or $65535$ items (depending on the engine) cannot be
%     shuffled.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2018-05-03]{\seq_indexed_map_function:NN}
%   \begin{syntax}
%     \cs{seq_indexed_map_function:NN} \meta{seq~var} \meta{function}
%   \end{syntax}
%   Applies \meta{function} to every entry in the \meta{sequence
%   variable}.  The \meta{function} should have signature |:nn|.  It
%   receives two arguments for each iteration: the \meta{index} (namely
%   |1| for the first entry, then |2| and so on) and the \meta{item}.
% \end{function}
%
% \begin{function}[added = 2018-05-03]{\seq_indexed_map_inline:Nn}
%   \begin{syntax}
%     \cs{seq_indexed_map_inline:Nn} \meta{seq~var} \Arg{inline function}
%   \end{syntax}
%   Applies \meta{inline function} to every entry in the \meta{sequence
%   variable}.  The \meta{inline function} should consist of code which
%   receives the \meta{index} (namely |1| for the first entry, then |2|
%   and so on) as~|#1| and the \meta{item} as~|#2|.
% \end{function}
%
% \section{Additions to \pkg{l3skip}}
%
% \begin{function}[EXP, added = 2018-11-03]{\dim_sign:n}
%   \begin{syntax}
%     \cs{dim_sign:n} \Arg{dimexpr}
%   \end{syntax}
%   Evaluates the \meta{dimexpr} then leaves $1$ or $0$ or $-1$ in the
%   input stream according to the sign of the result.
% \end{function}
%
% \section{Additions to \pkg{l3sys}}
%
% \begin{function}[noTF, added = 2019-01-16, updated = 2019-02-16]
%   {\sys_shell_get:nnN}
%   \begin{syntax}
%     \cs{sys_shell_get:nnN} \Arg{shell~command} \Arg{setup} \meta{tl~var}
%     \cs{sys_shell_get:nnNTF} \Arg{shell~command} \Arg{setup} \meta{tl~var} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Defines \meta{tl} to the text returned by the \meta{shell command}.
%   The \meta{shell command} is converted to a string using
%   \cs{tl_to_str:n}.  Category codes may need to be set appropriately
%   via the \meta{setup} argument, which is run just before running the
%   \meta{shell command} (in a group).
%   If shell escape is disabled, the \meta{tl~var} will be set to
%   \cs{q_no_value} in the non-branching version.
%   Note that quote characters (|"|) \emph{cannot} be used inside the
%   \meta{shell command}.  The \cs{sys_shell_get:nnNTF} conditional
%   returns \texttt{true} if the shell is available and no quote is
%   detected, and \texttt{false} otherwise.
% \end{function}
%
% \begin{variable}[added = 2018-05-02]{\c_sys_engine_version_str}
%   The version string of the current engine, in the same form as
%   given in the banner issued when running a job. For \pdfTeX{}
%   and \LuaTeX{} this is of the form
%   \begin{quote}
%     \meta{major}.\meta{minor}.\meta{revision}
%   \end{quote}
%   For \XeTeX{}, the form is
%   \begin{quote}
%     \meta{major}.\meta{minor}
%   \end{quote}
%   For \pTeX{} and \upTeX{}, only releases since \TeX{} Live 2018
%   make the data available, and the form is more complex, as it comprises
%   the \pTeX{} version, the \upTeX{} version and the e-\pTeX{} version.
%   \begin{quote}
%     p\meta{major}.\meta{minor}.\meta{revision}-u\meta{major}.\meta{minor}^^A
%     -\meta{epTeX}
%   \end{quote}
%   where the |u| part is only present for \upTeX{}.
% \end{variable}
%
% \begin{function}[added = 2017-05-27, EXP, pTF]{\sys_if_rand_exist:}
%   \begin{syntax}
%     \cs{sys_if_rand_exist_p:}
%     \cs{sys_if_rand_exist:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if the engine has a pseudo-random number generator.  Currently
%   this is the case in \pdfTeX{}, \LuaTeX{}, \pTeX{} and \upTeX{}.
% \end{function}
%
% \begin{function}[added = 2017-05-27, EXP]{\sys_rand_seed:}
%   \begin{syntax}
%     \cs{sys_rand_seed:}
%   \end{syntax}
%   Expands to the current value of the engine's random seed, a
%   non-negative integer.  In engines without random number support this
%   expands to $0$.
% \end{function}
%
% \begin{function}[added = 2017-05-27]{\sys_gset_rand_seed:n}
%   \begin{syntax}
%     \cs{sys_gset_rand_seed:n} \Arg{intexpr}
%   \end{syntax}
%   Globally sets the seed for the engine's pseudo-random number
%   generator to the \meta{integer expression}.  This random seed
%   affects all \cs[no-index]{\ldots{}_rand} functions (such as
%   \cs{int_rand:nn} or \cs{clist_rand_item:n}) as well as other
%   packages relying on the engine's random number generator.  In
%   engines without random number support this produces an error.
%   \begin{texnote}
%     While a $32$-bit (signed) integer can be given as a seed, only the
%     absolute value is used and any number beyond $2^{28}$ is divided
%     by an appropriate power of~$2$.  We recommend using an integer in
%     $[0,2^{28}-1]$.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2018-07-27, EXP, pTF]
%   {
%     \sys_if_platform_unix:,
%     \sys_if_platform_windows:
%   }
%   \begin{syntax}
%     \cs{sys_if_platform_unix:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Conditionals which allow platform-specific code to be used. The names
%   follow the \Lua{} |os.type()| function, \emph{i.e.}~all Unix-like systems
%   are |unix| (including Linux and MacOS).
% \end{function}
%
% \begin{variable}[added = 2018-07-27]{\c_sys_platform_str}
%   The current platform given as a lower case string: one of
%   |unix|, |windows| or |unknown|.
% \end{variable}
%
% \begin{variable}[added = 2017-05-27]{\c_sys_shell_escape_int}
%   This variable exposes the internal triple of the shell escape
%   status.  The possible values are
%   \begin{description}
%   \item[0] Shell escape is disabled
%   \item[1] Unrestricted shell escape is enabled
%   \item[2] Restricted shell escape is enabled
%   \end{description}
% \end{variable}
%
% \begin{function}[added = 2017-05-27, EXP, pTF]{\sys_if_shell:}
%   \begin{syntax}
%     \cs{sys_if_shell_p:}
%     \cs{sys_if_shell:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Performs a check for whether shell escape is enabled.  This
%   returns true if either of restricted or unrestricted shell escape
%   is enabled.
% \end{function}
%
% \begin{function}[added = 2017-05-27, EXP, pTF]{\sys_if_shell_unrestricted:}
%   \begin{syntax}
%     \cs{sys_if_shell_unrestricted_p:}
%     \cs{sys_if_shell_unrestricted:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Performs a check for whether \emph{unrestricted} shell escape is
%   enabled.
% \end{function}
%
% \begin{function}[added = 2017-05-27, EXP, pTF]{\sys_if_shell_restricted:}
%   \begin{syntax}
%     \cs{sys_if_shell_restricted_p:}
%     \cs{sys_if_shell_restricted:TF} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Performs a check for whether \emph{restricted} shell escape is
%   enabled.  This returns false if unrestricted shell escape is
%   enabled.  Unrestricted shell escape is not considered a superset
%   of restricted shell escape in this case.  To find whether any
%   shell escape is enabled use \cs{sys_if_shell:}.
% \end{function}
%
% \begin{function}[added = 2017-05-27]{\sys_shell_now:n, \sys_shell_now:x}
%   \begin{syntax}
%     \cs{sys_shell_now:n} \Arg{tokens}
%   \end{syntax}
%   Execute \meta{tokens} through shell escape immediately.
% \end{function}
%
% \begin{function}[added = 2017-05-27]{\sys_shell_shipout:n, \sys_shell_shipout:x}
%   \begin{syntax}
%     \cs{sys_shell_shipout:n} \Arg{tokens}
%   \end{syntax}
%   Execute \meta{tokens} through shell escape at shipout.
% \end{function}
%
% \section{Additions to \pkg{l3tl}}
%
% \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
%   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 is 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 matches 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}
% produces
% \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 does 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}
%   becomes
%   \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 expands 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}[EXP, added = 2017-07-15]
%   {
%     \tl_range_braced:Nnn, \tl_range_braced:cnn, \tl_range_braced:nnn,
%     \tl_range_unbraced:Nnn, \tl_range_unbraced:cnn, \tl_range_unbraced:nnn
%   }
%   \begin{syntax}
%     \cs{tl_range_braced:Nnn} \meta{tl~var} \Arg{start index} \Arg{end index}
%     \cs{tl_range_braced:nnn} \Arg{token list} \Arg{start index} \Arg{end index}
%     \cs{tl_range_unbraced:Nnn} \meta{tl~var} \Arg{start index} \Arg{end index}
%     \cs{tl_range_unbraced:nnn} \Arg{token list} \Arg{start index} \Arg{end index}
%   \end{syntax}
%   Leaves in the input stream the items from the \meta{start index} to
%   the \meta{end index} inclusive, using the same indexing as
%   \cs{tl_range:nnn}.  Spaces are ignored.  Regardless of whether items
%   appear with or without braces in the \meta{token list}, the
%   \cs{tl_range_braced:nnn} function wraps each item in braces, while
%   \cs{tl_range_unbraced:nnn} does not (overall it removes an outer set
%   of braces).  For instance,
%   \begin{verbatim}
%     \iow_term:x { \tl_range_braced:nnn { abcd~{e{}}f } { 2 } { 5 } }
%     \iow_term:x { \tl_range_braced:nnn { abcd~{e{}}f } { -4 } { -1 } }
%     \iow_term:x { \tl_range_braced:nnn { abcd~{e{}}f } { -2 } { -1 } }
%     \iow_term:x { \tl_range_braced:nnn { abcd~{e{}}f } { 0 } { -1 } }
%   \end{verbatim}
%   prints \verb*|{b}{c}{d}{e{}}|, \verb*|{c}{d}{e{}}{f}|, \verb*|{e{}}{f}|, and an empty
%   line to the terminal, while
%   \begin{verbatim}
%     \iow_term:x { \tl_range_unbraced:nnn { abcd~{e{}}f } { 2 } { 5 } }
%     \iow_term:x { \tl_range_unbraced:nnn { abcd~{e{}}f } { -4 } { -1 } }
%     \iow_term:x { \tl_range_unbraced:nnn { abcd~{e{}}f } { -2 } { -1 } }
%     \iow_term:x { \tl_range_unbraced:nnn { abcd~{e{}}f } { 0 } { -1 } }
%   \end{verbatim}
%   prints \verb*|bcde{}|, \verb*|cde{}f|, \verb*|e{}f|, and an empty
%   line to the terminal.  Because braces are removed, the result of
%   \cs{tl_range_unbraced:nnn} may have a different number of items as
%   for \cs{tl_range:nnn} or \cs{tl_range_braced:nnn}.  In cases where
%   preserving spaces is important, consider the slower function
%   \cs{tl_range:nnn}.
%   \begin{texnote}
%     The result is returned within the \tn{unexpanded}
%     primitive (\cs{exp_not:n}), which means that the \meta{item}
%     does not expand further when appearing in an \texttt{x}-type
%     argument expansion.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2018-04-01]{\tl_build_begin:N, \tl_build_gbegin:N}
%   \begin{syntax}
%     \cs{tl_build_begin:N} \meta{tl~var}
%   \end{syntax}
%   Clears the \meta{tl~var} and sets it up to support other
%   \cs[no-index]{tl_build_\ldots{}} functions, which allow accumulating
%   large numbers of tokens piece by piece much more efficiently than
%   standard \pkg{l3tl} functions.  Until \cs{tl_build_end:N}
%   \meta{tl~var} is called, applying any function from \pkg{l3tl} other
%   than \cs[no-index]{tl_build_\ldots{}} will lead to incorrect
%   results.  The |begin| and |gbegin| functions must be used for local
%   and global \meta{tl~var} respectively.
% \end{function}
%
% \begin{function}[added = 2018-04-01]{\tl_build_clear:N, \tl_build_gclear:N}
%   \begin{syntax}
%     \cs{tl_build_clear:N} \meta{tl~var}
%   \end{syntax}
%   Clears the \meta{tl~var} and sets it up to support other
%   \cs[no-index]{tl_build_\ldots{}} functions.  The |clear| and
%   |gclear| functions must be used for local and global \meta{tl~var}
%   respectively.
% \end{function}
%
% \begin{function}[added = 2018-04-01]
%   {
%     \tl_build_put_left:Nn, \tl_build_put_left:Nx,
%     \tl_build_gput_left:Nn, \tl_build_gput_left:Nx,
%     \tl_build_put_right:Nn, \tl_build_put_right:Nx,
%     \tl_build_gput_right:Nn, \tl_build_gput_right:Nx,
%   }
%   \begin{syntax}
%     \cs{tl_build_put_left:Nn} \meta{tl~var} \Arg{tokens}
%     \cs{tl_build_put_right:Nn} \meta{tl~var} \Arg{tokens}
%   \end{syntax}
%   Adds \meta{tokens} to the left or right side of the current contents
%   of \meta{tl~var}.  The \meta{tl~var} must have been set up with
%   \cs{tl_build_begin:N} or \cs{tl_build_gbegin:N}.  The |put| and
%   |gput| functions must be used for local and global \meta{tl~var}
%   respectively.  The |right| functions are about twice faster than the
%   |left| functions.
% \end{function}
%
% \begin{function}[added = 2018-04-01]{\tl_build_get:NN}
%   \begin{syntax}
%     \cs{tl_build_get:N} \meta{tl~var_1} \meta{tl~var_2}
%   \end{syntax}
%   Stores the contents of the \meta{tl~var_1} in the \meta{tl~var_2}.
%   The \meta{tl~var_1} must have been set up with \cs{tl_build_begin:N}
%   or \cs{tl_build_gbegin:N}.  The \meta{tl~var_2} is a
%   \enquote{normal} token list variable, assigned locally using
%   \cs{tl_set:Nn}.
% \end{function}
%
% \begin{function}[added = 2018-04-01]{\tl_build_end:N, \tl_build_gend:N}
%   \begin{syntax}
%     \cs{tl_build_end:N} \meta{tl~var}
%   \end{syntax}
%   Gets the contents of \meta{tl~var} and stores that into the
%   \meta{tl~var} using \cs{tl_set:Nn}.  The \meta{tl~var} must have
%   been set up with \cs{tl_build_begin:N} or \cs{tl_build_gbegin:N}.
%   The |end| and |gend| functions must be used for local and global
%   \meta{tl~var} respectively.  These functions completely remove the
%   setup code that enabled \meta{tl~var} to be used for other
%   \cs[no-index]{tl_build_\ldots{}} functions.
% \end{function}
%
% \section{Additions to \pkg{l3token}}
%
% \begin{variable}[added = 2017-08-07]{\c_catcode_active_space_tl}
%   Token list containing one character with category code $13$,
%   (\enquote{active}), and character code $32$ (space).
% \end{variable}
%
% \begin{function}[added = 2018-04-06, updated = 2019-05-03, EXP]
%   {
%     \char_lower_case:N, \char_upper_case:N,
%     \char_mixed_case:N, \char_fold_case:N,
%     \char_str_lower_case:N, \char_str_upper_case:N,
%     \char_str_mixed_case:N, \char_str_fold_case:N,
%   }
%   \begin{syntax}
%     \cs{char_lower_case:N} \meta{char}
%   \end{syntax}
%   Converts the \meta{char} to the equivalent case-changed character
%   as detailed by the function name (see \cs{str_fold_case:n}
%   and \cs{tl_mixed_case:n} for details of these terms). The case mapping
%   is carried out with no context-dependence (\emph{cf.}~\cs{tl_upper_case:n},
%   \emph{etc.}) The \texttt{str} versions always generate \enquote{other}
%   (category code $12$) characters, whilst the standard versions generate
%   characters with the currently-active category code (\emph{i.e.}~as if
%   the character had been read directly here).
% \end{function}
%
% \begin{function}[added = 2018-06-01, EXP]{\char_codepoint_to_bytes:n}
%   \begin{syntax}
%     \cs{char_codepoint_to_bytes:n} \Arg{codepoint}
%   \end{syntax}
%   Converts the (Unicode) \meta{codepoint} to UTF-8 bytes. The expansion
%   of this function comprises four brace groups, each of which will contain
%   a hexadecimal value: the appropriate byte. As UTF-8 is a variable-length,
%   one or more of the grouos may be empty: the bytes read in the logical order,
%   such that a two-byte codepoint will have groups |#1| and |#2| filled
%   and |#3| and |#4| empty.
% \end{function}
%
% \begin{function}[added = 2018-09-23]
%   {
%     \peek_catcode_collect_inline:Nn,
%     \peek_charcode_collect_inline:Nn,
%     \peek_meaning_collect_inline:Nn
%   }
%   \begin{syntax}
%     \cs{peek_catcode_collect_inline:Nn} \meta{test token} \Arg{inline code}
%     \cs{peek_charcode_collect_inline:Nn} \meta{test token} \Arg{inline code}
%     \cs{peek_meaning_collect_inline:Nn} \meta{test token} \Arg{inline code}
%   \end{syntax}
%   Collects and removes tokens from the input stream until finding a
%   token that does not match the \meta{test token} (as defined by the
%   test \cs{token_if_eq_catcode:NNTF} or \cs{token_if_eq_charcode:NNTF}
%   or \cs{token_if_eq_meaning:NNTF}).  The collected tokens are passed
%   to the \meta{inline code} as~|#1|.  When begin-group or end-group
%   tokens (usually |{| or~|}|) are collected they are replaced by
%   implicit \cs{c_group_begin_token} and \cs{c_group_end_token}, and
%   when spaces (including \cs{c_space_token}) are collected they are
%   replaced by explicit spaces.
%
%   For example the following code prints ``Hello'' to the terminal and
%   leave ``, world!'' in the input stream.
% \begin{verbatim}
% \peek_catcode_collect_inline:Nn A { \iow_term:n {#1} } Hello,~world!
% \end{verbatim}
%   Another example is that the following code tests if the next token is |*|, ignoring intervening spaces, but putting them back using |#1| if there is no~|*|.
% \begin{verbatim}
% \peek_meaning_collect_inline:Nn \c_space_token
%   { \peek_charcode:NTF * { star } { no~star #1 } }
% \end{verbatim}
% \end{function}
%
% \begin{function}[added = 2018-10-01]{\peek_remove_spaces:n}
%   \begin{syntax}
%     \cs{peek_remove_spaces:n} \Arg{code}
%   \end{syntax}
%   Removes explicit and implicit space tokens (category code~$10$ and
%   character code~$32$) from the input stream, then inserts \meta{code}.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3candidates} Implementation}
%
%    \begin{macrocode}
%<*initex|package>
%    \end{macrocode}
%
% \subsection{Additions to \pkg{l3basics}}
%
% \begin{macro}{\mode_leave_vertical:}
%   The approach here is different to that used by \LaTeXe{} or plain \TeX{},
%   which unbox a void box to force horizontal mode. That inserts the
%   \tn{everypar} tokens \emph{before} the re-inserted unboxing tokens. The
%   approach here uses either the \tn{quitvmode} primitive or the equivalent
%   protected macro. In vertical mode, the \tn{indent} primitive is inserted:
%   this will switch to horizontal mode and insert \tn{everypar} tokens and
%   nothing else. Unlike the \LaTeXe{} version, the availability of \eTeX{}
%   means using a mode test can be done at for example the start of an
%   \tn{halign}.
%    \begin{macrocode}
\cs_new_protected:Npn \mode_leave_vertical:
  {
    \if_mode_vertical:
      \exp_after:wN \tex_indent:D
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3box}}
%
%    \begin{macrocode}
%<@@=box>
%    \end{macrocode}
%
% \subsubsection{Viewing part of a box}
%
% \begin{macro}{\box_clip:N, \box_clip:c, \box_gclip:N, \box_gclip:c}
%   A wrapper around the driver-dependent code.
%    \begin{macrocode}
\cs_new_protected:Npn \box_clip:N #1
  { \hbox_set:Nn #1 { \@@_backend_clip:N #1 } }
\cs_generate_variant:Nn \box_clip:N { c }
\cs_new_protected:Npn \box_gclip:N #1
  { \hbox_gset:Nn #1 { \@@_backend_clip:N #1 } }
\cs_generate_variant:Nn \box_gclip:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_set_trim:Nnnnn, \box_set_trim:cnnnn,
%     \box_gset_trim:Nnnnn, \box_gset_trim:cnnnn
%   }
% \begin{macro}{\@@_set_trim:NnnnnN}
%   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_set_trim:Nnnnn #1#2#3#4#5
  { \@@_set_trim:NnnnnN #1 {#2} {#3} {#4} {#5} \box_set_eq:NN }
\cs_generate_variant:Nn \box_set_trim:Nnnnn { c }
\cs_new_protected:Npn \box_gset_trim:Nnnnn #1#2#3#4#5
  { \@@_set_trim:NnnnnN #1 {#2} {#3} {#4} {#5} \box_gset_eq:NN }
\cs_generate_variant:Nn \box_gset_trim:Nnnnn { c }
\cs_new_protected:Npn \@@_set_trim:NnnnnN #1#2#3#4#5#6
  {
    \hbox_set:Nn \l_@@_internal_box
      {
        \tex_kern:D - \@@_dim_eval:n {#2}
        \box_use:N #1
        \tex_kern:D - \@@_dim_eval:n {#4}
      }
%    \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_drop: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_drop: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_drop: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_drop:N \l_@@_internal_box }
          }
        \box_set_ht:Nn \l_@@_internal_box \c_zero_dim
      }
    #6 #1 \l_@@_internal_box
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_set_viewport:Nnnnn, \box_set_viewport:cnnnn,
%     \box_gset_viewport:Nnnnn, \box_gset_viewport:cnnnn
%   }
% \begin{macro}{\@@_viewport:NnnnnN}
%   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_set_viewport:Nnnnn #1#2#3#4#5
  { \@@_set_viewport:NnnnnN #1 {#2} {#3} {#4} {#5} \box_set_eq:NN }
\cs_generate_variant:Nn \box_set_viewport:Nnnnn { c }
\cs_new_protected:Npn \box_gset_viewport:Nnnnn #1#2#3#4#5
  { \@@_set_viewport:NnnnnN #1 {#2} {#3} {#4} {#5} \box_gset_eq:NN }
\cs_generate_variant:Nn \box_gset_viewport:Nnnnn { c }
\cs_new_protected:Npn \@@_set_viewport:NnnnnN #1#2#3#4#5#6
  {
    \hbox_set:Nn \l_@@_internal_box
      {
        \tex_kern:D - \@@_dim_eval:n {#2}
        \box_use:N #1
        \tex_kern:D \@@_dim_eval:n { #4 - \box_wd:N #1 }
      }
    \dim_compare:nNnTF {#3} < \c_zero_dim
      {
        \hbox_set:Nn \l_@@_internal_box
          {
            \box_move_down:nn \c_zero_dim
              { \box_use_drop: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_drop: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_drop: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_drop:N \l_@@_internal_box }
          }
        \box_set_ht:Nn \l_@@_internal_box \c_zero_dim
      }
    #6 #1 \l_@@_internal_box
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Additions to \pkg{l3fp-convert}}
%
%    \begin{macrocode}
%<@@=fp>
%    \end{macrocode}
%
% \begin{macro}{\fp_sign:n}
%   Trivial but useful.  See the implementation of \cs{fp_add:Nn} for an
%   explanation of why to use \cs{@@_parse:n}, namely, for better error
%   reporting.
%    \begin{macrocode}
\cs_new:Npn \fp_sign:n #1
  { \fp_to_decimal:n { sign \@@_parse:n {#1} } }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3flag}}
%
%    \begin{macrocode}
%<@@=flag>
%    \end{macrocode}
%
% \begin{macro}[EXP]{\flag_raise_if_clear:n}
%   It might be faster to just call the \enquote{trap} function in all
%   cases but conceptually the function name suggests we should only run
%   it if the flag is zero in case the \enquote{trap} made customizable
%   in the future.
%    \begin{macrocode}
\__kernel_patch:nnNNpn { \@@_chk_exist:n {#1} } { }
\cs_new:Npn \flag_raise_if_clear:n #1
  {
    \if_cs_exist:w flag~#1~0 \cs_end:
    \else:
      \cs:w flag~#1 \cs_end: 0 ;
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3int}}
%
%    \begin{macrocode}
%<@@=int>
%    \end{macrocode}
%
% \begin{macro}[EXP]{\int_sign:n, \@@_sign:Nw}
%   See \cs{int_abs:n}.  Evaluate the expression once (and when
%   debugging is enabled, check that the expression is well-formed),
%   then test the first character to determine the sign.  This is
%   wrapped in \cs{int_value:w} \ldots{} \cs{exp_stop_f:} to ensure a
%   fixed number of expansions and to avoid dealing with closing the
%   conditionals.
%    \begin{macrocode}
\__kernel_patch_args:nNNpn
  { { \__kernel_chk_expr:nNnN {#1} \@@_eval:w { } \int_sign:n } }
\cs_new:Npn \int_sign:n #1
  {
    \int_value:w \exp_after:wN \@@_sign:Nw
      \int_value:w \@@_eval:w #1 \@@_eval_end: ;
    \exp_stop_f:
  }
\cs_new:Npn \@@_sign:Nw #1#2 ;
  {
    \if_meaning:w 0 #1
      0
    \else:
      \if_meaning:w - #1 - \fi: 1
    \fi:
  }
%    \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}{\@@_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:Ne \@@_expandable_error_module:nn
      {
        \exp_args:Nc \exp_args:Noooo
          { \c_@@_text_prefix_tl #1 / #2 }
          { \tl_to_str:n {#3} }
          { \tl_to_str:n {#4} }
          { \tl_to_str:n {#5} }
          { \tl_to_str:n {#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}
%
% \begin{macro}{\msg_show_eval:Nn, \msg_log_eval:Nn, \@@_show_eval:nnN}
%   A short-hand used for \cs{int_show:n} and similar functions that
%   passes to \cs{tl_show:n} the result of applying |#1| (a
%   function such as \cs{int_eval:n}) to the expression |#2|.  The use of
%   \texttt{f}-expansion ensures that |#1| is expanded in the scope in which the
%   show command is called, rather than in the group created by
%   \cs{iow_wrap:nnnN}.  This is only important for expressions
%   involving the \tn{currentgrouplevel} or \tn{currentgrouptype}.
%   On the other hand we want the expression to be converted to a string
%   with the usual escape character, hence within the wrapping code.
%    \begin{macrocode}
\cs_new_protected:Npn \msg_show_eval:Nn #1#2
  { \exp_args:Nf \@@_show_eval:nnN { #1 {#2} } {#2} \tl_show:n }
\cs_new_protected:Npn \msg_log_eval:Nn #1#2
  { \exp_args:Nf \@@_show_eval:nnN { #1 {#2} } {#2} \tl_log:n }
\cs_new_protected:Npn \@@_show_eval:nnN #1#2#3 { #3 { #2 = #1 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\msg_show_item:n}
% \begin{macro}[EXP]{\msg_show_item_unbraced:n}
% \begin{macro}[EXP]{\msg_show_item:nn}
% \begin{macro}[EXP]{\msg_show_item_unbraced:nn}
%   Each item in the variable is formatted using one of the following
%   functions.  We cannot use |\\| and so on because these short-hands
%   cannot be used inside the arguments of messages, only when defining
%   the messages.
%    \begin{macrocode}
\cs_new:Npx \msg_show_item:n #1
  { \iow_newline: > ~ \c_space_tl \exp_not:N \tl_to_str:n { {#1} } }
\cs_new:Npx \msg_show_item_unbraced:n #1
  { \iow_newline: > ~ \c_space_tl \exp_not:N \tl_to_str:n {#1} }
\cs_new:Npx \msg_show_item:nn #1#2
  {
    \iow_newline: > \use:nn { ~ } { ~ }
    \exp_not:N \tl_to_str:n { {#1} }
    \use:nn { ~ } { ~ } => \use:nn { ~ } { ~ }
    \exp_not:N \tl_to_str:n { {#2} }
  }
\cs_new:Npx \msg_show_item_unbraced:nn #1#2
  {
    \iow_newline: > \use:nn { ~ } { ~ }
    \exp_not:N \tl_to_str:n {#1}
    \use:nn { ~ } { ~ } => \use:nn { ~ } { ~ }
    \exp_not:N \tl_to_str:n {#2}
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Additions to \pkg{l3prg}}
%
% \begin{macro}[added = 2017-11-28]{\bool_const:Nn, \bool_const:cn}
%   A merger between \cs{tl_const:Nn} and \cs{bool_set:Nn}.
%    \begin{macrocode}
\__kernel_patch:nnNNpn { \__kernel_chk_var_scope:NN c #1 } { }
\cs_new_protected:Npn \bool_const:Nn #1#2
  {
    \__kernel_chk_if_free_cs:N #1
    \tex_global:D \tex_chardef:D #1 = \bool_if_p:n {#2}
  }
\cs_generate_variant:Nn \bool_const:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[added = 2018-05-10]
%   {\bool_set_inverse:N, \bool_set_inverse:c, \bool_gset_inverse:N, \bool_gset_inverse:c}
%   Set to \texttt{false} or \texttt{true} locally or globally.
%    \begin{macrocode}
\cs_new_protected:Npn \bool_set_inverse:N #1
  { \bool_if:NTF #1 { \bool_set_false:N } { \bool_set_true:N } #1 }
\cs_generate_variant:Nn \bool_set_inverse:N { c }
\cs_new_protected:Npn \bool_gset_inverse:N #1
  { \bool_if:NTF #1 { \bool_gset_false:N } { \bool_gset_true:N } #1 }
\cs_generate_variant:Nn \bool_gset_inverse:N { c }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3prop}}
%
%    \begin{macrocode}
%<@@=prop>
%    \end{macrocode}
%
% \begin{macro}[EXP]
%   {\prop_rand_key_value:N, \prop_rand_key_value:c}
% \begin{macro}[EXP]{\@@_rand_item:w}
%   Contrarily to |clist|, |seq| and |tl|, there is no function to get
%   an item of a |prop| given an integer between $1$ and the number of
%   items, so we write the appropriate code.  There is no bounds
%   checking because \cs{int_rand:nn} is always within bounds.  The
%   initial \cs{int_value:w} is stopped by the first \cs{s_@@} in~|#1|.
%    \begin{macrocode}
\cs_new:Npn \prop_rand_key_value:N #1
  {
    \prop_if_empty:NF #1
      {
        \exp_after:wN \@@_rand_item:w
        \int_value:w \int_rand:nn { 1 } { \prop_count:N #1 }
        #1 \q_stop
      }
  }
\cs_generate_variant:Nn \prop_rand_key_value:N { c }
\cs_new:Npn \@@_rand_item:w #1 \s_@@ \@@_pair:wn #2 \s_@@ #3
  {
    \int_compare:nNnF {#1} > 1
      { \use_i_delimit_by_q_stop:nw { \exp_not:n { {#2} {#3} } } }
    \exp_after:wN \@@_rand_item:w
    \int_value:w \int_eval:n { #1 - 1 } \s_@@
  }
%    \end{macrocode}
% \end{macro}
% \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}
%   {
%     \@@_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 both sequences are \cs{s_@@}
%   \cs{@@_item:n}.  The function to be mapped are then be applied to
%   the two entries.  When the code hits the end of one of the
%   sequences, the break material stops 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 , c , cc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_set_filter:NNn, \seq_gset_filter:NNn}
% \begin{macro}{\@@_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}{\@@_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_set_from_inline_x:Nnn, \seq_gset_from_inline_x:Nnn}
% \begin{macro}{\@@_set_from_inline_x:NNnn}
%   Set \cs{@@_item:n} then map it using the loop code.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_from_inline_x:Nnn
  { \@@_set_from_inline_x:NNnn \tl_set:Nx }
\cs_new_protected:Npn \seq_gset_from_inline_x:Nnn
  { \@@_set_from_inline_x:NNnn \tl_gset:Nx }
\cs_new_protected:Npn \@@_set_from_inline_x:NNnn #1#2#3#4
  {
    \@@_push_item_def:n { \exp_not:N \@@_item:n {#4} }
    #1 #2 { \s_@@ #3 \@@_item:n }
    \@@_pop_item_def:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\seq_set_from_function:NnN, \seq_gset_from_function:NnN}
%   Reuse \cs{seq_set_from_inline_x:Nnn}.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_set_from_function:NnN #1#2#3
  { \seq_set_from_inline_x:Nnn #1 {#2} { #3 {##1} } }
\cs_new_protected:Npn \seq_gset_from_function:NnN #1#2#3
  { \seq_gset_from_inline_x:Nnn #1 {#2} { #3 {##1} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\seq_const_from_clist:Nn, \seq_const_from_clist:cn}
%   Almost identical to \cs{seq_set_from_clist:Nn}.
%    \begin{macrocode}
\cs_new_protected:Npn \seq_const_from_clist:Nn #1#2
  {
    \tl_const:Nx #1
      { \s_@@ \clist_map_function:nN {#2} \@@_wrap_item:n }
  }
\cs_generate_variant:Nn \seq_const_from_clist:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\seq_shuffle:N, \seq_gshuffle:N, \@@_shuffle:NN, \@@_shuffle_item:n}
% \begin{variable}{\g_@@_internal_seq, \l_@@_internal_a_int, \l_@@_internal_b_int}
%   We apply the Fisher–Yates shuffle, storing items in \tn{toks}
%   registers.  We use the primitive \cs{tex_uniformdeviate:D} for
%   speed reasons.  Its non-uniformity is of order its argument divided
%   by $2^{28}$, not too bad for small lists.  For sequences with more
%   than $13$ elements there are more possible permutations than
%   possible seeds ($13!>2^{28}$) so the question of uniformity is
%   somewhat moot.
%    \begin{macrocode}
\cs_if_exist:NTF \tex_uniformdeviate:D
  {
    \int_new:N \l_@@_internal_a_int
    \int_new:N \l_@@_internal_b_int
    \seq_new:N \g_@@_internal_seq
    \cs_new_protected:Npn \seq_shuffle:N { \@@_shuffle:NN \seq_set_eq:NN }
    \cs_new_protected:Npn \seq_gshuffle:N { \@@_shuffle:NN \seq_gset_eq:NN }
    \cs_new_protected:Npn \@@_shuffle:NN #1#2
      {
        \int_compare:nNnTF { \seq_count:N #2 } > \c_max_register_int
          {
            \__kernel_msg_error:nnx { kernel } { shuffle-too-large }
              { \token_to_str:N #2 }
          }
          {
            \group_begin:
              \cs_set_eq:NN \@@_item:n \@@_shuffle_item:n
              \int_zero:N \l_@@_internal_a_int
              #2
              \seq_gset_from_inline_x:Nnn \g_@@_internal_seq
                { \int_step_function:nN { \l_@@_internal_a_int } }
                { \tex_the:D \tex_toks:D ##1 }
            \group_end:
            #1 #2 \g_@@_internal_seq
            \seq_gclear:N \g_@@_internal_seq
          }
      }
    \cs_new_protected:Npn \@@_shuffle_item:n
      {
        \int_incr:N \l_@@_internal_a_int
        \int_set:Nn \l_@@_internal_b_int
          { 1 + \tex_uniformdeviate:D \l_@@_internal_a_int }
        \tex_toks:D \l_@@_internal_a_int
          = \tex_toks:D \l_@@_internal_b_int
        \tex_toks:D \l_@@_internal_b_int
      }
    \__kernel_msg_new:nnnn { kernel } { shuffle-too-large }
      { The~sequence~#1~is~too~long~to~be~shuffled~by~TeX. }
      {
        TeX~has~ \int_eval:n { \c_max_register_int + 1 } ~
        toks~registers:~this~only~allows~to~shuffle~up~to~
        \int_use:N \c_max_register_int \ items.~
        The~list~will~not~be~shuffled.
      }
  }
  {
    \cs_new_protected:Npn \seq_shuffle:N #1
      {
        \__kernel_msg_error:nnn { kernel } { fp-no-random }
          { \seq_shuffle:N #1 }
      }
    \cs_new_eq:NN \seq_gshuffle:N \seq_shuffle:N
  }
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
% \begin{macro}
%   {
%     \seq_indexed_map_function:NN, \seq_indexed_map_inline:Nn,
%     \@@_indexed_map:nNN, \@@_indexed_map:Nw
%   }
%   Similar to \cs{seq_map_function:NN} but we keep track of the item
%   index as a |;|-delimited argument of \cs{@@_indexed_map:Nw}.
%    \begin{macrocode}
\cs_new:Npn \seq_indexed_map_function:NN #1#2
  {
    \@@_indexed_map:NN #1#2
    \prg_break_point:Nn \seq_map_break: { }
  }
\cs_new_protected:Npn \seq_indexed_map_inline:Nn #1#2
  {
    \int_gincr:N \g__kernel_prg_map_int
    \cs_gset_protected:cpn
      { @@_map_ \int_use:N \g__kernel_prg_map_int :w } ##1##2 {#2}
    \exp_args:NNc \@@_indexed_map:NN #1
      { @@_map_ \int_use:N \g__kernel_prg_map_int :w }
    \prg_break_point:Nn \seq_map_break:
      { \int_gdecr:N \g__kernel_prg_map_int }
  }
\cs_new:Npn \@@_indexed_map:NN #1#2
  {
    \exp_after:wN \@@_indexed_map:Nw
    \exp_after:wN #2
    \int_value:w 1
    \exp_after:wN \use_i:nn
    \exp_after:wN ;
    #1
    \prg_break: \@@_item:n { } \prg_break_point:
  }
\cs_new:Npn \@@_indexed_map:Nw #1#2 ; #3 \@@_item:n #4
  {
    #3
    #1 {#2} {#4}
    \exp_after:wN \@@_indexed_map:Nw
    \exp_after:wN #1
    \int_value:w \int_eval:w 1 + #2 ;
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3skip}}
%
%    \begin{macrocode}
%<@@=dim>
%    \end{macrocode}
%
% \begin{macro}[EXP]{\dim_sign:n, \@@_sign:Nw}
%   See \cs{dim_abs:n}.  Contrarily to \cs{int_sign:n} the case of a
%   zero dimension cannot be distinguished from a positive dimension by
%   looking only at the first character, since |0.2pt| and |0pt| start
%   the same way.  We need explicit comparisons.  We start by
%   distinguishing the most common case of a positive dimension.
%    \begin{macrocode}
\__kernel_patch_args:nNNpn
  { { \__kernel_chk_expr:nNnN {#1} \@@_eval:w { } \dim_sign:n } }
\cs_new:Npn \dim_sign:n #1
  {
    \int_value:w \exp_after:wN \@@_sign:Nw
      \dim_use:N \@@_eval:w #1 \@@_eval_end: ;
    \exp_stop_f:
  }
\cs_new:Npn \@@_sign:Nw #1#2 ;
  {
    \if_dim:w #1#2 > \c_zero_dim
      1
    \else:
      \if_meaning:w - #1
        -1
      \else:
        0
      \fi:
    \fi:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3sys}}
%
%    \begin{macrocode}
%<@@=sys>
%    \end{macrocode}
%
% \begin{variable}{\c_sys_engine_version_str}
%   Various different engines, various different ways to extract the
%   data!
%    \begin{macrocode}
\str_const:Nx \c_sys_engine_version_str
  {
    \str_case:on \c_sys_engine_str
      {
        { pdftex }
          {
            \fp_eval:n { round(\int_use:N \tex_pdftexversion:D / 100 , 2) }
            .
            \tex_pdftexrevision:D
          }
        { ptex }
          {
            \cs_if_exist:NT \tex_ptexversion:D
              {
                p
                \int_use:N  \tex_ptexversion:D
                \int_use:N \tex_ptexminorversion:D
                \tex_ptexrevision:D
                -
                \int_use:N \tex_epTeXversion:D
              }
          }
        { luatex }
          {
            \fp_eval:n { round(\int_use:N \tex_luatexversion:D / 100, 2) }
            .
            \tex_luatexrevision:D
          }
        { uptex }
          {
            \cs_if_exist:NT \tex_ptexversion:D
              {
                p
                \int_use:N  \tex_ptexversion:D
                \int_use:N \tex_ptexminorversion:D
                \tex_ptexrevision:D
                -
                u
                \int_use:N  \tex_uptexversion:D
                \tex_uptexrevision:D
                -
                \int_use:N \tex_epTeXversion:D
              }
          }
        { xetex }
          {
            \int_use:N \tex_XeTeXversion:D
            \tex_XeTeXrevision:D
          }
      }
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[EXP]{\sys_rand_seed:}
%   Unpack the primitive.  When random numbers are not available, we
%   return zero after an error (and incidentally make sure the number of
%   expansions needed is the same as with random numbers available).
%    \begin{macrocode}
\sys_if_rand_exist:TF
  { \cs_new:Npn \sys_rand_seed: { \tex_the:D \tex_randomseed:D } }
  {
    \cs_new:Npn \sys_rand_seed:
      {
        \int_value:w
        \__kernel_msg_expandable_error:nnn { kernel } { fp-no-random }
          { \sys_rand_seed: }
        \c_zero_int
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\sys_gset_rand_seed:n}
%   The primitive always assigns the seed globally.
%    \begin{macrocode}
\sys_if_rand_exist:TF
  {
    \cs_new_protected:Npn \sys_gset_rand_seed:n #1
      { \tex_setrandomseed:D \int_eval:n {#1} \exp_stop_f: }
  }
  {
    \cs_new_protected:Npn \sys_gset_rand_seed:n #1
      {
        \__kernel_msg_error:nnn { kernel } { fp-no-random }
          { \sys_gset_rand_seed:n {#1} }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\c_sys_shell_escape_int}
%   Expose the engine's shell escape status to the user.
%    \begin{macrocode}
\int_const:Nn \c_sys_shell_escape_int
  {
    \sys_if_engine_luatex:TF
      {
        \tex_directlua:D
          { tex.sprint(status.shell_escape~or~os.execute()) }
      }
      {
        \tex_shellescape:D
      }
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_internal_tl}
%    \begin{macrocode}
\tl_new:N \l_@@_internal_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\c_@@_marker_tl}
%   The same idea as the marker for rescanning token lists.
%    \begin{macrocode}
\tl_const:Nx \c_@@_marker_tl { : \token_to_str:N : }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[TF]{\sys_shell_get:nnN}
% \begin{macro}{\sys_shell_get:nnN,\@@_get:nnN,\@@_get_do:Nw}
%   Setting using a shell is at this level just a slightly specialised file
%   operation, with an additional check for quotes, as these are not supported.
%    \begin{macrocode}
\cs_new_protected:Npn \sys_shell_get:nnN #1#2#3
  {
    \sys_shell_get:nnNF {#1} {#2} #3
      { \tl_set:Nn #3 { \q_no_value } }
  }
\prg_new_protected_conditional:Npnn \sys_shell_get:nnN #1#2#3 { T , F , TF }
  {
    \sys_if_shell:TF
      { \exp_args:No \@@_get:nnN { \tl_to_str:n {#1} } {#2} #3 }
      { \prg_return_false: }
  }
\cs_new_protected:Npn \@@_get:nnN #1#2#3
  {
    \tl_if_in:nnTF {#1} { " }
      {
        \__kernel_msg_error:nnx
          { kernel } { quote-in-shell } {#1}
        \prg_return_false:
      }
      {
        \group_begin:
          \if_false: { \fi:
          \int_set_eq:NN \tex_tracingnesting:D \c_zero_int
          \exp_args:No \tex_everyeof:D { \c_@@_marker_tl }
          #2 \scan_stop:
          \exp_after:wN \@@_get_do:Nw
          \exp_after:wN #3
          \exp_after:wN \prg_do_nothing:
            \tex_input:D | "#1" \scan_stop:
        \if_false: } \fi:
        \prg_return_true:
      }
  }
\exp_args:Nno \use:nn
  { \cs_new_protected:Npn \@@_get_do:Nw #1#2 }
  { \c_@@_marker_tl }
  {
    \group_end:
    \tl_set:No #1 {#2}
  }
\__kernel_msg_new:nnnn { kernel } { quote-in-shell }
  { Quotes~in~shell~command~'#1'. }
  { Shell~commands~cannot~contain~quotes~("). }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{variable}{\c_sys_platform_str}
%   Detecting the platform on \LuaTeX{} is easy: for other engines, we use
%   the fact that the two common cases have special null files. It is possible
%   to probe further (see package \pkg{platform}), but that requires shell
%   escape and seems unlikely to be useful.
%    \begin{macrocode}
\sys_if_engine_luatex:TF
  {
    \str_const:Nx \c_sys_platform_str
      { \lua_now:n { tex.print(os.type) } }
  }
  {
    \file_if_exist:nTF { nul: }
      {
        \file_if_exist:nF { /dev/null }
          { \str_const:Nn \c_sys_platform_str { windows } }
      }
      {
        \file_if_exist:nT { /dev/null }
          { \str_const:Nn \c_sys_platform_str { unix } }
      }
  }
\cs_if_exist:NF \c_sys_platform_str
  { \str_const:Nn \c_sys_platform_str { unknown }  }
%    \end{macrocode}
% \end{variable}
% \begin{macro}[pTF]{\sys_if_platform_unix:}
% \begin{macro}[pTF]{\sys_if_platform_windows:}
%   We can now set up the tests.
%    \begin{macrocode}
\clist_map_inline:nn { unix , windows }
  {
    \@@_const:nn { sys_if_platform_ #1 }
      { \str_if_eq_p:Vn \c_sys_platform_str { #1 } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP, pTF]{\sys_if_shell:, \sys_if_shell_unrestricted:, \sys_if_shell_restricted:}
%   Performs a check for whether shell escape is enabled.  The first set
%   of functions returns true if either of restricted or unrestricted
%   shell escape is enabled, while the other two sets of functions
%   return true in only one of these two cases.
%    \begin{macrocode}
\@@_const:nn { sys_if_shell }
  { \int_compare_p:nNn \c_sys_shell_escape_int > 0 }
\@@_const:nn { sys_if_shell_unrestricted }
  { \int_compare_p:nNn \c_sys_shell_escape_int = 1 }
\@@_const:nn { sys_if_shell_restricted }
  { \int_compare_p:nNn \c_sys_shell_escape_int = 2 }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\c_@@_shell_stream_int}
%   This is not needed for \LuaTeX{}: shell escape there isn't done using
%   a \TeX{} interface.
%    \begin{macrocode}
\sys_if_engine_luatex:F
  { \int_const:Nn \c_@@_shell_stream_int { 18 } }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\sys_shell_now:n}
%   Execute commands through shell escape immediately.
%    \begin{macrocode}
\sys_if_engine_luatex:TF
  {
    \cs_new_protected:Npn \sys_shell_now:n #1
      {
        \lua_now:e
          { os.execute(" \lua_escape:e { \tl_to_str:n {#1} } ") }
      }
  }
  {
    \cs_new_protected:Npn \sys_shell_now:n #1
      { \iow_now:Nn \c_@@_shell_stream_int {#1} }
  }
\cs_generate_variant:Nn \sys_shell_now:n { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\sys_shell_shipout:n}
%   Execute commands through shell escape at shipout.
%    \begin{macrocode}
\sys_if_engine_luatex:TF
  {
    \cs_new_protected:Npn \sys_shell_shipout:n #1
      {
        \lua_shipout_e:n
          { os.execute(" \lua_escape:e { \tl_to_str:n {#1} } ") }
      }
  }
  {
    \cs_new_protected:Npn \sys_shell_shipout:n #1
      { \iow_shipout:Nn \c_@@_shell_stream_int {#1} }
  }
\cs_generate_variant:Nn \sys_shell_shipout:n { x }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Additions to \pkg{l3file}}
%
%    \begin{macrocode}
%<@@=file>
%    \end{macrocode}
%
% \begin{macro}[EXP]{\@@_str_cmp:nn}
% \begin{macro}[EXP]{\@@_str_escape:n}
%   As we are doing a fixed-length \enquote{big} integer comparison, it
%   is easiest to use the low-level behavior  of string comparisons.
%    \begin{macrocode}
\cs_new:Npn \@@_str_cmp:nn #1#2 { \tex_strcmp:D {#1} {#2} }
\sys_if_engine_luatex:T
  {
    \cs_set:Npn \@@_str_cmp:nn #1#2
      {
        \lua_now:e
          {
            l3kernel.strcmp
              (
                " \@@_str_escape:n {#1}",
                " \@@_str_escape:n {#2}"
              )
          }
      }
   \cs_new:Npn \@@_str_escape:n #1
     {
       \lua_escape:e
         { \__kernel_tl_to_str:w \use:e { {#1} } }
     }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{variable}{\l_@@_first_tl, \l_@@_second_tl}
%    \begin{macrocode}
\tl_new:N \l_@@_first_tl
\tl_new:N \l_@@_second_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[TF]{\file_compare_timestamp:nNn}
% \begin{macro}[EXP]{\@@_timestamp:n}
%   Comparison of file date can be done by using the low-level nature of the
%   string comparison functions. This could be expandable but that would
%   skip any file look-up: to stay consistent we retain that at the cost of
%   expansion.
%    \begin{macrocode}
\prg_new_protected_conditional:Npnn \file_compare_timestamp:nNn #1#2#3
  { T , F , TF }
  {
    \group_begin:
      \file_get_full_name:nNTF {#1} \l_@@_first_tl
        {
          \file_get_full_name:nNTF {#3} \l_@@_second_tl
            {
              \if_int_compare:w
                  \@@_str_cmp:nn
                    { \@@_timestamp:n \exp_after:wN { \l_@@_first_tl } }
                    { \@@_timestamp:n \exp_after:wN { \l_@@_second_tl } }
                    #2 0 \exp_stop_f:
              \group_end:
              \prg_return_true:
            \else:
              \group_end:
               \prg_return_false:
            \fi:
            }
            {
              \group_end:
               \if_charcode:w #2 >
                  \prg_return_true:
                \else:
                  \prg_return_false:
                \fi:
            }
        }
        {
          \group_end:
          \if_charcode:w #2 <
            \prg_return_true:
          \else:
            \prg_return_false:
          \fi:
        }
  }
\sys_if_engine_luatex:TF
  {
    \cs_new:Npn \@@_timestamp:n #1
      {
        \lua_now:e
          { l3kernel.filemoddate ( " \lua_escape:e {#1} " ) }
      }
  }
  { \cs_new_eq:NN \@@_timestamp:n \tex_filemoddate:D }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%<@@=ior>
%    \end{macrocode}
%
% \begin{macro}{\ior_shell_open:Nn}
% \begin{macro}{\@@_shell_open:nN}
%   Actually much easier than either the standard open or input versions!
%    \begin{macrocode}
\cs_new_protected:Npn \ior_shell_open:Nn #1#2
  {
    \sys_if_shell:TF
      { \exp_args:No \@@_shell_open:nN { \tl_to_str:n {#2} } #1 }
      { \__kernel_msg_error:nn { kernel } { pipe-failed } }
  }
\cs_new_protected:Npn \@@_shell_open:nN #1#2
  {
    \tl_if_in:nnTF {#1} { " }
      {
        \__kernel_msg_error:nnx
          { kernel } { quote-in-shell } {#1}
      }
      { \__kernel_ior_open:Nn #2 { "|#1" } }
  }
\__kernel_msg_new:nnnn { kernel } { pipe-failed }
  { Cannot~run~piped~system~commands. }
  {
    LaTeX~tried~to~call~a~system~process~but~this~was~not~possible.\\
    Try~the~"--shell-escape"~(or~"--enable-pipes")~option.
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Additions to \pkg{l3tl}}
%
% \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).
%
% First, some code which \enquote{belongs} in \pkg{l3tokens} but has to come
% here.
%    \begin{macrocode}
%<@@=char>
%    \end{macrocode}
%
% \begin{macro}[EXP]
%   {
%     \char_lower_case:N, \char_upper_case:N,
%     \char_mixed_case:N, \char_fold_case:N
%   }
% \begin{macro}[EXP]{\@@_change_case:nNN}
% \begin{macro}[EXP]{\@@_change_case:nN}
% \begin{macro}[EXP]{\@@_change_case_multi:nN, \@@_change_case_multi:vN}
% \begin{macro}[EXP]{\@@_change_case_multi:NNNNw}
% \begin{macro}[EXP]{\@@_change_case:NNN}
% \begin{macro}[EXP]{\@@_change_case:NNNN}
% \begin{macro}[EXP]{\@@_change_case:NN}
% \begin{macro}[EXP]{\@@_change_case_catcode:N}
% \begin{macro}[EXP]
%   {
%     \char_str_lower_case:N, \char_str_upper_case:N,
%     \char_str_mixed_case:N, \char_str_fold_case:N
%   }
% \begin{macro}[EXP]{\@@_str_change_case:nNN}
% \begin{macro}[EXP]{\@@_str_change_case:nN}
%   Expandable character generation is done using a two-part approach.
%   First, see if the current character has a special mapping for the current
%   transformation. If it does, insert that. Otherwise, use the \TeX{} data
%   to look up the one-to-one mapping, and generate the appropriate character
%   with the appropriate category code. Mixed case needs an extra step as it
%   may be special-cased or might be a special upper case outcome. The internal
%   when using non-Unicode engines has to be set up to only do anything
%   with ASCII characters.
%
%  To ensure that the category codes produced are predictable, every character
%  is re-generated even if it is otherwise unchanged. This makes life a little
%  interesting when we might have multiple output characters: we have to
%  grab each of them and case change them in reverse order to maintain
%  \texttt{f}-type expandability.
%    \begin{macrocode}
\cs_new:Npn \char_lower_case:N #1
  { \@@_change_case:nNN { lower } \char_value_lccode:n #1 }
\cs_new:Npn \char_upper_case:N #1
  { \@@_change_case:nNN { upper } \char_value_uccode:n #1 }
\cs_new:Npn \char_mixed_case:N #1
  {
    \tl_if_exist:cTF { c_@@_mixed_case_ \token_to_str:N #1 _tl }
      {
        \@@_change_case_multi:vN
          { c_@@_mixed_case_ \token_to_str:N #1 _tl } #1
      }
      { \char_upper_case:N #1 }
  }
\cs_new:Npn \char_fold_case:N #1
  { \@@_change_case:nNN { fold } \char_value_lccode:n #1 }
\cs_new:Npn \@@_change_case:nNN #1#2#3
  {
    \tl_if_exist:cTF { c_@@_ #1 _case_ \token_to_str:N #3 _tl }
      {
        \@@_change_case_multi:vN
          { c_@@_ #1 _case_ \token_to_str:N #3 _tl } #3
      }
      { \exp_args:Nf \@@_change_case:nN { #2 { `#3 } } #3 }
  }
\cs_new:Npn \@@_change_case:nN #1#2
  {
    \int_compare:nNnTF {#1} = 0
      { #2 }
      { \char_generate:nn {#1} { \@@_change_case_catcode:N #2 } }
  }
\cs_new:Npn \@@_change_case_multi:nN #1#2
  { \@@_change_case_multi:NNNNw #2 #1 \q_no_value \q_no_value \q_stop }
\cs_generate_variant:Nn \@@_change_case_multi:nN { v }
\cs_new:Npn \@@_change_case_multi:NNNNw #1#2#3#4#5 \q_stop
  {
    \quark_if_no_value:NTF #4
      {
        \quark_if_no_value:NTF #3
          { \@@_change_case:NN #1 #2 }
          { \@@_change_case:NNN #1 #2#3 }
      }
      { \@@_change_case:NNNN #1 #2#3#4 }
  }
\cs_new:Npn \@@_change_case:NNN #1#2#3
  {
    \exp_args:Nnf \use:nn
      { \@@_change_case:NN #1 #2 }
      { \@@_change_case:NN #1 #3 }
  }
\cs_new:Npn \@@_change_case:NNNN #1#2#3#4
  {
    \exp_args:Nnff \use:nnn
      { \@@_change_case:NN #1 #2 }
      { \@@_change_case:NN #1 #3 }
      { \@@_change_case:NN #1 #4 }
  }
\cs_new:Npn \@@_change_case:NN #1#2
  { \char_generate:nn { `#2 } { \@@_change_case_catcode:N #1 } }
\cs_new:Npn \@@_change_case_catcode:N #1
  {
    \if_catcode:w \exp_not:N #1 \c_math_toggle_token
      3
    \else:
      \if_catcode:w \exp_not:N #1 \c_alignment_token
        4
      \else:
        \if_catcode:w \exp_not:N #1 \c_math_superscript_token
          7
        \else:
          \if_catcode:w \exp_not:N #1 \c_math_subscript_token
            8
          \else:
            \if_catcode:w \exp_not:N #1 \c_space_token
              10
            \else:
             \if_catcode:w \exp_not:N #1 \c_catcode_letter_token
               11
             \else:
               \if_catcode:w \exp_not:N #1 \c_catcode_other_token
                 12
               \else:
                 13
               \fi:
             \fi:
            \fi:
          \fi:
        \fi:
      \fi:
    \fi:
  }
%    \end{macrocode}
%   Same story for the string version, except category code is easier
%   to follow. This of course makes this version significantly faster.
%    \begin{macrocode}
\cs_new:Npn \char_str_lower_case:N #1
  { \@@_str_change_case:nNN { lower } \char_value_lccode:n #1 }
\cs_new:Npn \char_str_upper_case:N #1
  { \@@_str_change_case:nNN { upper } \char_value_uccode:n #1 }
\cs_new:Npn \char_str_mixed_case:N #1
  {
    \tl_if_exist:cTF { c_@@_mixed_case_ \token_to_str:N #1 _tl }
      { \tl_to_str:c { c_@@_mixed_case_ \token_to_str:N #1 _tl } }
      { \char_str_upper_case:N #1 }
  }
\cs_new:Npn \char_str_fold_case:N #1
  { \@@_str_change_case:nNN { fold } \char_value_lccode:n #1 }
\cs_new:Npn \@@_str_change_case:nNN #1#2#3
  {
    \tl_if_exist:cTF { c_@@_ #1 _case_ \token_to_str:N #3 _tl }
      { \tl_to_str:c { c_@@_ #1 _case_ \token_to_str:N #3 _tl } }
      { \exp_args:Nf \@@_str_change_case:nN { #2 { `#3 } } #3 }
  }
\cs_new:Npn \@@_str_change_case:nN #1#2
  {
    \int_compare:nNnTF {#1} = 0
      { \tl_to_str:n {#2} }
      { \char_generate:nn {#1} { 12 } }
  }
\cs_if_exist:NF \tex_Uchar:D
  {
    \cs_set:Npn \@@_str_change_case:nN #1#2
      { \tl_to_str:n {#2} }
  }
%    \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}
%
% \begin{macro}[EXP]{\char_codepoint_to_bytes:n}
% \begin{macro}[EXP]{\@@_codepoint_to_bytes_auxi:n}
% \begin{macro}[EXP]{\@@_codepoint_to_bytes_auxii:Nnn}
% \begin{macro}[EXP]{\@@_codepoint_to_bytes_auxiii:n}
% \begin{macro}[EXP]
%   {
%     \@@_codepoint_to_bytes_outputi:nw   ,
%     \@@_codepoint_to_bytes_outputii:nw  ,
%     \@@_codepoint_to_bytes_outputiii:nw ,
%     \@@_codepoint_to_bytes_outputiv:nw
%   }
% \begin{macro}[EXP]
%   {\@@_codepoint_to_bytes_output:nnn, \@@_codepoint_to_bytes_output:fnn}
% \begin{macro}[EXP]{\@@_codepoint_to_bytes_end:}
%   This code converts a codepoint into the correct UTF-8 representation.
%   In terms of the algorithm itself, see
%   \url{https://en.wikipedia.org/wiki/UTF-8} for the octet pattern.
%    \begin{macrocode}
\cs_new:Npn \char_codepoint_to_bytes:n #1
  {
    \exp_args:Nf \@@_codepoint_to_bytes_auxi:n
      { \int_eval:n {#1} }
  }
\cs_new:Npn \@@_codepoint_to_bytes_auxi:n #1
  {
    \if_int_compare:w #1 > "80 \exp_stop_f:
      \if_int_compare:w #1 < "800 \exp_stop_f:
        \@@_codepoint_to_bytes_outputi:nw
          { \@@_codepoint_to_bytes_auxii:Nnn C {#1} { 64 } }
        \@@_codepoint_to_bytes_outputii:nw
          { \@@_codepoint_to_bytes_auxiii:n {#1} }
      \else:
        \if_int_compare:w #1 < "10000 \exp_stop_f:
          \@@_codepoint_to_bytes_outputi:nw
            { \@@_codepoint_to_bytes_auxii:Nnn E {#1} { 64 * 64 } }
          \@@_codepoint_to_bytes_outputii:nw
            {
              \@@_codepoint_to_bytes_auxiii:n
                { \int_div_truncate:nn {#1} { 64 } }
            }
          \@@_codepoint_to_bytes_outputiii:nw
            { \@@_codepoint_to_bytes_auxiii:n {#1} }
        \else:
          \@@_codepoint_to_bytes_outputi:nw
            {
              \@@_codepoint_to_bytes_auxii:Nnn F
                 {#1} { 64 * 64 * 64 }
            }
          \@@_codepoint_to_bytes_outputii:nw
            {
              \@@_codepoint_to_bytes_auxiii:n
                { \int_div_truncate:nn {#1} { 64 * 64 } }
            }
          \@@_codepoint_to_bytes_outputiii:nw
            {
              \@@_codepoint_to_bytes_auxiii:n
                { \int_div_truncate:nn {#1} { 64 } }
            }
          \@@_codepoint_to_bytes_outputiv:nw
            { \@@_codepoint_to_bytes_auxiii:n {#1} }
        \fi:
      \fi:
    \else:
      \@@_codepoint_to_bytes_outputi:nw {#1}
    \fi:
    \@@_codepoint_to_bytes_end: { } { } { } { }
  }
\cs_new:Npn \@@_codepoint_to_bytes_auxii:Nnn #1#2#3
  {  "#10 + \int_div_truncate:nn {#2} {#3} }
\cs_new:Npn \@@_codepoint_to_bytes_auxiii:n #1
  { \int_mod:nn {#1} { 64 } + 128 }
\cs_new:Npn \@@_codepoint_to_bytes_outputi:nw
  #1 #2 \@@_codepoint_to_bytes_end: #3
  { \@@_codepoint_to_bytes_output:fnn { \int_eval:n {#1} } { } {#2} }
\cs_new:Npn \@@_codepoint_to_bytes_outputii:nw
  #1 #2 \@@_codepoint_to_bytes_end: #3#4
  { \@@_codepoint_to_bytes_output:fnn { \int_eval:n {#1} } { {#3} } {#2} }
\cs_new:Npn \@@_codepoint_to_bytes_outputiii:nw
  #1 #2 \@@_codepoint_to_bytes_end: #3#4#5
  {
    \@@_codepoint_to_bytes_output:fnn
      { \int_eval:n {#1} } { {#3} {#4} } {#2}
  }
\cs_new:Npn \@@_codepoint_to_bytes_outputiv:nw
  #1 #2 \@@_codepoint_to_bytes_end: #3#4#5#6
  {
    \@@_codepoint_to_bytes_output:fnn
      { \int_eval:n {#1} } { {#3} {#4} {#5} } {#2}
  }
\cs_new:Npn \@@_codepoint_to_bytes_output:nnn #1#2#3
  {
    #3
    \@@_codepoint_to_bytes_end: #2 {#1}
  }
\cs_generate_variant:Nn \@@_codepoint_to_bytes_output:nnn { f }
\cs_new:Npn \@@_codepoint_to_bytes_end: { }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%<@@=tl>
%    \end{macrocode}
%
% \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.
%    \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 { \@@_change_case:nnn { mixed } { } }
\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 { \@@_change_case:nnn { mixed } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_change_case:nnn}
% \begin{macro}[EXP]{\@@_change_case_aux:nnn}
% \begin{macro}[EXP]{\@@_change_case_loop:wnn}
% \begin{macro}[EXP]
%   {
%     \@@_change_case_output:nwn ,
%     \@@_change_case_output:Vwn ,
%     \@@_change_case_output:own ,
%     \@@_change_case_output:vwn ,
%     \@@_change_case_output:fwn ,
%   }
% \begin{macro}[EXP]{\@@_change_case_end:wn}
% \begin{macro}[EXP]{\@@_change_case_group:nwnn}
% \begin{macro}[EXP]
%   {
%     \@@_change_case_group_lower:nnnn ,
%     \@@_change_case_group_upper:nnnn ,
%     \@@_change_case_group_mixed:nnnn
%   }
% \begin{macro}[EXP]{\@@_change_case_space:wnn}
% \begin{macro}[EXP]{\@@_change_case_N_type:Nwnn}
% \begin{macro}[EXP]{\@@_change_case_N_type:NNNnnn}
% \begin{macro}[EXP]{\@@_change_case_math:NNNnnn}
% \begin{macro}[EXP]{\@@_change_case_math_loop:wNNnn}
% \begin{macro}[EXP]{\@@_change_case_math:NwNNnn}
% \begin{macro}[EXP]{\@@_change_case_math_group:nwNNnn}
% \begin{macro}[EXP]{\@@_change_case_math_space:wNNnn}
% \begin{macro}[EXP]{\@@_change_case_N_type:Nnnn}
% \begin{macro}[EXP]
%   {
%     \@@_change_case_char_lower:Nnn ,
%     \@@_change_case_char_upper:Nnn ,
%     \@@_change_case_char_mixed:Nnn
%   }
% \begin{macro}[EXP]{\@@_change_case_char:nN}
% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNN}
% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNNN}
% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nNNNN}
% \begin{macro}[EXP]{\@@_change_case_char_UTFviii:nn}
% \begin{macro}[EXP]{\@@_change_case_cs_letterlike:Nn}
% \begin{macro}[EXP]{\@@_change_case_cs_letterlike:NnN}
% \begin{macro}[EXP]{\@@_change_case_cs_accents:NN}
% \begin{macro}[EXP]{\@@_change_case_cs:N}
% \begin{macro}[EXP]{\@@_change_case_cs:NN}
% \begin{macro}[EXP]{\@@_change_case_cs:NNn}
% \begin{macro}[EXP]{\@@_change_case_protect:wNN}
% \begin{macro}[EXP]{\@@_change_case_if_expandable:NTF}
% \begin{macro}[EXP]{\@@_change_case_cs_expand:Nnw}
% \begin{macro}[EXP]{\@@_change_case_cs_expand:NN}
% \begin{macro}[EXP]{\@@_change_case_mixed_skip:N}
% \begin{macro}[EXP]{\@@_change_case_mixed_skip:NN}
% \begin{macro}[EXP]{\@@_change_case_mixed_skip_tidy:Nwn}
% \begin{macro}[EXP]{\@@_change_case_mixed_switch:w}
%   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
  {
    \__kernel_exp_not:w \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
  {
    \use:c { @@_change_case_group_ #3 : nnnn } {#1} {#2} {#3} {#4}
  }
\cs_new:Npn \@@_change_case_group_lower:nnnn #1#2#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}
  }
\cs_new_eq:NN \@@_change_case_group_upper:nnnn
  \@@_change_case_group_lower:nnnn
%    \end{macrocode}
%  For the \enquote{mixed} case, a group is taken as forcing a switch to lower
%  casing. That means we need a separate auxiliary. (Tracking whether we have
%  found a first character inside a group and transferring the information out
%  looks pretty horrible.)
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_group_mixed:nnnn #1#2#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 { lower } {#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 is forced (\emph{i.e.}~there is no assumption
%   of \enquote{well-behaved} input 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:Nn #1 {#3} }
      { \use:c { @@_change_case_char_ #3 :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_lower: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 }
        }
  }
\cs_new_eq:NN \@@_change_case_char_upper:Nnn
  \@@_change_case_char_lower:Nnn
%    \end{macrocode}
%   For mixed case, the code is somewhat different: there is a need to
%   look up both mixed and upper case chars and we have to cover the
%   situation where there is a character to skip over.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_char_mixed:Nnn #1#2#3
  {
    \@@_change_case_mixed_switch:w
    \cs_if_exist_use:cF { @@_change_case_mixed_ #3 :Nnw }
      {
        \cs_if_exist_use:cF { @@_change_case_upper_ #3 :Nnw }
          { \use_ii:nn }
      }
        #1
        { \@@_change_case_mixed_skip:N #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}
\bool_lazy_or:nnTF
  { \sys_if_engine_luatex_p: }
  { \sys_if_engine_xetex_p: }
  {
    \cs_new:Npn \@@_change_case_char:nN #1#2
      {
        \@@_change_case_output:fwn
          { \use:c { char_ #1 _case:N } #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_output:fwn
              { \use:c { char_ #1 _case:N } #2 }
          }
       }
  }
%    \end{macrocode}
%   To allow for the special case of mixed case, we insert here a
%   action-dependent auxiliary.
%    \begin{macrocode}
\bool_lazy_or:nnF
  { \sys_if_engine_luatex_p: }
  { \sys_if_engine_xetex_p: }
  {
    \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_@@_ #1 _case_ \tl_to_str:n {#2} _tl }
          {
            \@@_change_case_output:vwn
              { c_@@_ #1 _case_ \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 split into two parts here allows us to insert
%   the \enquote{switch} code for mixed casing.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_cs_letterlike:Nn #1#2
  {
    \str_if_eq:nnTF {#2} { mixed }
      {
        \@@_change_case_cs_letterlike:NnN #1 { upper }
          \@@_change_case_mixed_switch:w
      }
      { \@@_change_case_cs_letterlike:NnN #1 {#2} \prg_do_nothing: }
  }
\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 expandability 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}
%   would choke if |#1| was |(|!
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_if_expandable:NTF #1
  {
    \token_if_expandable:NTF #1
      {
        \bool_lazy_any:nTF
          {
            { \token_if_eq_meaning_p:NN \q_recursion_tail #1 }
            { \token_if_protected_macro_p:N      #1 }
            { \token_if_protected_long_macro_p:N #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}
%  For mixed case, there is an additional list of exceptions to deal with:
%  once that is sorted, we can move on back to the main loop.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_mixed_skip:N #1
  {
    \exp_after:wN \@@_change_case_mixed_skip:NN
      \exp_after:wN #1 \l_tl_mixed_case_ignore_tl
      \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \@@_change_case_mixed_skip:NN #1#2
  {
    \quark_if_recursion_tail_stop_do:nn {#2}
      { \@@_change_case_char:nN { mixed } #1 }
    \int_compare:nNnT { `#1 }  = { `#2 }
      {
        \use_i_delimit_by_q_recursion_stop:nw
          {
            \@@_change_case_output:nwn {#1}
            \@@_change_case_mixed_skip_tidy:Nwn
          }
      }
    \@@_change_case_mixed_skip:NN #1
  }
\cs_new:Npn \@@_change_case_mixed_skip_tidy:Nwn #1#2 \q_recursion_stop #3
  {
    \@@_change_case_loop:wnn #2 \q_recursion_stop { mixed }
  }
%    \end{macrocode}
%   Needed to switch from mixed to lower casing when we have found a
%   first character in the former mode.
%    \begin{macrocode}
\cs_new:Npn \@@_change_case_mixed_switch:w
  #1 \@@_change_case_loop:wnn #2 \q_recursion_stop #3
  {
    #1
    \@@_change_case_loop:wnn #2 \q_recursion_stop { lower }
  }
%    \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}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\@@_change_case_lower_sigma:Nnw}
% \begin{macro}[EXP]{\@@_change_case_lower_sigma:w}
% \begin{macro}[EXP]{\@@_change_case_lower_sigma:Nw}
% \begin{macro}[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_@@_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_@@_std_sigma_tl }
          { \c_@@_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}[EXP]{\@@_change_case_lower_tr:Nnw}
% \begin{macro}[EXP]{\@@_change_case_lower_tr_auxi:Nw}
% \begin{macro}[EXP]{\@@_change_case_lower_tr_auxii:Nw}
% \begin{macro}[EXP]{\@@_change_case_upper_tr:Nnw}
% \begin{macro}[EXP]{\@@_change_case_lower_az:Nnw}
% \begin{macro}[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}
\bool_lazy_or:nnTF
  { \sys_if_engine_luatex_p: }
  { \sys_if_engine_xetex_p: }
  {
    \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_@@_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_lazy_or:nnTF
              { \token_if_cs_p:N #1 }
              { ! \int_compare_p:nNn { `#1 } = { "0307 } }
              { \@@_change_case_output:Vwn \c_@@_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_@@_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_@@_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}[EXP]{\@@_change_case_lower_lt:Nnw}
% \begin{macro}[EXP]{\@@_change_case_lower_lt:nNnw}
% \begin{macro}[EXP]{\@@_change_case_lower_lt:nnw}
% \begin{macro}[EXP]{\@@_change_case_lower_lt:Nw}
% \begin{macro}[EXP]{\@@_change_case_lower_lt:NNw}
% \begin{macro}[EXP]{\@@_change_case_upper_lt:Nnw}
% \begin{macro}[EXP]{\@@_change_case_upper_lt:nnw}
% \begin{macro}[EXP]{\@@_change_case_upper_lt:Nw}
% \begin{macro}[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_@@_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_@@_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_lazy_and:nnT
          { ! \token_if_cs_p:N #2 }
          {
            \bool_lazy_any_p:n
              {
                { \int_compare_p:nNn { `#2 } = { "0300 } }
                { \int_compare_p:nNn { `#2 } = { "0301 } }
                { \int_compare_p:nNn { `#2 } = { "0303 } }
              }
          }
          { \@@_change_case_output:Vwn \c_@@_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_@@_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_lazy_and:nnTF
          { ! \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_@@_upper_Eszett_tl }
      {#2}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}
%   {
%     \c_@@_std_sigma_tl    ,
%     \c_@@_final_sigma_tl  ,
%     \c_@@_accents_lt_tl   ,
%     \c_@@_dot_above_tl    ,
%     \c_@@_upper_Eszett_tl
%   }
%   The above needs various special token lists containing pre-formed characters.
%   This set are only available in Unicode engines, with no-op definitions
%   for $8$-bit use.
%    \begin{macrocode}
\bool_lazy_or:nnTF
  { \sys_if_engine_luatex_p: }
  { \sys_if_engine_xetex_p: }
  {
    \group_begin:
      \cs_set:Npn \@@_tmp:n #1
        {
          \exp_after:wN \exp_after:wN \exp_after:wN \exp_not:N
            \char_generate:nn {#1} { \char_value_catcode:n {#1} }
        }
      \tl_const:Nx \c_@@_std_sigma_tl    { \@@_tmp:n { "03C3 } }
      \tl_const:Nx \c_@@_final_sigma_tl  { \@@_tmp:n { "03C2 } }
      \tl_const:Nx \c_@@_accents_lt_tl
        {
          \@@_tmp:n { "00CC }
            {
              \@@_tmp:n { "0069 }
              \@@_tmp:n { "0307 }
              \@@_tmp:n { "0300 }
            }
          \@@_tmp:n { "00CD }
            {
              \@@_tmp:n { "0069 }
              \@@_tmp:n { "0307 }
              \@@_tmp:n { "0301 }
            }
          \@@_tmp:n { "0128 }
            {
              \@@_tmp:n { "0069 }
              \@@_tmp:n { "0307 }
              \@@_tmp:n { "0303 }
            }
        }
      \tl_const:Nx \c_@@_dot_above_tl    { \@@_tmp:n { "0307 } }
      \tl_const:Nx \c_@@_upper_Eszett_tl { \@@_tmp:n { "1E9E } }
    \group_end:
  }
  {
      \tl_const:Nn \c_@@_std_sigma_tl    { }
      \tl_const:Nn \c_@@_final_sigma_tl  { }
      \tl_const:Nn \c_@@_accents_lt_tl   { }
      \tl_const:Nn \c_@@_dot_above_tl    { }
      \tl_const:Nn \c_@@_upper_Eszett_tl { }
  }
%    \end{macrocode}
% \end{variable}
% \begin{variable}
%   {
%     \c_@@_dotless_i_tl    ,
%     \c_@@_dotted_I_tl     ,
%     \c_@@_i_ogonek_tl     ,
%     \c_@@_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:
  \bool_lazy_or:nnTF
    { \sys_if_engine_luatex_p: }
    { \sys_if_engine_xetex_p: }
    {
      \cs_set_protected:Npn \@@_tmp:w #1#2
        {
          \tl_const:Nx #1
            {
              \exp_after:wN \exp_after:wN \exp_after:wN
               \exp_not:N \char_generate:nn
                 {"#2} { \char_value_catcode:n {"#2} }
            }
        }
    }
    {
      \cs_set_protected:Npn \@@_tmp:w #1#2
        {
          \group_begin:
            \cs_set_protected:Npn \@@_tmp:w ##1##2##3##4
              {
                \tl_const:Nx #1
                  {
                    \exp_after:wN \exp_after:wN \exp_after:wN
                      \exp_not:N \char_generate:nn {##1} { 13 }
                    \exp_after:wN \exp_after:wN \exp_after:wN
                      \exp_not:N \char_generate:nn {##2} { 13 }
                  }
              }
            \tl_set:Nx \l_@@_internal_a_tl
              { \char_codepoint_to_bytes:n {"#2} }
            \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
          \group_end:
        }
    }
  \@@_tmp:w \c_@@_dotless_i_tl { 0131 }
  \@@_tmp:w \c_@@_dotted_I_tl  { 0130 }
  \@@_tmp:w \c_@@_i_ogonek_tl  { 012F }
  \@@_tmp:w \c_@@_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_lazy_or:nnT
    { \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
            {
              \char_codepoint_to_bytes:n {"#1}
              \char_codepoint_to_bytes:n {"#2}
            }
          \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
          \@@_loop:nn
        }
      \cs_set_protected:Npn \@@_tmp:nnnn #1#2#3#4#5
        {
          \tl_const:cx
            {
              c_@@_ #1 _case_
              \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 {#4} { 13 }
              \exp_after:wN \exp_after:wN \exp_after:wN
                \exp_not:N \char_generate:nn {#5} { 13 }
            }
        }
      \cs_set_protected:Npn \@@_tmp:w #1#2#3#4#5#6#7#8
        {
          \tl_const:cx
            {
              c_@@_lower_case_
              \char_generate:nn {#1} { 12 }
              \char_generate:nn {#2} { 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 }
            }
          \@@_tmp:nnnn { upper } {#5} {#6} {#1} {#2}
          \@@_tmp:nnnn { mixed } {#5} {#6} {#1} {#2}
        }
      \@@_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##4
              {
                \tl_const:cx
                  {
                    c_@@_ #3 _case_
                    \char_generate:nn {##1} { 12 }
                    \char_generate:nn {##2} { 12 }
                    _tl
                  }
                    {#2}
              }
            \tl_set:Nx \l_@@_internal_a_tl
              { \char_codepoint_to_bytes:n { "#1 } }
            \exp_after:wN \@@_tmp:w \l_@@_internal_a_tl
          \group_end:
        }
      \@@_tmp:w { 00DF } { SS } { upper }
      \@@_tmp:w { 00DF } { Ss } { mixed }
      \@@_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}[EXP]{\@@_change_case_mixed_nl:Nnw}
% \begin{macro}[EXP]{\@@_change_case_mixed_nl:Nw}
% \begin{macro}[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_lazy_or:nnTF
      { \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_lazy_and:nnTF
          { ! ( \token_if_cs_p:N #2 ) }
          {
            \bool_lazy_or_p:nn
              { \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}
%
% \subsubsection{Building a token list}
%
% Between \cs{tl_build_begin:N} \meta{tl~var} and \cs{tl_build_end:N}
% \meta{tl~var}, the \meta{tl~var} has the structure
% \begin{quote}
%   \cs{exp_end:} \ldots{} \cs{exp_end:} \cs{@@_build_last:NNn}
%   \meta{assignment} \meta{next~tl} \Arg{left} \meta{right}
% \end{quote}
% where \meta{right} is not braced.  The \enquote{data} it represents is
% \meta{left} followed by the \enquote{data} of \meta{next~tl} followed
% by \meta{right}.  The \meta{next~tl} is a token list variable whose
% name is that of \meta{tl~var} followed by~|'|.  There are between $0$
% and $4$ \cs{exp_end:} to keep track of when \meta{left} and
% \meta{right} should be put into the \meta{next~tl}.  The
% \meta{assignment} is \cs{cs_set_nopar:Npx} if the variable is local,
% and \cs{cs_gset_nopar:Npx} if it is global.
%
% \begin{macro}{\tl_build_begin:N, \tl_build_gbegin:N}
% \begin{macro}{\@@_build_begin:NN, \@@_build_begin:NNN}
%   First construct the \meta{next~tl}: using a prime here conflicts
%   with the usual \pkg{expl3} convention but we need a name that can be
%   derived from |#1| without any external data such as a counter.
%   Empty that \meta{next~tl} and setup the structure.  The local and
%   global versions only differ by a single function
%   \cs[no-index]{cs_(g)set_nopar:Npx} used for all assignments: this is
%   important because only that function is stored in the \meta{tl~var}
%   and \meta{next~tl} for subsequent assignments.  In principle
%   \cs{@@_build_begin:NNN} could use \cs[no-index]{tl_(g)clear_new:N}
%   to empty |#1| and make sure it is defined, but logging the
%   definition does not seem useful so we just do |#3| |#1| |{}| to
%   clear it locally or globally as appropriate.
%    \begin{macrocode}
\__kernel_patch:nnNNpn { \__kernel_chk_var_local:N #1 } { }
\cs_new_protected:Npn \tl_build_begin:N #1
  { \@@_build_begin:NN \cs_set_nopar:Npx #1 }
\__kernel_patch:nnNNpn { \__kernel_chk_var_global:N #1 } { }
\cs_new_protected:Npn \tl_build_gbegin:N #1
  { \@@_build_begin:NN \cs_gset_nopar:Npx #1 }
\cs_new_protected:Npn \@@_build_begin:NN #1#2
  { \exp_args:Nc \@@_build_begin:NNN { \cs_to_str:N #2 ' } #2 #1 }
\cs_new_protected:Npn \@@_build_begin:NNN #1#2#3
  {
    #3 #1 { }
    #3 #2
      {
        \exp_not:n { \exp_end: \exp_end: \exp_end: \exp_end: }
        \exp_not:n { \@@_build_last:NNn #3 #1 { } }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\tl_build_clear:N, \tl_build_gclear:N}
%   The |begin| and |gbegin| functions already clear enough to make the
%   token list variable effectively empty.  Eventually the |begin| and
%   |gbegin| functions should check that |#1'| is empty or undefined,
%   while the |clear| and |gclear| functions ought to empty |#1'|,
%   |#1''| and so on, similar to \cs{tl_build_end:N}.  This only affects
%   memory usage.
%    \begin{macrocode}
\cs_new_eq:NN \tl_build_clear:N \tl_build_begin:N
\cs_new_eq:NN \tl_build_gclear:N \tl_build_gbegin:N
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \tl_build_put_right:Nn, \tl_build_put_right:Nx,
%     \tl_build_gput_right:Nn, \tl_build_gput_right:Nx,
%     \@@_build_last:NNn, \@@_build_put:nn, \@@_build_put:nw
%   }
%   Similar to \cs{tl_put_right:Nn}, but apply \cs{exp:w} to |#1|.  Most
%   of the time this just removes one \cs{exp_end:}.  When there are
%   none left, \cs{@@_build_last:NNn} is expanded instead.  It resets
%   the definition of the \meta{tl~var} by ending the \cs{exp_not:n} and
%   the definition early.  Then it makes sure the \meta{next~tl} (its
%   argument |#1|) is set-up and starts a new definition.  Then
%   \cs{@@_build_put:nn} and \cs{@@_build_put:nw} place the \meta{left}
%   part of the original \meta{tl~var} as appropriate for the definition
%   of the \meta{next~tl} (the \meta{right} part is left in the right
%   place without ever becoming a macro argument).  We use
%   \cs{exp_after:wN} rather than some \cs{exp_args:No} to avoid reading
%   arguments that are likely very long token lists.  We use
%   \cs[no-index]{cs_(g)set_nopar:Npx} rather than
%   \cs[no-index]{tl_(g)set:Nx} partly for the same reason and partly
%   because the assignments are interrupted by brace tricks, which
%   implies that the assignment does not simply set the token list to an
%   |x|-expansion of the second argument.
%    \begin{macrocode}
\__kernel_patch:nnNNpn { \__kernel_chk_var_local:N #1 } { }
\cs_new_protected:Npn \tl_build_put_right:Nn #1#2
  {
    \cs_set_nopar:Npx #1
      { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 #2 } }
  }
\__kernel_patch:nnNNpn { \__kernel_chk_var_local:N #1 } { }
\cs_new_protected:Npn \tl_build_put_right:Nx #1#2
  {
    \cs_set_nopar:Npx #1
      { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 } #2 }
  }
\__kernel_patch:nnNNpn { \__kernel_chk_var_global:N #1 } { }
\cs_new_protected:Npn \tl_build_gput_right:Nn #1#2
  {
    \cs_gset_nopar:Npx #1
      { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 #2 } }
  }
\__kernel_patch:nnNNpn { \__kernel_chk_var_global:N #1 } { }
\cs_new_protected:Npn \tl_build_gput_right:Nx #1#2
  {
    \cs_gset_nopar:Npx #1
      { \exp_after:wN \exp_not:n \exp_after:wN { \exp:w #1 } #2 }
  }
\cs_new_protected:Npn \@@_build_last:NNn #1#2
  {
    \if_false: { { \fi:
          \exp_end: \exp_end: \exp_end: \exp_end: \exp_end:
          \@@_build_last:NNn #1 #2 { }
        }
      }
    \if_meaning:w \c_empty_tl #2
      \@@_build_begin:NN #1 #2
    \fi:
    #1 #2
      {
        \exp_after:wN \exp_not:n \exp_after:wN
          {
            \exp:w \if_false: } } \fi:
            \exp_after:wN \@@_build_put:nn \exp_after:wN {#2}
  }
\cs_new_protected:Npn \@@_build_put:nn #1#2 { \@@_build_put:nw {#2} #1 }
\cs_new_protected:Npn \@@_build_put:nw #1#2 \@@_build_last:NNn #3#4#5
  { #2 \@@_build_last:NNn #3 #4 { #1 #5 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \tl_build_put_left:Nn, \tl_build_put_left:Nx,
%     \tl_build_gput_left:Nn, \tl_build_gput_left:Nx, \@@_build_put_left:NNn
%   }
%   See \cs{tl_build_put_right:Nn} for all the machinery.  We could
%   easily provide \cs[no-index]{tl_build_put_left_right:Nnn}, by just
%   add the \meta{right} material after the \Arg{left} in the
%   |x|-expanding assignment.
%    \begin{macrocode}
\__kernel_patch:nnNNpn { \__kernel_chk_var_local:N #1 } { }
\cs_new_protected:Npn \tl_build_put_left:Nn #1
  { \@@_build_put_left:NNn \cs_set_nopar:Npx #1 }
\cs_generate_variant:Nn \tl_build_put_left:Nn { Nx }
\__kernel_patch:nnNNpn { \__kernel_chk_var_global:N #1 } { }
\cs_new_protected:Npn \tl_build_gput_left:Nn #1
  { \@@_build_put_left:NNn \cs_gset_nopar:Npx #1 }
\cs_generate_variant:Nn \tl_build_gput_left:Nn { Nx }
\cs_new_protected:Npn \@@_build_put_left:NNn #1#2#3
  {
    #1 #2
      {
        \exp_after:wN \exp_not:n \exp_after:wN
          {
            \exp:w \exp_after:wN \@@_build_put:nn
              \exp_after:wN {#2} {#3}
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\tl_build_get:NN}
% \begin{macro}{\@@_build_get:NNN, \@@_build_get:w, \@@_build_get_end:w}
%   The idea is to expand the \meta{tl~var} then the \meta{next~tl} and
%   so on, all within an |x|-expanding assignment, and wrap as
%   appropriate in \cs{exp_not:n}.  The various \meta{left} parts are
%   left in the assignment as we go, which enables us to expand the
%   \meta{next~tl} at the right place.  The various \meta{right} parts
%   are eventually picked up in one last \cs{exp_not:n}, with a brace
%   trick to wrap all the \meta{right} parts together.
%    \begin{macrocode}
\cs_new_protected:Npn \tl_build_get:NN
  { \@@_build_get:NNN \tl_set:Nx }
\cs_new_protected:Npn \@@_build_get:NNN #1#2#3
  { #1 #3 { \if_false: { \fi: \exp_after:wN \@@_build_get:w #2 } } }
\cs_new:Npn \@@_build_get:w #1 \@@_build_last:NNn #2#3#4
  {
    \exp_not:n {#4}
    \if_meaning:w \c_empty_tl #3
      \exp_after:wN \@@_build_get_end:w
    \fi:
    \exp_after:wN \@@_build_get:w #3
  }
\cs_new:Npn \@@_build_get_end:w #1#2#3
  { \exp_after:wN \exp_not:n \exp_after:wN { \if_false: } \fi: }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\tl_build_end:N, \tl_build_gend:N, \@@_build_end_loop:NN}
%   Get the data then clear the \meta{next~tl} recursively until finding
%   an empty one.  It is perhaps wasteful to repeatedly use
%   \cs{cs_to_sr:N}.  The local/global scope is checked by
%   \cs{tl_set:Nx} or \cs{tl_gset:Nx}.
%    \begin{macrocode}
\cs_new_protected:Npn \tl_build_end:N #1
  {
    \@@_build_get:NNN \tl_set:Nx #1 #1
    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } \tl_clear:N
  }
\cs_new_protected:Npn \tl_build_gend:N #1
  {
    \@@_build_get:NNN \tl_gset:Nx #1 #1
    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } \tl_gclear:N
  }
\cs_new_protected:Npn \@@_build_end_loop:NN #1#2
  {
    \if_meaning:w \c_empty_tl #1
      \exp_after:wN \use_none:nnnnnn
    \fi:
    #2 #1
    \exp_args:Nc \@@_build_end_loop:NN { \cs_to_str:N #1 ' } #2
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Other additions to \pkg{l3tl}}
%
% \begin{macro}{\tl_range_braced:Nnn, \tl_range_braced:cnn, \tl_range_braced:nnn}
% \begin{macro}
%   {\tl_range_unbraced:Nnn, \tl_range_unbraced:cnn, \tl_range_unbraced:nnn}
% \begin{macro}
%   {
%     \@@_range_braced:w, \@@_range_collect_braced:w,
%     \@@_range_unbraced:w, \@@_range_collect_unbraced:w,
%   }
%   For the braced version \cs{@@_range_braced:w} sets up
%   \cs{@@_range_collect_braced:w} which stores items one by one in an
%   argument after the semicolon.  The unbraced version is almost
%   identical.  The version preserving braces and spaces starts by
%   deleting spaces before the argument to avoid collecting them, and
%   sets up \cs{@@_range_collect:nn} with a first argument of the form
%   |{| \Arg{collected} \meta{tokens} |}|, whose head is the collected
%   tokens and whose tail is what remains of the original token list.
%   This form makes it easier to move tokens to the \meta{collected}
%   tokens.
%    \begin{macrocode}
\cs_new:Npn \tl_range_braced:Nnn { \exp_args:No \tl_range_braced:nnn }
\cs_generate_variant:Nn \tl_range_braced:Nnn { c }
\cs_new:Npn \tl_range_braced:nnn { \@@_range:Nnnn \@@_range_braced:w }
\cs_new:Npn \tl_range_unbraced:Nnn
  { \exp_args:No \tl_range_unbraced:nnn }
\cs_generate_variant:Nn \tl_range_unbraced:Nnn { c }
\cs_new:Npn \tl_range_unbraced:nnn
  { \@@_range:Nnnn \@@_range_unbraced:w }
\cs_new:Npn \@@_range_braced:w #1 ; #2
  { \@@_range_collect_braced:w #1 ; { } #2 }
\cs_new:Npn \@@_range_unbraced:w #1 ; #2
  { \@@_range_collect_unbraced:w #1 ; { } #2 }
\cs_new:Npn \@@_range_collect_braced:w #1 ; #2#3
  {
    \if_int_compare:w #1 > 1 \exp_stop_f:
      \exp_after:wN \@@_range_collect_braced:w
      \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
    \fi:
    { #2 {#3} }
  }
\cs_new:Npn \@@_range_collect_unbraced:w #1 ; #2#3
  {
    \if_int_compare:w #1 > 1 \exp_stop_f:
      \exp_after:wN \@@_range_collect_unbraced:w
      \int_value:w \int_eval:n { #1 - 1 } \exp_after:wN ;
    \fi:
    { #2 #3 }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Additions to \pkg{l3token}}
%
% \begin{variable}{\c_catcode_active_space_tl}
%   While \cs{char_generate:nn} can produce active characters in some
%   engines it cannot in general.  It would be possible to simply change
%   the catcode of space but then the code would need to avoid all
%   spaces, making it quite unreadable.  Instead we use the primitive
%   \cs{tex_lowercase:D} trick.
%    \begin{macrocode}
\group_begin:
  \char_set_catcode_active:N *
  \char_set_lccode:nn { `* } { `\ }
  \tex_lowercase:D { \tl_const:Nn \c_catcode_active_space_tl { * } }
\group_end:
%    \end{macrocode}
% \end{variable}
%
%    \begin{macrocode}
%<@@=peek>
%    \end{macrocode}
%
% \begin{variable}{\l_@@_collect_tl}
%    \begin{macrocode}
\tl_new:N \l_@@_collect_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}
%   {
%     \peek_catcode_collect_inline:Nn,
%     \peek_charcode_collect_inline:Nn,
%     \peek_meaning_collect_inline:Nn
%   }
% \begin{macro}
%   {
%     \@@_collect:NNn, \@@_collect_true:w,
%     \@@_collect_remove:nw, \@@_collect:N
%   }
%     Most of the work is done by \cs{@@_execute_branches_\ldots{}:},
%     which calls either \cs{@@_true:w} or \cs{@@_false:w} according to
%     whether the next token \cs{l_peek_token} matches the search token
%     (stored in \cs{l_@@_search_token} and \cs{l_@@_search_tl}).
%     Here, in the \texttt{true} case we run \cs{@@_collect_true:w},
%     which generally calls \cs{@@_collect:N} to store the peeked token
%     into \cs{l_@@_collect_tl}, except in special non-\texttt{N}-type
%     cases (begin-group, end-group, or space), where a frozen token is
%     stored.  The \texttt{true} branch calls
%     \cs{@@_execute_branches_\ldots{}:} to fetch more matching tokens.
%     Once there are no more, \cs{@@_false_aux:n} closes the safe-align
%     group and runs the user's inline code.
%    \begin{macrocode}
\cs_new_protected:Npn \peek_catcode_collect_inline:Nn
  { \@@_collect:NNn \@@_execute_branches_catcode: }
\cs_new_protected:Npn \peek_charcode_collect_inline:Nn
  { \@@_collect:NNn \@@_execute_branches_charcode: }
\cs_new_protected:Npn \peek_meaning_collect_inline:Nn
  { \@@_collect:NNn \@@_execute_branches_meaning: }
\cs_new_protected:Npn \@@_collect:NNn #1#2#3
  {
    \group_align_safe_begin:
    \cs_set_eq:NN \l_@@_search_token #2
    \tl_set:Nn \l_@@_search_tl {#2}
    \tl_clear:N \l_@@_collect_tl
    \cs_set:Npn \@@_false:w
      { \exp_args:No \@@_false_aux:n \l_@@_collect_tl }
    \cs_set:Npn \@@_false_aux:n ##1
      {
        \group_align_safe_end:
        #3
      }
    \cs_set_eq:NN \@@_true:w \@@_collect_true:w
    \cs_set:Npn \@@_true_aux:w { \peek_after:Nw #1 }
    \@@_true_aux:w
  }
\cs_new_protected:Npn \@@_collect_true:w
  {
    \if_case:w
        \if_catcode:w \exp_not:N \l_peek_token {   1 \exp_stop_f: \fi:
        \if_catcode:w \exp_not:N \l_peek_token }   2 \exp_stop_f: \fi:
        \if_meaning:w \l_peek_token \c_space_token 3 \exp_stop_f: \fi:
        0 \exp_stop_f:
      \exp_after:wN \@@_collect:N
    \or: \@@_collect_remove:nw { \c_group_begin_token }
    \or: \@@_collect_remove:nw { \c_group_end_token }
    \or: \@@_collect_remove:nw { ~ }
    \fi:
  }
\cs_new_protected:Npn \@@_collect:N #1
  {
    \tl_put_right:Nn \l_@@_collect_tl {#1}
    \@@_true_aux:w
  }
\cs_new_protected:Npn \@@_collect_remove:nw #1
  {
    \tl_put_right:Nn \l_@@_collect_tl {#1}
    \exp_after:wN \@@_true_remove:w
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
