% \iffalse
%% File: l3clist.dtx Copyright (C) 2005-2006 Frank Mittelbach, LaTeX3 project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the ``expl3 bundle'' (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/cgi-bin/cvsweb.cgi/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
\RequirePackage{l3names}
%</driver|package>
%\fi
\GetIdInfo$Id: l3clist.dtx 745 2008-08-03 18:50:46Z morten $
       {L3 Experimental comma separated lists}
%\iffalse
%<*driver>
%\fi
\ProvidesFile{\filename.\filenameext}
  [\filedate\space v\fileversion\space\filedescription]
%\iffalse
\documentclass{l3doc}
\begin{document}
\DocInput{\filename.\filenameext}
\end{document}
%</driver>
% \fi
%
%
%
% \title{The \textsf{l3clist} package\thanks{This file
%         has version number \fileversion, last
%         revised \filedate.}\\
% Comma separated lists}
% \author{Frank Mittelbach}
% \date{\filedate}
% \maketitle
%
%
%
% \section{Comma lists}
%
% \LaTeX3 implements a data type called `clist (comma-lists)'. These
% are special
% token lists that can be accessed via special function on the `left'.
% Appending tokens is possible at both ends. Appended token lists can be
% accessed only as a union.  The token lists that form the individual
% items of a comma-list might contain any tokens except for commas that
% are used to structure comma-lists (braces are need if commas are
% part of the value).  It is also possible to map functions on such
% comma-lists so that they are executed for every item of the comma-list.
%
% All functions that return items from a comma-list in some \m{tlp} assume
% that the \m{tlp} is local. See remarks below if you need a global
% returned value.
%
% The defined functions are not orthogonal in the sense that every
% possible variation possible is actually available. If you need a new
% variant use the expansion functions described in the package
% \texttt{l3expan} to build it.
%
% Adding items to the left of a comma-list can currently be done with
% either something like "\clist_put_left:Nn" or with a ``stack'' function
% like "\clist_push:Nn" which has the same effect. Maybe one should
% therefore remove the ``left'' functions totally.
%
% \subsection{Functions}
%
% \begin{function}{%
%                  \clist_new:N |
%                  \clist_new:c |
% }
% \begin{syntax}
%    "\clist_new:N" <comma-list>
% \end{syntax}
% Defines <comma-list> to be a variable of type clist.
% \end{function}
%
% \begin{function}{%
%                  \clist_clear:N |
%                  \clist_clear:c |
%                  \clist_gclear:N |
%                  \clist_gclear:c |
% }
% \begin{syntax}
%   "\clist_clear:N"  <comma-list>
% \end{syntax}
% These functions locally or globally clear <comma-list>.
% \end{function}
%
% \begin{function}{%
%                  \clist_put_left:Nn |
%                  \clist_put_left:No |
%                  \clist_put_left:Nx |
%                  \clist_put_left:cn |
%                  \clist_put_right:Nn |
%                  \clist_put_right:No |
%                  \clist_put_right:Nx |
% }
% \begin{syntax}
%   "\clist_put_left:Nn" <comma-list> <token list>
% \end{syntax}
% Locally  appends <token list> as a single item to the left
% or right of <comma-list>. <token list> might get expanded before
% appending.
% \end{function}
%
% \begin{function}{%
%                  \clist_gput_left:Nn |
%                  \clist_gput_right:Nn |
%                  \clist_gput_right:No |
%                  \clist_gput_right:cn |
%                  \clist_gput_right:co |
%                  \clist_gput_right:cc |
% }
% \begin{syntax}
%   "\clist_gput_left:Nn" <comma-list> <token list>
% \end{syntax}
% Globally appends <token list> as a single item to the left
% or right of <comma-list>.
% \end{function}
%
% \begin{function}{%
%                  \clist_get:NN |
%                  \clist_get:cN |
% }
% \begin{syntax}
%    "\clist_get:NN" <comma-list> <tlp>
% \end{syntax}
% Functions that locally assign the left-most item of <comma-list> to the
% token list pointer <tlp>. Item is not removed from <comma-list>! If you
% need a global return value you need to code something like this:
% \begin{quote}
%   "\clist_get:NN" <comma-list> "\l_tmpa_tlp" \\
%   "\tlp_gset_eq:NN" <global tlp> "\l_tmpa_tlp"
% \end{quote}
% But if this kind of construction is used often enough a separate
% function should be provided.
% \end{function}
%
% \begin{function}{%
%                  \clist_set_eq:NN
% }
% \begin{syntax}
%   "\clist_set_eq:NN" <clist1> <clist2>
% \end{syntax}
% Function that locally makes <clist1> identical to <clist2>.
% \end{function}
%
%
% \begin{function}{%
%                  \clist_gset_eq:NN |
%                  \clist_gset_eq:cN |
%                  \clist_gset_eq:Nc |
%                  \clist_gset_eq:cc
% }
% \begin{syntax}
%   "\clist_gset_eq:NN" <clist1> <clist2>
% \end{syntax}
% Function that globally makes <clist1> identical to <clist2>.
% \end{function}
%
%
% \begin{function}{%
%                  \clist_concat:NNN |
%                  \clist_gconcat:NNN |
%                  \clist_gconcat:NNc |
%                  \clist_gconcat:ccc |
% }
% \begin{syntax}
%   "\clist_gconcat:NNN" <clist1> <clist2> <clist3>
% \end{syntax}
% Function that concatenates <clist2> and <clist3> and globally assigns the
% result to <clist1>.
% \end{function}
%
%
% \begin{function}{%
%                  \clist_remove_duplicates:N |
%                  \clist_gremove_duplicates:N |
% }
% \begin{syntax}
%   "\clist_gremove_duplicates:N" <clist>
% \end{syntax}
% Function that removes any duplicate entries in <clist>.
% \end{function}
%
% \begin{function}{%
%                  \clist_use:N |
%                  \clist_use:c
% }
% \begin{syntax}
%   "\clist_use:N" <clist>
% \end{syntax}
% Function that inserts the <clist> into the processing stream. Mainly
% useful if one knows what the <clist> contains, e.g., for displaying
% the content of template parameters.
% \end{function}
%
%
% \subsection{Mapping functions}
%
%
% We provide three types of mapping functions, each with their own
% strengths. The "\clist_map_function:NN" is expandable whereas
% "\clist_map_inline:Nn" type uses "##1" as a placeholder for the
% current item in \m{clist}.  Finally we have the
% "\clist_map_variable:NNn" type which uses a user-defined variable as
% placeholder. Both the |_inline| and |_variable| versions are nestable.
%
%
% \begin{function}{\clist_map_function:NN|
%                  \clist_map_function:cN|
%                  \clist_map_function:nN
% }
% \begin{syntax}
%    "\clist_map_function:NN" <comma-list> <function>
% \end{syntax}
% This function applies <function> (which must be a function with one
% argument) to every item of <comma-list>. <function> is not executed
% within a sub-group so that side effects can be achieved locally. The
% operation is expandable which means that it can be used within write
% operations etc.
% \end{function}
%
% \begin{function}{\clist_map_inline:Nn |
%                  \clist_map_inline:cn |
%                  \clist_map_inline:nn |
% }
% \begin{syntax}
%   "\clist_map_inline:Nn" <comma-list> "{" <inline function> "}"
% \end{syntax}
% Applies <inline function> (which should be the direct coding for a
% function with one argument (i.e.\ use "##1" as the placeholder for
% this argument)) to every item of <comma-list>.  <inline function> is not
% executed within a sub-group so that side effects can be achieved locally.
% The operation is not expandable which means that it can't be used
% within write operations etc. These functions can be nested.
% \end{function}
%
%
% \begin{function}{\clist_map_variable:NNn |
%                  \clist_map_variable:cNn |
%                  \clist_map_variable:nNn |
% }
% \begin{syntax}
%   "\clist_map_variable:NNn" <comma-list> <temp-var> "{" <action> "}"
% \end{syntax}
% Assigns <temp-var> to each element in <clist> and then executes
% <action> which should contain <temp-var>. As the
% operation performs an assignment, it is not expandable.
% \begin{texnote}
%   These functions resemble the \LaTeXe{} function \tn{@for} but does
%   not borrow the somewhat strange syntax.
% \end{texnote}
% \end{function}
%
%  \begin{function}{%
%                   \clist_map_break:w |
%  }
%  \begin{syntax}
%     "\clist_map_break:w"
%  \end{syntax}
%  For breaking out of a loop. To be used inside "TF" type functions as
%  in the example below.
%  \begin{verbatim}
%  \def_new:Npn \test_function:n #1 {
%    \int_compare:nNnTF {#1}> 3 {\clist_map_break:w}{``#1''}
%  }
%  \clist_map_function:nN {1,2,3,4,5,6,7,8}\test_function:n
%  \end{verbatim}
%  This would return "``1''``2''``3''".
%  \end{function}
%
%
% \subsection{Predicates and conditionals}
%
% \begin{function}{\clist_if_empty_p:N}
% \begin{syntax}
%   "\clist_if_empty_p:N" <comma-list>
% \end{syntax}
% This predicate returns `true' if <comma-list> is `empty' i.e., doesn't
% contain any tokens.
% \end{function}
%
% \begin{function}{%
%                  \clist_if_empty:NTF |
%                  \clist_if_empty:cTF |
%                  \clist_if_empty:NF |
%                  \clist_if_empty:cF |
% }
% \begin{syntax}
%   "\clist_if_empty:NTF" <comma-list> "{" <true code> "}{" <false code> "}"
% \end{syntax}
% Set of conditionals that test whether or not a particular <comma-list>
% is empty and if so executes either <true code> or <false code>.
% \end{function}
%
% \begin{function}{%
%                  \clist_if_eq:NNTF |
% }
% \begin{syntax}
%   "\clist_if_eq:NNTF" <comma-list1> <comma-list2> "{" <true code>
%     "}{" <false code> "}"
% \end{syntax}
% Check if <comma-list1> and <comma-list2> are equal and execute
% either <true code> or <false code> accordingly.
% \end{function}
%
% \begin{function}{%
%                  \clist_if_in:NnTF |
%                  \clist_if_in:NoTF |
%                  \clist_if_in:cnTF |
%                  \clist_if_in:coTF |
% }
% \begin{syntax}
%   "\clist_if_in:NnTF" <comma-list> "{" <item> "}{" <true code> "}{"
%     <false code> "}"
% \end{syntax}
% Function that tests if <item> is in <comma-list>. Depending on the result
% either <true code> or <false code> is executed.
% \end{function}
%
% \subsection{Internal functions}
%
% \begin{function}{\clist_if_empty_err:N}
% \begin{syntax}
%   "\clist_if_empty_err:N" <comma-list>
% \end{syntax}
% Signals an \LaTeX3 error if <comma-list> is empty.
% \end{function}
%
% \begin{function}{\clist_pop_aux:nnNN}
% \begin{syntax}
%   "\clist_pop_aux:nnNN" <assign1> <assign2> <comma-list> <tlp>
% \end{syntax}
% Function that assigns the left-most item of <comma-list> to <tlp> using
% <assign1> and assigns the tail to <comma-list> using <assign2>. This
% function could be used to implement a global return function.
% \end{function}
%
% \begin{function}{%
%                  \clist_get_aux:w |
%                  \clist_pop_aux:w |
%                  \clist_pop_auxi:w |
%                  \clist_put_aux:NNnnNn |
% }
%  \begin{syntax}\end{syntax}
% Functions used to implement put and get operations. They  are not for
% meant for direct use.
% \end{function}
%
%
%
%  \begin{function}{%
%                   \clist_map_function_aux:Nw |
%                   \clist_map_inline_aux:Nw |
%                   \clist_map_variable_aux:Nnw |
%  }
%  \begin{syntax}\end{syntax}
%  Internal helper functions for the <clist> mapping functions.
%  \end{function}
%
%
%  \begin{function}{%
%                   \clist_concat_aux:NNNN |
%                   \clist_remove_duplicates_aux:NN |
%                   \clist_remove_duplicates_aux:n |
%                   \l_clist_remove_duplicates_clist |
%  }
%  \begin{syntax}\end{syntax}
%  Functions that help concatenate <clist>s and remove duplicate
%  elements from a <clist>.
%  \end{function}
%
%
%
% \subsection{Comma list Stacks}
%
% Special comma-lists in \LaTeX3 are `stacks' with their usual operations
% of `push', `pop', and `top'. They are internally implemented as
% comma-lists and share some of the functions (like "\clist_new:N" etc.)
%
%
% \begin{function}{%
%                  \clist_push:Nn |
%                  \clist_push:No |
%                  \clist_push:cn |
%                  \clist_gpush:Nn |
%                  \clist_gpush:No |
%                  \clist_gpush:cn |
% }
% \begin{syntax}
%   "\clist_push:Nn" <stack> "{" <token list> "}"
% \end{syntax}
% Locally or globally pushes <token list> as a single item onto the
% <stack>. <token list> might get expanded before the operation.
% \end{function}
%
% \begin{function}{%
%                  \clist_pop:NN |
%                  \clist_pop:cN |
%                  \clist_gpop:NN |
%                  \clist_gpop:cN |
% }
% \begin{syntax}
%    "\clist_pop:NN" <stack> <tlp>
% \end{syntax}
% Functions that assign the top item of <stack> to the token
% list pointer <tlp> and removes it from <stack>!
% \end{function}
%
% \begin{function}{%
%                  \clist_top:NN |
%                  \clist_top:cN |
% }
% \begin{syntax}
%    "\clist_top:NN" <stack> <tlp>
% \end{syntax}
% Functions that locally assign the top item of <stack> to the token
% list pointer <tlp>. Item is not removed from <stack>!
% \end{function}
%
% \StopEventually{}
%
% Use "clist" functions.
%
%
% \subsection {The Implementation}
%
%    We start by ensuring that the required packages are loaded.
%    \begin{macrocode}
%<package>\ProvidesExplPackage
%<package>  {\filename}{\filedate}{\fileversion}{\filedescription}
%<*package>
\NeedsTeXFormat{LaTeX2e}
%<!check>\RequirePackage{l3prg,l3quark}
%<check>\RequirePackage{l3chk}
%</package>
%<*initex|package>
%    \end{macrocode}
%
%
% \begin{macro}{\clist_new:N}
% \begin{macro}{\clist_new:c}
%    Comma-Lists are implemented using token lists.
%    \begin{macrocode}
\def_new:Npn \clist_new:N #1{\tlp_new:Nn #1{}}
\def_new:Npn \clist_new:c {\exp_args:Nc \clist_new:N}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_clear:N}
% \begin{macro}{\clist_clear:c}
% \begin{macro}{\clist_gclear:N}
% \begin{macro}{\clist_gclear:c}
%    Clearing a comma-list is the same as clearing a token list.
%    \begin{macrocode}
\let_new:NN \clist_clear:N \tlp_clear:N
\let_new:NN \clist_clear:c \tlp_clear:c
\let_new:NN \clist_gclear:N \tlp_gclear:N
\let_new:NN \clist_gclear:c \tlp_gclear:c
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\clist_set_eq:NN}
%    We can set one \meta{clist} equal to another.
%    \begin{macrocode}
\let_new:NN \clist_set_eq:NN \let:NN
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\clist_set_eq:NN}
% \begin{macro}{\clist_set_eq:cN}
% \begin{macro}{\clist_set_eq:Nc}
% \begin{macro}{\clist_set_eq:cc}
%    An of course globally which seems to be needed far more often.
%    \begin{macrocode}
\let_new:NN \clist_gset_eq:NN \glet:NN
\def_new:Npn \clist_gset_eq:cN {\exp_args:Nc \clist_gset_eq:NN}
\def_new:Npn \clist_gset_eq:Nc {\exp_args:NNc \clist_gset_eq:NN}
\def_new:Npn \clist_gset_eq:cc {\exp_args:Ncc \clist_gset_eq:NN}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\clist_if_empty_p:N}
%    A predicate which evaluates to |\c_true| iff the comma-list is empty.
%    \begin{macrocode}
\let_new:NN \clist_if_empty_p:N \tlp_if_empty_p:N
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\clist_if_empty:NTF}
% \begin{macro}{\clist_if_empty:NT}
% \begin{macro}{\clist_if_empty:NF}
% \begin{macro}{\clist_if_empty:cTF}
% \begin{macro}{\clist_if_empty:cT}
% \begin{macro}{\clist_if_empty:cF}
%    |\clist_if_empty:NTF|\m{clist}\m{true~case}\m{false~case} will check
%    whether the \m{clist} is empty and then select one of the other
%    arguments. |\clist_if_empty:cTF| turns its first argument into a
%    control comma-list to get the name of the comma-list.
%    \begin{macrocode}
\def_test_function_new:npn {clist_if_empty:N}#1{\if_meaning:NN#1\c_empty_tlp}
\def_new:Npn \clist_if_empty:cTF {\exp_args:Nc\clist_if_empty:NTF}
\def_new:Npn \clist_if_empty:cT {\exp_args:Nc\clist_if_empty:NT}
\def_new:Npn \clist_if_empty:cF {\exp_args:Nc\clist_if_empty:NF}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\clist_if_empty_err:N}
%   Signals an error if the comma-list is empty.
%    \begin{macrocode}
\def_new:Npn \clist_if_empty_err:N #1{
  \if_meaning:NN#1\c_empty_tlp
    \tlp_clear:N \l_testa_tlp % catch prefixes
    \err_latex_bug:x{Empty~comma-list~`\token_to_string:N#1'}
  \fi:}
