summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expl3/l3clist.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2007-05-22 17:46:23 +0000
committerKarl Berry <karl@freefriends.org>2007-05-22 17:46:23 +0000
commitf4eb27d3314d15838f674a3872000159d029f88b (patch)
tree6e9ab33c5a2d702912b4a969ade4e4e2ac586d62 /Master/texmf-dist/source/latex/expl3/l3clist.dtx
parent14af3f447439750920f754792b89f113d019076a (diff)
update expl3
git-svn-id: svn://tug.org/texlive/trunk@4335 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3clist.dtx')
-rw-r--r--Master/texmf-dist/source/latex/expl3/l3clist.dtx1082
1 files changed, 1082 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3clist.dtx b/Master/texmf-dist/source/latex/expl3/l3clist.dtx
new file mode 100644
index 00000000000..f8fdba275bb
--- /dev/null
+++ b/Master/texmf-dist/source/latex/expl3/l3clist.dtx
@@ -0,0 +1,1082 @@
+% \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.
+%%
+%% -----------------------------------------------------------------------
+%
+%<package>\RequirePackage{l3names}
+%<*dtx>
+%\fi
+\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{%
+ \def\fileversion{#2}%
+ \def\filedate{#3/#4/#5}%
+ \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]%
+}
+%\iffalse
+%</dtx>
+%\fi
+\GetIdInfo$Id: l3clist.dtx 573 2006-08-21 20:59:37Z morten $
+ {L3 Experimental comma separated lists}
+%
+% \iffalse
+%<*driver>
+\documentclass{l3doc}
+\begin{document}
+\DocInput{l3clist.dtx}
+\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>
+\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_set:Nn \tlp_put_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_nil , \q_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_empty:nF {#1}
+ { \clist_map_function_aux:Nw #2 #1 , \q_nil , \q_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_new:Npn \clist_map_function_aux:Nw #1#2,{
+ \quark_if_nil:nT{#2} \clist_map_break:w
+ #1{#2}
+ \clist_map_function_aux:Nw #1
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\clist_map_break:w}
+% The break statement is easy: Just gobble everything op to the last
+% of the two stop markers "\q_stop" waiting at the end and close the
+% "\if_..." we're in. Technically this should get an "w" specifier,
+% but it doesn't take any arguments when you call it -- at least not
+% any you would expect.
+% \begin{macrocode}
+\let_new:NN \clist_map_break:w \use_none_delimit_by_q_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.
+% \begin{macrocode}
+\int_new:N \l_clist_inline_level_int
+\def_new:Npn \clist_map_inline:Nn #1#2{
+ \clist_if_empty:NF #1
+ {
+ \int_incr:N \l_clist_inline_level_int
+ \def:cpn {clist_map_inline_ \int_use:N \l_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 \l_clist_inline_level_int :n}
+ #1 , \q_nil , \q_stop
+ \int_decr:N \l_clist_inline_level_int
+ }
+}
+\def_new:Npn \clist_map_inline:cn{\exp_args:Nc\clist_map_inline:Nn}
+\def_new:Npn \clist_map_inline:nn #1#2{
+ \tlist_if_empty:nF {#1}
+ {
+ \int_incr:N \l_clist_inline_level_int
+ \def:cpn {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n}
+ ##1{#2}
+ \exp_args:Nc \clist_map_function_aux:Nw
+ {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n}
+ #1 , \q_nil , \q_stop
+ \int_decr:N \l_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_nil , \q_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_nil:NT #1 \clist_map_break:w
+ #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 ... \cd_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
+%