%    \end{macrocode}
% \end{macro}
%
%  \begin{macro}{\clist_if_eq:NNTF}
%  As comma lists are token list pointers internally this is just an
%  alias.
%    \begin{macrocode}
\let_new:NN \clist_if_eq:NNTF \tlp_if_eq:NNTF
%    \end{macrocode}
%  \end{macro}
%
% \begin{macro}{\clist_get:NN}
% \begin{macro}{\clist_get:cN}
%    |\clist_get:NN |\zz{comma-list}\zz{cmd} defines \zz{cmd} to be the
%    left-most element of \zz{comma-list}.
%    \begin{macrocode}
\def_new:Npn \clist_get:NN #1{
  \clist_if_empty_err:N #1
  \exp_after:NN\clist_get_aux:w #1,\q_stop}
%    \end{macrocode}
%    \begin{macrocode}
\def_new:Npn \clist_get_aux:w  #1,#2\q_stop #3{\tlp_set:Nn #3{#1}}
%    \end{macrocode}
%    \begin{macrocode}
\def_new:Npn \clist_get:cN {\exp_args:Nc \clist_get:NN}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_pop_aux:nnNN}
% \begin{macro}{\clist_pop_aux:w}
% \begin{macro}{\clist_pop_auxi:w}
%    |\clist_pop_aux:nnNN| \zz{def$\sb1$} \zz{def$\sb2$} \zz{comma-list}
%    \zz{cmd} assigns the left-most element of \zz{comma-list} to
%    \zz{cmd} using \zz{def$\sb2$}, and assigns the tail of
%    \zz{comma-list} to \zz{comma-list} using \zz{def$\sb1$}.
%    \begin{macrocode}
\def_new:Npn \clist_pop_aux:nnNN #1#2#3{
  \clist_if_empty_err:N #3
  \exp_after:NN\clist_pop_aux:w #3,\q_nil\q_stop #1#2#3}
%    \end{macrocode}
%    \begin{macrocode}
\def_new:Npn \clist_pop_aux:w  #1,#2\q_stop #3#4#5#6{
   #4#6{#1}
   #3#5{#2}
%    \end{macrocode}
% If there was only one element in the original clist, it now contains
% only |\q_nil|.
%    \begin{macrocode}
   \quark_if_nil:NTF #5
   { #3#5{} }
   { \clist_pop_auxi:w #2 #3#5 }
}
%    \end{macrocode}
%    \begin{macrocode}
\def_new:Npn\clist_pop_auxi:w #1,\q_nil #2#3  {#2#3{#1}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_put_aux:NNnnNn}
%    The generic put function.
%    \begin{macrocode}
\def_new:Npn \clist_put_aux:NNnnNn #1#2#3#4#5#6{
%    \end{macrocode}
%    When adding we have to distinguish between an empty \meta{clist}
%    and one that contains at least one item (otherwise we accumulate
%    commas).
%    \begin{macrocode}
  \clist_if_empty:NTF#5 {#1 #5{#6}}
%    \end{macrocode}
% MH says: Perhaps we should make sure that empty arguments don't get
% on the stack as that is probably a mistake. That's what I've
% implemented here. Since |\tlist_if_empty:nF| is expandable prefixes
% are still allowed.
%    \begin{macrocode}
  { \tlist_if_empty:nF {#6}{ #2 #5{#3#6#4} } }
}
%    \end{macrocode}
% \end{macro}
% \begin{macro}{\clist_put_left:Nn}
% \begin{macro}{\clist_put_left:No}
% \begin{macro}{\clist_put_left:Nx}
% \begin{macro}{\clist_put_left:cn}
%    The operations for adding to the left.
%    \begin{macrocode}
\def_new:Npn \clist_put_left:Nn {
  \clist_put_aux:NNnnNn \tlp_set:Nn \tlp_put_left:Nn {} ,
}
\def_new:Npn \clist_put_left:cn {\exp_args:Nc \clist_put_left:Nn}
\def_new:Npn \clist_put_left:No {\exp_args:NNo\clist_put_left:Nn}
\def_new:Npn \clist_put_left:Nx {\exp_args:Nnx\clist_put_left:Nn}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \begin{macro}{\clist_gput_left:Nn}
% Global versions.
%    \begin{macrocode}
\def_new:Npn \clist_gput_left:Nn {
  \clist_put_aux:NNnnNn \tlp_gset:Nn \tlp_gput_left:Nn {} ,
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\clist_put_right:Nn}
% \begin{macro}{\clist_put_right:cn}
% \begin{macro}{\clist_put_right:No}
% \begin{macro}{\clist_put_right:Nx}
%  Adding something to the right side is almost the same.
%    \begin{macrocode}
\def_new:Npn \clist_put_right:Nn {
  \clist_put_aux:NNnnNn \tlp_set:Nn \tlp_put_right:Nn , {}
}
\def_new:Npn \clist_put_right:cn {\exp_args:Nc \clist_put_right:Nn}
\def_new:Npn \clist_put_right:No {\exp_args:Nno\clist_put_right:Nn}
\def_new:Npn \clist_put_right:Nx {\exp_args:Nnx\clist_put_right:Nn}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_gput_right:Nn}
% \begin{macro}{\clist_gput_right:No}
% \begin{macro}{\clist_gput_right:cn}
% \begin{macro}{\clist_gput_right:co}
% \begin{macro}{\clist_gput_right:cc}
% \begin{macro}{\clist_gput_right:NC}
%    An here the global variants.
%    \begin{macrocode}
\def_new:Npn \clist_gput_right:Nn {
  \clist_put_aux:NNnnNn \tlp_gset:Nn \tlp_gput_right:Nn , {}
}
\def_new:Npn \clist_gput_right:No {\exp_args:NNo \clist_gput_right:Nn}
\def_new:Npn \clist_gput_right:cn {\exp_args:Nc  \clist_gput_right:Nn}
\def_new:Npn \clist_gput_right:co {\exp_args:Nco \clist_gput_right:Nn}
\def_new:Npn \clist_gput_right:cc {\exp_args:Ncc \clist_gput_right:Nn}
%    \end{macrocode}
%    \begin{macrocode}
\def_new:Npn \clist_gput_right:NC {\exp_args:NNC \clist_gput_right:Nn}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_map_function:nN}
% \begin{macro}{\clist_map_function:cN}
% \begin{macro}{\clist_map_function:NN}
%    |\clist_map_function:NN| \zz{comma-list} \zz{cmd} applies \zz{cmd} to each
%    element of \zz{comma-list}, from left to right.
%    \begin{macrocode}
\def_new:Npn \clist_map_function:NN #1#2{
  \clist_if_empty:NF #1
  {
    \exp_after:NN \clist_map_function_aux:Nw
    \exp_after:NN #2 #1 , \q_recursion_tail , \q_recursion_stop 
  }
}
\def_new:Npn \clist_map_function:cN{\exp_args:Nc\clist_map_function:NN}
\def_new:Npn \clist_map_function:nN #1#2{
  \tlist_if_blank:nF {#1}
  { \clist_map_function_aux:Nw #2 #1 , \q_recursion_tail , \q_recursion_stop }
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_map_function_aux:Nw}
%  The general loop. Tests if we hit the first stop marker and exits if
%  we did. If we didn't, place the function "#1" in front of the
%  element "#2", which is surrounded by braces.
%    \begin{macrocode}
\def_long_new:Npn \clist_map_function_aux:Nw #1#2,{
  \quark_if_recursion_tail_stop:n{#2} 
  #1{#2}
  \clist_map_function_aux:Nw #1
}
%    \end{macrocode}
% \end{macro}
%
%  \begin{macro}{\clist_map_break:w}
%    The break statement is easy. Same as in other modules, gobble
%    everything up to the special recursion stop marker.
%    \begin{macrocode}
\let_new:NN \clist_map_break:w \use_none_delimit_by_q_recursion_stop:w
%    \end{macrocode}
%  \end{macro}
%
% \begin{macro}{\clist_map_inline:Nn}
% \begin{macro}{\clist_map_inline:cn}
% \begin{macro}{\clist_map_inline:nn}
%   The inline type is faster but not expandable. In order to make it
%   nestable, we use a counter to keep track of the nesting level so
%   that all of the functions called have distict names. A simpler
%   approach would of course be to use grouping and thus the save
%   stack but then you lose the ability to do things locally.
%
%   A funny little thing occured in one document: The command setting
%   up the first call of |\clist_map_inline:Nn| was used in a tabular
%   cell and the inline code used |\\| so the loop broke as soon as
%   this happened. Lesson to be learned from this: If you wish to have
%   group like structure but not using the groupings of \TeX, then do
%   every operation globally.
%    \begin{macrocode}
\int_new:N \g_clist_inline_level_int
\def_long_new:Npn \clist_map_inline:Nn #1#2{
  \clist_if_empty:NF #1
  {
    \int_gincr:N \g_clist_inline_level_int
    \gdef_long:cpn {clist_map_inline_ \int_use:N \g_clist_inline_level_int :n} 
    ##1{#2}
%    \end{macrocode}
% Recall that the |E| in |\exp_args:NcE| means `single token expanded
% once and no braces added'. It is a lot more efficient to carry over
% the special function rather than constructing the same csname over
% and over again, so we just do it once. We reuse
% |\clist_map_function_aux:Nw| for the actual loop.
%    \begin{macrocode}
    \exp_args:NcE \clist_map_function_aux:Nw 
    {clist_map_inline_ \int_use:N \g_clist_inline_level_int :n}
    #1 , \q_recursion_tail , \q_recursion_stop 
    \int_gdecr:N \g_clist_inline_level_int
  }
}
\def_new:Npn \clist_map_inline:cn{\exp_args:Nc\clist_map_inline:Nn}
\def_long_new:Npn \clist_map_inline:nn #1#2{
  \tlist_if_empty:nF {#1}
  {
    \int_gincr:N \g_clist_inline_level_int
    \gdef_long:cpn {clist_map_inline_ \int_use:N \g_clist_inline_level_int :n} 
    ##1{#2}
    \exp_args:Nc \clist_map_function_aux:Nw 
    {clist_map_inline_ \int_use:N \g_clist_inline_level_int :n} 
    #1 , \q_recursion_tail , \q_recursion_stop 
    \int_gdecr:N \g_clist_inline_level_int
  }
}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\clist_map_variable:nNn}
% \begin{macro}{\clist_map_variable:NNn}
% \begin{macro}{\clist_map_variable:cNn}
%    |\clist_map:NNn| \zz{comma-list} \zz{temp} \zz{action} assigns
%    \zz{temp} to each element and executes \zz{action}.
%    \begin{macrocode}
\def_new:Npn \clist_map_variable:nNn #1#2#3{
  \tlist_if_empty:nF{#1}
  {
    \clist_map_variable_aux:Nnw #2 {#3} #1 
    , \q_recursion_tail , \q_recursion_stop
  }
}
\def_new:Npn \clist_map_variable:NNn {\exp_args:No \clist_map_variable:nNn}
\def_new:Npn \clist_map_variable:cNn {\exp_args:Nc \clist_map_variable:NNn}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_map_variable_aux:Nnw}
%  The general loop. Assign the temp variable |#1| to the current item
%  |#3| and then check if that's the stop marker. If it is, break the
%  loop. If not, execute the action |#2| and continue.
%    \begin{macrocode}
\def_new:Npn \clist_map_variable_aux:Nnw #1#2#3,{
  \def:Npn #1{#3}
  \quark_if_recursion_tail_stop:N #1 
  #2 \clist_map_variable_aux:Nnw #1{#2}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\clist_concat_aux:NNNN}
% \begin{macro}{\clist_concat:NNN}
% \begin{macro}{\clist_gconcat:NNN}
% \begin{macro}{\clist_gconcat:NNc}
% \begin{macro}{\clist_gconcat:ccc}
%    |\clist_gconcat:NNN| \m{clist~1} \m{clist~2} \m{clist~3} will globally
%    assign \m{clist~1} the concatenation of \m{clist~2} and
%    \m{clist~3}.
%    \begin{macrocode}
\def_new:Npn \clist_concat_aux:NNNN #1#2#3#4{
  \toks_set:No \l_tmpa_toks {#3}
  \toks_set:No \l_tmpb_toks {#4}
  #1 #2 {
    \toks_use:N \l_tmpa_toks
%    \end{macrocode}
%    Again the situation is a bit more complicated because of the use
%    of commas between items, so if either list is empty we have to avoid
%    adding a comma.
%    \begin{macrocode}
    \toks_if_empty:NF \l_tmpa_toks {\toks_if_empty:NF \l_tmpb_toks ,}
    \toks_use:N \l_tmpb_toks
  }
}
\def_new:Npn \clist_concat:NNN {\clist_concat_aux:NNNN \tlp_set:Nx}
\def_new:Npn \clist_gconcat:NNN {\clist_concat_aux:NNNN \tlp_gset:Nx}
%    \end{macrocode}
%  And the usual versions.
%    \begin{macrocode}
\def_new:Npn \clist_gconcat:NNc{\exp_args:Nnnc\clist_gconcat:NNN}
\def_new:Npn \clist_gconcat:ccc{\exp_args:Nccc\clist_gconcat:NNN}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
%  \begin{macro}{\clist_remove_duplicates_aux:NN}
%  \begin{macro}{\clist_remove_duplicates_aux:n}
%  \begin{macro}{\clist_remove_duplicates:N}
%  \begin{macro}{\clist_gremove_duplicates:N}
%  Removing duplicate entries in a \meta{clist} is fairly straight
%  forward. We use a temporary variable and then go through the list
%  from left to right. For each element check if the element is
%  already present in the list.
%    \begin{macrocode}
\def:Npn \clist_remove_duplicates_aux:NN #1#2 {
  \clist_clear:N \l_clist_remove_duplicates_clist
  \clist_map_function:NN #2 \clist_remove_duplicates_aux:n
  #1 #2 \l_clist_remove_duplicates_clist
}
\def:Npn \clist_remove_duplicates_aux:n #1 {
  \clist_if_in:NnTF \l_clist_remove_duplicates_clist {#1} {}
  {\clist_put_right:Nn \l_clist_remove_duplicates_clist {#1}}
}
%    \end{macrocode}
%  The high level functions are just for telling if it should be a
%  local or global setting.
%    \begin{macrocode}
\def_new:Npn \clist_remove_duplicates:N {
  \clist_remove_duplicates_aux:NN \clist_set_eq:NN
}
\def_new:Npn \clist_gremove_duplicates:N {
  \clist_remove_duplicates_aux:NN \clist_gset_eq:NN
}
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%  \end{macro}
%  \end{macro}
%
%  \begin{macro}{\l_clist_remove_duplicates_clist}
%    \begin{macrocode}
\clist_new:N \l_clist_remove_duplicates_clist
%    \end{macrocode}
%  \end{macro}
%
% \begin{macro}{\clist_use:N}
% \begin{macro}{\clist_use:c}
% Using a \meta{clist} is just executing it but\dots
%    \begin{macrocode}
\def_new:Npn \clist_use:N #1 {
  \if_meaning:NN #1 \scan_stop:
%    \end{macrocode}
%  \dots\ if \m{clist} equals |\scan_stop:| it is probably stemming
%  from a |\cs:w ... \cs_end:| that was created by mistake somewhere.
%    \begin{macrocode}
    \err_latex_bug:x {Comma~list~ `\token_to_string:N #1'~
                      has~ an~ erroneous~ structure!}
  \else:
    \exp_after:NN #1
  \fi:
}
\def_new:Npn \clist_use:c {\exp_args:Nc \clist_use:N}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\clist_if_in:NnTF}
% \begin{macro}{\clist_if_in:NoTF}
% \begin{macro}{\clist_if_in:cnTF}
% \begin{macro}{\clist_if_in:coTF}
%    |\clist_if_in:NnTF| \m{clist}\m{item} \m{true~case} \m{false~case}
%    will check whether \m{item} is in \m{clist} and then either execute
%    the \m{true~case} or the \m{false~case}. \m{true~case} and
%    \m{false~case} may contain incomplete |\if_charcode:w|
%    statements.
%    \begin{macrocode}
\def_new:Npn \clist_if_in:NnTF #1#2{
  \def:Npn \tmp:w ##1 ,#2, ##2##3\q_stop{
    \if_meaning:NN\q_no_value##2
      \exp_after:NN\use_arg_ii:nn
    \else:
      \exp_after:NN\use_arg_i:nn
    \fi:
  }
  \exp_after:NN \tmp:w
  \exp_after:NN , #1, #2, \q_no_value \q_stop
}
\def_new:Npn \clist_if_in:NoTF {\exp_args:NNo \clist_if_in:NnTF}
\def_new:Npn \clist_if_in:coTF {\exp_args:Nco \clist_if_in:NnTF}
\def_new:Npn \clist_if_in:cnTF {\exp_args:Nc \clist_if_in:NnTF}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
%
% \subsubsection{Stack operations}
%
% We build stacks from comma-lists,  but here we put the
% specific functions together.
%
%
% \begin{macro}{\clist_push:Nn}
% \begin{macro}{\clist_push:No}
% \begin{macro}{\clist_push:cn}
% \begin{macro}{\clist_pop:NN}
% \begin{macro}{\clist_pop:cN}
%    Since comma-lists can be used as stacks, we ought to have both
%    `push' and `pop'. In most cases they are nothing more then new
%    names for old functions.
%    \begin{macrocode}
\let_new:NN \clist_push:Nn \clist_put_left:Nn
\let_new:NN \clist_push:No \clist_put_left:No
\let_new:NN \clist_push:cn \clist_put_left:cn
\def_new:Npn \clist_pop:NN {\clist_pop_aux:nnNN \tlp_set:Nn \tlp_set:Nn}
\def_new:Npn \clist_pop:cN {\exp_args:Nc \clist_pop:NN}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
%
% \begin{macro}{\clist_gpush:Nn}
% \begin{macro}{\clist_gpush:No}
% \begin{macro}{\clist_gpush:cn}
% \begin{macro}{\clist_gpop:NN}
% \begin{macro}{\clist_gpop:cN}
%    I don't agree with Denys that one needs only local stacks,
%    actually I believe that one will probably need the functions
%    here more often. In case of |\clist_gpop:NN| the value is
%    nevertheless returned locally.
%    \begin{macrocode}
\let_new:NN \clist_gpush:Nn \clist_gput_left:Nn
\def_new:Npn \clist_gpush:No {\exp_args:NNo \clist_gpush:Nn}
\def_new:Npn \clist_gpush:cn {\exp_args:Nc \clist_gpush:Nn}
\def_new:Npn \clist_gpop:NN {\clist_pop_aux:nnNN \tlp_gset:Nn \tlp_set:Nn}
\def_new:Npn \clist_gpop:cN {\exp_args:Nc \clist_gpop:NN}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\clist_top:NN}
% \begin{macro}{\clist_top:cN}
%    Looking at the top element of the stack without removing it is
%    done with this operation.
%    \begin{macrocode}
\let_new:NN \clist_top:NN \clist_get:NN
\let_new:NN \clist_top:cN \clist_get:cN
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
%    Show token usage:
%    \begin{macrocode}
%</initex|package>
%<*showmemory>
%\showMemUsage
%</showmemory>
%    \end{macrocode}
%
%
%
% \endinput
%
%  $Log$
%  Revision 1.16  2006/07/30 15:45:46  morten
%  Made \clist_map_inline:Nn and variants nestable plus a little cleanup.
%
%  Revision 1.15  2006/03/20 18:26:34  braams
%  Updated the copyright notice (2006) and demoted all implementation
%  sections to subsections and so on to clean up the toc for source3.tex
%
%  Revision 1.14  2006/01/04 01:32:09  morten
%  Minor changes to code to reflect changes in l3tlp.
%
%  Revision 1.13  2005/12/27 09:52:51  morten
%  Minor changes plus changed RCS information retrieval
%
%  Revision 1.12  2005/10/27 23:14:49  morten
%  Improved loops.
%
%  Revision 1.11  2005/04/12 16:45:22  morten
%  Enabled put operations. Added function that removes duplicate entries (mostly for
%   use after concatenating to clists)
%
%  Revision 1.10  2005/04/12 13:22:13  morten
%  Mostly cosmetic changes. \clist_gconcat:NNN reprogrammed using "proper" methods, \clist_put_right:Nn likewise.
%
%  Revision 1.9  2005/03/22 23:26:54  morten
%  Fix error message
%
%  Revision 1.8  2005/03/16 22:36:43  braams
%  Added the tweaks necessary to be able to load with initex
%
%  Revision 1.7  2005/03/11 21:36:36  braams
%  Fixed the use of RCS information;
%  Fixed a few documentation typos; added \StopEventually
%  Replaced \ifx by \if_meaning:NN, \c_if_empty_toks became \c_empty_toks
%  but needs further work according to Morten
%
