diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3clist.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3clist.dtx | 1437 |
1 files changed, 1437 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx new file mode 100644 index 00000000000..d031b15f552 --- /dev/null +++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx @@ -0,0 +1,1437 @@ +% \iffalse meta-comment +% +%% File: l3clist.dtx Copyright (C) 2004-2011 Frank Mittelbach, +%% The LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the "expl3 bundle" (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/svnroot/experimental/trunk/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX3 Project. +%% +%% ----------------------------------------------------------------------- +% +%<*driver|package> +\RequirePackage{l3names} +\GetIdInfo$Id: l3clist.dtx 2498 2011-07-09 17:51:47Z joseph $ + {L3 Experimental comma separated lists} +%</driver|package> +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3clist} package\\ Comma separated lists^^A +% \thanks{This file describes v\ExplFileVersion, +% last revised \ExplFileDate.}^^A +% } +% +% \author{^^A +% The \LaTeX3 Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released \ExplFileDate} +% +% \maketitle +% +% \begin{documentation} +% +% Comma lists contain ordered data where items can be added to the left +% or right end of the sequence. This gives an ordered list which can +% then be utilised with the \cs{clist_map_function:NN} function. Comma +% Comma lists cannot contain empty items, thus +% \begin{verbatim} +% \clist_new:N \l_my_clist +% \clist_put_right:Nn \l_my_clist { } +% \clist_if_empty:NTF \l_my_clist { true } { false } +% \end{verbatim} +% will leave \texttt{true} in the input stream. +% +% \section{Creating and initialising comma lists} +% +% \begin{function}{\clist_new:N, \clist_new:c} +% \begin{syntax} +% \cs{clist_new:N} \meta{comma list} +% \end{syntax} +% Creates a new \meta{comma list} or raises an error if the name is +% already taken. The declaration is global. The \meta{comma list} will +% initially contain no items. +% \end{function} +% +% \begin{function}{\clist_clear:N, \clist_clear:c} +% \begin{syntax} +% \cs{clist_clear:N} \meta{comma list} +% \end{syntax} +% Clears all items from the \meta{comma list} within the scope of +% the current \TeX{} group. +% \end{function} +% +% \begin{function}{\clist_gclear:N, \clist_gclear:c} +% \begin{syntax} +% \cs{clist_gclear:N} \meta{comma list} +% \end{syntax} +% Clears all entries from the \meta{comma list} globally. +% \end{function} +% +% \begin{function}{\clist_clear_new:N, \clist_clear_new:c} +% \begin{syntax} +% \cs{clist_clear_new:N} \meta{comma list} +% \end{syntax} +% If the \meta{comma list} already exists, clears it within the scope +% of the current \TeX{} group. If the \meta{comma list} is not defined, +% it will be created (using \cs{clist_new:N}). Thus the comma list is +% guaranteed to be available and clear within the current \TeX{} +% group. The \meta{comma list} will exist globally, but the content +% outside of the current \TeX{} group is not specified. +% \end{function} +% +% \begin{function}{\clist_gclear_new:N, \clist_gclear_new:c} +% \begin{syntax} +% \cs{clist_gclear_new:N} \meta{comma list} +% \end{syntax} +% If the \meta{comma list} already exists, clears it globally. If the +% \meta{comma list} is not defined, it will be created (using +% \cs{clist_new:N}). Thus the comma list is guaranteed to be available +% and globally clear. +% \end{function} +% +% \begin{function} +% {\clist_set_eq:NN, \clist_set_eq:cN, \clist_set_eq:Nc, \clist_set_eq:cc} +% \begin{syntax} +% \cs{clist_set_eq:NN} \meta{comma list1} \meta{comma list2} +% \end{syntax} +% Sets the content of \meta{comma list1} equal to that of +% \meta{comma list2}. This assignment is restricted to the current +% \TeX{} group level. +% \end{function} +% +% \begin{function} +% { +% \clist_gset_eq:NN, \clist_gset_eq:cN, +% \clist_gset_eq:Nc, \clist_gset_eq:cc +% } +% \begin{syntax} +% \cs{clist_gset_eq:NN} \meta{comma list1} \meta{comma list2} +% \end{syntax} +% Sets the content of \meta{comma list1} equal to that of +% \meta{comma list2}. This assignment is global and so is not +% limited by the current \TeX{} group level. +% \end{function} +% +% \begin{function}{\clist_concat:NNN, \clist_concat:ccc} +% \begin{syntax} +% \cs{clist_concat:NNN} \meta{comma list1} \meta{comma list2} +% ~~\meta{comma list3} +% \end{syntax} +% Concatenates the content of \meta{comma list2} and \meta{comma list3} +% together and saves the result in \meta{comma list1}. The items in +% \meta{comma list2} will be placed at the left side of the new comma list. +% This operation is local to the current \TeX{} group and will +% remove any existing content in \meta{comma list1}. +% \end{function} +% +% \begin{function}{\clist_gconcat:NNN, \clist_gconcat:ccc} +% \begin{syntax} +% \cs{clist_gconcat:NNN} \meta{comma list1} \meta{comma list2} +% ~~\meta{comma list3} +% \end{syntax} +% Concatenates the content of \meta{comma list2} and \meta{comma list3} +% together and saves the result in \meta{comma list1}. The items in +% \meta{comma list2} will be placed at the left side of the new comma list. +% This operation is global and will remove any existing content in +% \meta{comma list1}. +% \end{function} +% +% \section{Appending items to comma lists} +% +% \begin{function}{ +% \clist_put_left:Nn, \clist_put_left:NV, +% \clist_put_left:No, \clist_put_left:Nx, +% \clist_put_left:cn, \clist_put_left:cV, +% \clist_put_left:co, \clist_put_left:cx +% } +% \begin{syntax} +% \cs{clist_put_left:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the left of the \meta{comma list}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{ +% \clist_gput_left:Nn, \clist_gput_left:NV, +% \clist_gput_left:No, \clist_gput_left:Nx, +% \clist_gput_left:cn, \clist_gput_left:cV, +% \clist_gput_left:co, \clist_gput_left:cx +% } +% \begin{syntax} +% \cs{clist_gput_left:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the left of the \meta{comma list}. +% The assignment is global. +% \end{function} +% +% \begin{function}{ +% \clist_put_right:Nn, \clist_put_right:NV, +% \clist_put_right:No, \clist_put_right:Nx, +% \clist_put_right:cn, \clist_put_right:cV, +% \clist_put_right:co, \clist_put_right:cx +% } +% \begin{syntax} +% \cs{clist_put_right:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the right of the \meta{comma list}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{ +% \clist_gput_right:Nn, \clist_gput_right:NV, +% \clist_gput_right:No, \clist_gput_right:Nx, +% \clist_gput_right:cn, \clist_gput_right:cV, +% \clist_gput_right:co, \clist_gput_right:cx +% } +% \begin{syntax} +% \cs{clist_gput_right:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Appends the \meta{item} to the right of the \meta{comma list}. +% The assignment is global. +% \end{function} +% +% \section{Comma lists as stacks} +% +% \begin{function}{\clist_get:NN, \clist_get:cN} +% \begin{syntax} +% \cs{clist_get:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Stores the left-most item from a \meta{comma list} in the +% \meta{token list variable} without removing it from the +% \meta{comma list}. The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}{\clist_get:NN, \clist_get:cN} +% \begin{syntax} +% \cs{clist_get:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Stores the right-most item from a \meta{comma list} in the +% \meta{token list variable} without removing it from the +% \meta{comma list}. The \meta{token list variable} is assigned locally. +% \end{function} +% +% \begin{function}{\clist_pop:NN, \clist_pop:cN} +% \begin{syntax} +% \cs{clist_pop:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Pops the left-most item from a \meta{comma list} into the +% \meta{token list variable}, \emph{i.e.}~removes the item from the +% comma list and stores it in the \meta{token list variable}. +% Both of the variables are assigned locally. +% \end{function} +% +% \begin{function}{\clist_gpop:NN, \clist_gpop:cN} +% \begin{syntax} +% \cs{clist_gpop:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Pops the left-most item from a \meta{comma list} into the +% \meta{token list variable}, \emph{i.e.}~removes the item from the +% comma list and stores it in the \meta{token list variable}. +% The \meta{comma list} is modified globally, while the assignment of +% the \meta{token list variable} is local. +% \end{function} +% +% \begin{function} +% { +% \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, +% \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx +% } +% \begin{syntax} +% \cs{clist_push:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Adds the \Arg{item} to the top of the \meta{comma list}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function} +% { +% \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, \clist_gpush:Nx, +% \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx +% } +% \begin{syntax} +% \cs{clist_gpush:Nn} \meta{sequence} \Arg{item} +% \end{syntax} +% Pushes the \meta{item} onto the end of the top of the +% \meta{comma list}. The assignment is global. +% \end{function} +% +% \section{Using comma lists} +% +% \begin{function}[EXP]{\clist_use:N, \clist_use:c} +% \begin{syntax} +% \cs{clist_use:N} \meta{comma list} +% \end{syntax} +% Places the \meta{comma list} directly into the input stream, thus +% treating it as a \meta{token list}. +% \end{function} +% +% \section{Modifying comma lists} +% +% While comma lists are normally used as ordered lists, it may be +% necessary to modify the content. The functions here may be used +% to update comma lists, while retaining the order of the unaffected +% entries. +% +% \begin{function}{\clist_remove_duplicates:N, \clist_remove_duplicates:c} +% \begin{syntax} +% \cs{clist_remove_duplicates:N} \meta{comma list} +% \end{syntax} +% Removes duplicate items from the \meta{comma list}, leaving the +% left most copy of each item in the \meta{comma list}. The \meta{item} +% comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}. +% The removal is local to the current \TeX{} group. +% \begin{texnote} +% This function iterates through every item in the \meta{comma list} and +% does a comparison with the \meta{items} already checked. It is therefore +% relatively slow with large comma lists. +% \end{texnote} +% \end{function} +% +% \begin{function}{\clist_gremove_duplicates:N, \clist_gremove_duplicates:c} +% \begin{syntax} +% \cs{clist_gremove_duplicates:N} \meta{comma list} +% \end{syntax} +% Removes duplicate items from the \meta{comma list}, leaving the +% left most copy of each item in the \meta{comma list}. The \meta{item} +% comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}. +% The removal is applied globally. +% \begin{texnote} +% This function iterates through every item in the \meta{comma list} and +% does a comparison with the \meta{items} already checked. It is therefore +% relatively slow with large comma lists. +% \end{texnote} +% \end{function} +% +% \begin{function}{\clist_remove_all:Nn, \clist_remove_all:cn} +% \begin{syntax} +% \cs{clist_remove_all:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Removes every occurrence of \meta{item} from the \meta{comma list}. +% The \meta{item} comparison takes place on a token basis, as for +% \cs{tl_if_eq:nn(TF)}. The removal is local to the current \TeX{} group. +% \end{function} +% +% \begin{function}{\clist_gremove_all:Nn, \clist_gremove_all:cn} +% \begin{syntax} +% \cs{clist_gremove_all:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Removes each occurrence of \meta{item} from the \meta{comma list}. +% The \meta{item} comparison takes place on a token basis, as for +% \cs{tl_if_eq:nn(TF)}. The removal is applied globally. +% \end{function} +% +% \begin{function}{\clist_trim_spaces:N, \clist_trim_spaces:c} +% \begin{syntax} +% \cs{clist_trim_spaces:N} \meta{comma list} +% \end{syntax} +% Removes leading and trailing spaces from each \meta{item} in the +% \meta{comma list} within the current \TeX{} group. This space-removal +% process takes place as described for \cs{tl_trim_spaces:n}. +% \end{function} +% +% \begin{function}{\clist_gtrim_spaces:N, \clist_gtrim_spaces:c} +% \begin{syntax} +% \cs{clist_gtrim_spaces:N} \meta{comma list} +% \end{syntax} +% Removes leading and trailing spaces from each \meta{item} in the +% \meta{comma list} globally. This space-removal +% process takes place as described for \cs{tl_trim_spaces:n}. +% \end{function} +% +% \begin{function}[EXP]{\clist_trim_spaces:n} +% \begin{syntax} +% \cs{clist_trim_spaces:N} \meta{comma list} +% \end{syntax} +% Removes leading and trailing spaces from each \meta{item} in the +% \meta{comma list}, leaving the resulting modified list in the +% input stream. +% \end{function} +% +% \section{Comma list conditionals} +% +% \begin{function}[EXP,pTF]{\clist_if_empty:N, \clist_if_empty:c} +% \begin{syntax} +% \cs{clist_if_empty_p:N} \meta{comma list} +% \cs{clist_if_empty:NTF} \meta{comma list} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{comma list} is empty (containing no items). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \end{function} +% +% \begin{function}[EXP,pTF] +% {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc} +% \begin{syntax} +% \cs{clist_if_eq_p:NN} \Arg{clist1} \Arg{clist2} +% \cs{clist_if_eq:NNTF} \Arg{clist1} \Arg{clist2} \Arg{true code} +% ~~\Arg{false code} +% \end{syntax} +% Compares the content of two \meta{comma lists} and +% is logically \texttt{true} if the two contain the same list of +% entries in the same order. The branching versions then leave either +% \meta{true code} or \meta{false code} in the input stream, as +% appropriate to the truth of the test and the variant of the function +% chosen. The logical truth of the test is left in the input stream by +% the predicate version. +% \end{function} +% +% \begin{function}[TF]{ +% \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, +% \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co, +% \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no +% } +% \begin{syntax} +% \cs{clist_if_in:NnTF} \meta{comma list} \Arg{item} +% ~~\Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the \meta{item} is present in the \meta{comma list}. +% Either the \meta{true code} or \meta{false code} is left in the input +% stream, as appropriate to the truth of the test and the variant of the +% function +% chosen. +% \end{function} +% +% \section{Mapping to comma lists} +% +% \begin{function}[EXP] +% {\clist_map_function:NN, \clist_map_function:cN, \clist_map_function:nN} +% \begin{syntax} +% \cs{clist_map_function:NN} \meta{comma list} \meta{function} +% \end{syntax} +% Applies \meta{function} to every \meta{item} stored in the +% \meta{comma list}. The \meta{function} will receive one argument for +% each iteration. The \meta{items} are returned from left to right. +% The function \cs{clist_map_inline:Nn} is in general more efficient +% than \cs{clist_map_function:NN}. +% One mapping may be nested inside another. +% \end{function} +% +% \begin{function} +% {\clist_map_inline:Nn, \clist_map_inline:cn, \clist_map_inline:nn} +% \begin{syntax} +% \cs{clist_map_inline:Nn} \meta{comma list} \Arg{inline function} +% \end{syntax} +% Applies \meta{inline function} to every \meta{item} stored +% within the \meta{comma list}. The \meta{inline function} should +% consist of code which will receive the \meta{item} as |#1|. +% One in line mapping can be nested inside another. The \meta{items} +% are returned from left to right. +% \end{function} +% +% \begin{function} +% {\clist_map_variable:NNn, \clist_map_variable:cNn, \clist_map_variable:nNn} +% \begin{syntax} +% \cs{clist_map_variable:NNn} \meta{comma list} +% ~~\meta{tl~var.} \Arg{function using tl~var.} +% \end{syntax} +% Stores each entry in the \meta{comma list} in turn in the +% \meta{tl~var.}\ and applies the \meta{function using tl~var.} +% The \meta{function} will usually consist of code making use of +% the \meta{tl~var.}, but this is not enforced. One variable +% mapping can be nested inside another. The \meta{items} +% are returned from left to right. +% \end{function} +% +% \begin{function}[EXP]{\clist_map_break:} +% \begin{syntax} +% \cs{clist_map_break:} +% \end{syntax} +% Used to terminate a \cs{clist_map_\ldots} function before all +% entries in the \meta{comma list} have been processed. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \clist_map_inline:Nn \l_my_clist +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \clist_map_break: } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{clist_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{clist_break_point:n} before further items are taken +% from the input stream. This will depend on the design of the mapping +% function. +% \end{texnote} +% \end{function} +% +% \begin{function}[EXP]{\clist_map_break:n} +% \begin{syntax} +% \cs{clist_map_break:n} \Arg{tokens} +% \end{syntax} +% Used to terminate a \cs{clist_map_\ldots} function before all +% entries in the \meta{comma list} have been processed, inserting +% the \meta{tokens} after the mapping has ended. This will +% normally take place within a conditional statement, for example +% \begin{verbatim} +% \clist_map_inline:Nn \l_my_clist +% { +% \str_if_eq:nnTF { #1 } { bingo } +% { \clist_map_break:n { <tokens> } } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{clist_map_\ldots} scenario will lead to low +% level \TeX{} errors. +% \begin{texnote} +% When the mapping is broken, additional tokens may be inserted by the +% internal macro \cs{clist_break_point:n} before the \meta{tokens} are +% inserted into the input stream. +% This will depend on the design of the mapping function. +% \end{texnote} +% \end{function} +% +% \section{Comma lists as stacks} +% +% Comma lists can be used as stacks, where data is pushed to and popped +% from the top of the comma list. (The left of a comma list is the top, for +% performance reasons.) The stack functions for comma lists are not +% intended to be mixed with the general ordered data functions detailed +% in the previous section: a comma list should either be used as an +% ordered data type or as a stack, but not in both ways. +% +% \begin{function}{\clist_get:NN, \clist_get:cN} +% \begin{syntax} +% \cs{clist_get:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Reads the top item from a \meta{comma list} into the +% \meta{token list variable} without removing it from the +% \meta{comma list}. The \meta{token list variable} is assigned locally. +% If \meta{comma list} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\clist_pop:NN, \clist_pop:cN} +% \begin{syntax} +% \cs{clist_pop:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Pops the top item from a \meta{comma list} into the +% \meta{token list variable}. Both of the variables are assigned +% locally. If \meta{comma list} is empty an error will be raised. +% \end{function} +% +% \begin{function}{\clist_gpop:NN, \clist_gpop:cN} +% \begin{syntax} +% \cs{clist_gpop:NN} \meta{comma list} \meta{token list variable} +% \end{syntax} +% Pops the top item from a \meta{comma list} into the +% \meta{token list variable}. The \meta{comma list} is modified globally, +% while the \meta{token list variable} is assigned locally. If +% \meta{comma list} is empty an error will be raised. +% \end{function} +% +% \begin{function}{ +% \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, +% \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx +% } +% \begin{syntax} +% \cs{clist_push:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Adds the \Arg{item} to the top of the \meta{comma list}. +% The assignment is restricted to the current \TeX{} group. +% \end{function} +% +% \begin{function}{ +% \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, \clist_gpush:Nx, +% \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx +% } +% \begin{syntax} +% \cs{clist_gpush:Nn} \meta{comma list} \Arg{item} +% \end{syntax} +% Pushes the \meta{item} onto the end of the top of the +% \meta{comma list}. The assignment is global. +% \end{function} +% +% \section{Viewing comma lists} +% +% \begin{function}{\clist_show:N, \clist_show:c} +% \begin{syntax} +% \cs{clist_show:N} \meta{comma list} +% \end{syntax} +% Displays the entries in the \meta{comma list} in the terminal. +% \end{function} +% +% \section{Experimental comma list functions} +% +% This section contains functions which may or may not be retained, depending +% on how useful they are found to be. +% +% \begin{function}[EXP]{\clist_length:N, \clist_length:c,\clist_length:n} +% \begin{syntax} +% \cs{clist_length:N} \meta{comma list} +% \end{syntax} +% Leaves the number of items in the \meta{comma list} in the input +% stream as an \meta{integer denotation}. The total number of items +% in a \meta{comma list} will include those which are empty and duplicates, +% \emph{i.e.}~every item in a \meta{comma list} is unique. +% \end{function} +% +% \begin{function}[EXP]{\clist_item:Nn, \clist_item:cn, \clist_item:nn} +% \begin{syntax} +% \cs{clist_item:Nn} \meta{comma list} \Arg{integer expression} +% \end{syntax} +% Indexing items in the \meta{comma list} from $0$ at the top (left), this +% function will evaluate the \meta{integer expression} and leave the +% appropriate item from the comma list in the input stream. If the +% \meta{integer expression} is negative, indexing occurs from the +% bottom (right) of the comma list. When the \meta{integer expression} +% is larger than the number of items in the \meta{comma list} (as +% calculated by \cs{clist_length:N}) then the function will expand to +% nothing. +% \end{function} +% +% \begin{function} +% { +% \clist_set_from_seq:NN, \clist_set_from_seq:cN, +% \clist_set_from_seq:Nc, \clist_set_from_seq:cc +% } +% \begin{syntax} +% \cs{clist_set_from_seq:NN} \meta{comma list} \meta{sequence} +% \end{syntax} +% Sets the \meta{comma list} within the current \TeX{} group to be equal +% to the content of the \meta{sequence}. +% \end{function} +% +% \begin{function} +% { +% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, +% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc +% } +% \begin{syntax} +% \cs{clist_gset_from_seq:NN} \meta{comma list} \meta{sequence} +% \end{syntax} +% Sets the \meta{comma list} globally to equal to the content of the +% \meta{sequence}. +% \end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3clist} implementation} +% +% \TestFiles{m3clist002} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} +% +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} +\package_check_loaded_expl: +%</package> +% \end{macrocode} +% +% \begin{variable}{\l_clist_tmpa_tl, \l_clist_tmpb_tl} +% Scratch space for various internal uses. +% \begin{macrocode} +\tl_new:N \l_clist_tmpa_tl +\tl_new:N \l_clist_tmpb_tl +% \end{macrocode} +% \end{variable} +% +% \subsection{Allocation and initialisation} +% +% \begin{macro}{\clist_new:N,\clist_new:c} +% \UnitTested +% Internally, comma lists are just token lists. +% \begin{macrocode} +\cs_new_eq:NN \clist_new:N \tl_new:N +\cs_new_eq:NN \clist_new:c \tl_new:c +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_clear:N, \clist_clear:c} +% \UnitTested +% \begin{macro}{\clist_gclear:N, \clist_gclear:c} +% \UnitTested +% Clearing comma lists is just the same as clearing token lists. +% \begin{macrocode} +\cs_new_eq:NN \clist_clear:N \tl_clear:N +\cs_new_eq:NN \clist_clear:c \tl_clear:c +\cs_new_eq:NN \clist_gclear:N \tl_gclear:N +\cs_new_eq:NN \clist_gclear:c \tl_gclear:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_clear_new:N, \clist_clear_new:c} +% \UnitTested +% \begin{macro}{\clist_gclear_new:N, \clist_gclear_new:c} +% \UnitTested +% Once again a copy from the token list functions. +% \begin{macrocode} +\cs_new_eq:NN \clist_clear_new:N \tl_clear_new:N +\cs_new_eq:NN \clist_clear_new:c \tl_clear_new:c +\cs_new_eq:NN \clist_gclear_new:N \tl_gclear_new:N +\cs_new_eq:NN \clist_gclear_new:c \tl_gclear_new:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\clist_set_eq:NN, \clist_set_eq:cN, \clist_set_eq:Nc, \clist_set_eq:cc} +% \UnitTested +% \begin{macro} +% { +% \clist_gset_eq:NN, \clist_gset_eq:cN, +% \clist_gset_eq:Nc, \clist_gset_eq:cc +% } +% \UnitTested +% Once again, these are simple copies from the token list functions. +% \begin{macrocode} +\cs_new_eq:NN \clist_set_eq:NN \tl_set_eq:NN +\cs_new_eq:NN \clist_set_eq:Nc \tl_set_eq:Nc +\cs_new_eq:NN \clist_set_eq:cN \tl_set_eq:cN +\cs_new_eq:NN \clist_set_eq:cc \tl_set_eq:cc +\cs_new_eq:NN \clist_gset_eq:NN \tl_gset_eq:NN +\cs_new_eq:NN \clist_gset_eq:Nc \tl_gset_eq:Nc +\cs_new_eq:NN \clist_gset_eq:cN \tl_gset_eq:cN +\cs_new_eq:NN \clist_gset_eq:cc \tl_gset_eq:cc +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_concat:NNN, \clist_concat:ccc} +% \UnitTested +% \begin{macro}{\clist_gconcat:NNN, \clist_gconcat:ccc} +% \UnitTested +% \begin{macro}[aux]{\clist_concat_aux:NNNN} +% Concatenating sequences is not quite as easy as it seems, as there is +% the danger that |#1| may be the same as either |#2| or |#3|. Also, +% there needs to be the correct addition of a comma to the output. So +% a little work to do. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_concat:NNN + { \clist_concat_aux:NNNN \tl_set:Nx } +\cs_new_protected_nopar:Npn \clist_gconcat:NNN + { \clist_concat_aux:NNNN \tl_gset:Nx } +\cs_new_protected_nopar:Npn \clist_concat_aux:NNNN #1#2#3#4 + { + #1 #2 + { + \clist_if_empty:NTF #3 + { \exp_not:o #4 } + { + \exp_not:o #3 + \clist_if_empty:NF #4 + { + , + \exp_not:o #4 + } + } + } + } +\cs_generate_variant:Nn \clist_concat:NNN { ccc } +\cs_generate_variant:Nn \clist_gconcat:NNN { ccc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Appending items to comma lists} +% +% \begin{macro} +% { +% \clist_put_left:Nn, \clist_put_left:NV, +% \clist_put_left:No, \clist_put_left:Nx, +% \clist_put_left:cn, \clist_put_left:cV, +% \clist_put_left:co, \clist_put_left:cx +% } +% \UnitTested +% \begin{macro} +% { +% \clist_gput_left:Nn, \clist_gput_left:NV, +% \clist_gput_left:No, \clist_gput_left:Nx, +% \clist_gput_left:cn, \clist_gput_left:cV, +% \clist_gput_left:co, \clist_gput_left:cx +% } +% \UnitTested +% Comma lists cannot hold empty values: there are therefore a couple +% of sanity checks to avoid accumulating commas. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_put_left:Nn + { \clist_put_aux:NNnnNn \tl_set:Nn \tl_put_left:Nn { } , } +\cs_new_protected_nopar:Npn \clist_gput_left:Nn + { \clist_put_aux:NNnnNn \tl_gset:Nn \tl_gput_left:Nn { } , } +\cs_new_protected:Npn \clist_put_aux:NNnnNn #1#2#3#4#5#6 + { + \clist_if_empty:NTF #5 + { #1 #5 {#6} } + { \tl_if_empty:nF {#6} { #2 #5 { #3 #6 #4 } } } + } +\cs_generate_variant:Nn \clist_put_left:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_put_left:Nn { c , cV , co , cx } +\cs_generate_variant:Nn \clist_gput_left:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_gput_left:Nn { c , cV , co , cx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \clist_put_right:Nn, \clist_put_right:NV, +% \clist_put_right:No, \clist_put_right:Nx, +% \clist_put_right:cn, \clist_put_right:cV, +% \clist_put_right:co, \clist_put_right:cx +% } +% \begin{macro} +% { +% \clist_gput_right:Nn, \clist_gput_right:NV, +% \clist_gput_right:No, \clist_gput_right:Nx, +% \clist_gput_right:cn, \clist_gput_right:cV, +% \clist_gput_right:co, \clist_gput_right:cx +% } +% The same for the right side. +% \begin{macrocode} +\cs_new_protected:Npn \clist_put_right:Nn + { \clist_put_aux:NNnnNn \tl_set:Nn \tl_put_right:Nn , { } } +\cs_new_protected_nopar:Npn \clist_gput_right:Nn + { \clist_put_aux:NNnnNn \tl_gset:Nn \tl_gput_right:Nn , { } } +\cs_generate_variant:Nn \clist_put_right:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_put_right:Nn { c , cV , co , cx } +\cs_generate_variant:Nn \clist_gput_right:Nn { NV , No , Nx } +\cs_generate_variant:Nn \clist_gput_right:Nn { c , cV , co , cx } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Comma lists as stacks} +% +% \begin{macro}{\clist_get:NN, \clist_get:cN} +% \UnitTested +% \begin{macro}[aux]{\clist_get_aux:wN} +% Getting an item from the left of a comma list is pretty easy: just +% trim off the first item using the comma. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_get:NN #1#2 + { \exp_after:wN \clist_get_aux:wN #1 , \q_stop #2 } +\cs_new_protected:Npn \clist_get_aux:wN #1 , #2 \q_stop #3 + { \tl_set:Nn #3 {#1} } +\cs_generate_variant:Nn \clist_get:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_pop:NN, \clist_pop:cN} +% \UnitTested +% \begin{macro}{\clist_gpop:NN, \clist_gpop:cN} +% \UnitTested +% \begin{macro}[aux]{\clist_pop_aux:NNN} +% \begin{macro}[aux]{\clist_pop_aux:wNNN} +% The aim here is to get the popped item as |#1| in the auxiliary, with +% |#2| containing either the remainder of the list \emph{or} \cs{q_nil} +% if there were insufficient items. That keeps the number of auxiliary +% functions down. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_pop:NN + { \clist_pop_aux:NNN \tl_set:Nn } +\cs_new_protected_nopar:Npn \clist_gpop:NN + { \clist_pop_aux:NNN \tl_gset:Nn } +\cs_new_protected_nopar:Npn \clist_pop_aux:NNN #1#2#3 + { \exp_after:wN \clist_pop_aux:wNNN #2 , \q_nil , \q_nil , \q_stop #1#2#3 } +\cs_new_protected:Npn \clist_pop_aux:wNNN #1 , #2 , \q_nil , #3 \q_stop #4#5#6 + { + \quark_if_nil:nTF {#2} + { #4 #5 { } } + { #4 #5 {#2} } + \tl_set:Nn #6 {#1} + } +\cs_generate_variant:Nn \clist_pop:NN { c } +\cs_generate_variant:Nn \clist_gpop:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{ +% \clist_push:Nn, \clist_push:NV, \clist_push:No, \clist_push:Nx, +% \clist_push:cn, \clist_push:cV, \clist_push:co, \clist_push:cx +% } +% \UnitTested +% \begin{macro}{ +% \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, \clist_gpush:Nx, +% \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, \clist_gpush:cx +% } +% \UnitTested +% Pushing to a sequence is the same as adding on the left. +% \begin{macrocode} +\cs_new_eq:NN \clist_push:Nn \clist_put_left:Nn +\cs_new_eq:NN \clist_push:NV \clist_put_left:NV +\cs_new_eq:NN \clist_push:No \clist_put_left:No +\cs_new_eq:NN \clist_push:Nx \clist_put_left:Nx +\cs_new_eq:NN \clist_push:cn \clist_put_left:cn +\cs_new_eq:NN \clist_push:cV \clist_put_left:cV +\cs_new_eq:NN \clist_push:co \clist_put_left:co +\cs_new_eq:NN \clist_push:cx \clist_put_left:cx +\cs_new_eq:NN \clist_gpush:Nn \clist_gput_left:Nn +\cs_new_eq:NN \clist_gpush:NV \clist_gput_left:NV +\cs_new_eq:NN \clist_gpush:No \clist_gput_left:No +\cs_new_eq:NN \clist_gpush:Nx \clist_gput_left:Nx +\cs_new_eq:NN \clist_gpush:cn \clist_gput_left:cn +\cs_new_eq:NN \clist_gpush:cV \clist_gput_left:cV +\cs_new_eq:NN \clist_gpush:co \clist_gput_left:co +\cs_new_eq:NN \clist_gpush:cx \clist_gput_left:cx +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Using comma lists} +% +% \begin{macro}{\clist_use:N, \clist_use:c} +% \UnitTested +% The approach is the same as for \cs{tl_use:N}. +% \begin{macrocode} +\cs_new_eq:NN \clist_use:N \tl_use:N +\cs_new_eq:NN \clist_use:c \tl_use:c +% \end{macrocode} +% \end{macro} +% +% \subsection{Modifying comma lists} +% +% \begin{variable}{\l_clist_remove_clist} +% An internal comma list for the removal routines. +% \begin{macrocode} +\clist_new:N \l_clist_remove_clist +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\clist_remove_duplicates:N, \clist_remove_duplicates:c} +% \UnitTested +% \begin{macro}{\clist_gremove_duplicates:N, \clist_gremove_duplicates:c} +% \UnitTested +% \begin{macro}[aux]{\clist_remove_duplicates_aux:NN} +% Removing duplicates means making a new list then copying it. +% \begin{macrocode} +\cs_new_protected:Npn \clist_remove_duplicates:N + { \clist_remove_duplicates_aux:NN \clist_set_eq:NN } +\cs_new_protected:Npn \clist_gremove_duplicates:N + { \clist_remove_duplicates_aux:NN \clist_gset_eq:NN } +\cs_new_protected:Npn \clist_remove_duplicates_aux:NN #1#2 + { + \clist_clear:N \l_clist_remove_clist + \clist_map_inline:Nn #2 + { + \clist_if_in:NnF \l_clist_remove_clist {##1} + { \clist_put_right:Nn \l_clist_remove_clist {##1} } + } + #1 #2 \l_clist_remove_clist + } +\cs_generate_variant:Nn \clist_remove_duplicates:N { c } +\cs_generate_variant:Nn \clist_gremove_duplicates:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_remove_all:Nn, \clist_remove_all:cn} +% \UnitTested +% \begin{macro}{\clist_gremove_all:Nn, \clist_gremove_all:cn} +% \UnitTested +% \begin{macro}[aux]{\clist_remove_all_aux:NNn} +% \begin{macro}[aux]{\clist_remove_all_aux:w} +% Removing an item from a comma list is done without looping over +% the entire list, as the performance of that approach is very bad for +% long lists. Instead, a delimited function is needed. For this to work +% correctly, there is a need to add an additional comma at the start of +% the list, and to remove it again once the removal is complete. Of +% course, the list can end up empty, which is the reason for the test +% before copying back to the parent. +% \begin{macrocode} +\cs_new_protected:Npn \clist_remove_all:Nn + { \clist_remove_all_aux:NNn \clist_set_eq:NN } +\cs_new_protected:Npn \clist_gremove_all:Nn + { \clist_remove_all_aux:NNn \clist_gset_eq:NN } +\cs_new_protected:Npn \clist_remove_all_aux:NNn #1#2#3 + { + \clist_if_empty:NF #2 + { + \clist_clear:N \l_clist_remove_clist + \cs_set_protected:Npn \clist_remove_all_aux:w + ##1 , #3 , ##2 \q_stop + { + \tl_put_right:Nn \l_clist_remove_clist {##1} + \quark_if_no_value:nF {##2} + { \clist_remove_all_aux:w , ##2 \q_stop } + } + \exp_after:wN \clist_remove_all_aux:w + \exp_after:wN , #2 , #3 , \q_no_value \q_stop + \tl_if_empty:NF \l_clist_remove_clist + { + \exp_after:wN \tl_set:No \exp_after:wN + \l_clist_remove_clist \exp_after:wN + { \exp_after:wN \use_none:n \l_clist_remove_clist } + } + #1 #2 \l_clist_remove_clist + } + } +\cs_new_protected:Npn \clist_remove_all_aux:w { } +\cs_generate_variant:Nn \clist_remove_all:Nn { c } +\cs_generate_variant:Nn \clist_gremove_all:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_trim_spaces:n} +% \begin{macro} +% { +% \clist_trim_spaces:N, \clist_trim_spaces:c, +% \clist_gtrim_spaces:N, \clist_gtrim_spaces:c +% } +% \begin{macro}{\clist_trim_spaces_aux_i:n} +% \begin{macro}{\clist_trim_spaces_aux_ii:n} +% Here, the basic plan is to use \cs{tl_trim_spaces:n} to do the work: +% the only issue is to make sure that the number of commas at the end of +% the process is correct. +% \begin{macrocode} +\cs_new:Npn \clist_trim_spaces:n #1 + { + \exp_args:Nf \clist_trim_spaces_aux_i:n + { \clist_map_function:nN {#1} \clist_trim_spaces_aux_ii:n } + } +\cs_new:Npn \clist_trim_spaces_aux_i:n #1 { \use_ii:nn #1 } +\cs_new:Npn \clist_trim_spaces_aux_ii:n #1 + { , \tl_trim_spaces:n {#1} } +\cs_new_protected:Npn \clist_trim_spaces:N #1 + { \tl_set:Nf #1 { \exp_args:No \clist_trim_spaces:n #1 } } +\cs_new_protected:Npn \clist_gtrim_spaces:N #1 + { \tl_gset:Nf #1 { \exp_args:No \clist_trim_spaces:n #1 } } +\cs_generate_variant:Nn \clist_trim_spaces:N { c } +\cs_generate_variant:Nn \clist_gtrim_spaces:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Comma list conditionals} +% +% \begin{macro}[aux]{\clist_tmp:w} +% A temporary function for comparison. +% \begin{macrocode} +\cs_new_protected:Npn \clist_tmp:w { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\clist_if_empty:N, \clist_if_empty:c} +% \UnitTested +% Simple copies from the token list variable material. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \clist_if_empty:N \tl_if_empty:N { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_empty:c \tl_if_empty:c { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF] +% {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc} +% \UnitTested +% Simple copies from the token list variable material. +% \begin{macrocode} +\prg_new_eq_conditional:NNn \clist_if_eq:NN \tl_if_eq:NN { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:cN \tl_if_eq:cN { p , T , F , TF } +\prg_new_eq_conditional:NNn \clist_if_eq:cc \tl_if_eq:cc { p , T , F , TF } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[TF] +% { +% \clist_if_in:Nn, \clist_if_in:NV, \clist_if_in:No, +% \clist_if_in:cn, \clist_if_in:cV, \clist_if_in:co +% } +% \UnitTested +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 + { T , F , TF } + { + \cs_set_protected:Npn \clist_tmp:w ##1 , #2 , ##2##3 \q_stop + { + \if_meaning:w \q_no_value ##2 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } + \exp_last_unbraced:NNo \clist_tmp:w , #1 , #2 , \q_no_value \q_stop + } +\prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 + { T , F , TF } + { + \cs_set_protected:Npn \clist_tmp:w ##1 , #2 , ##2##3 \q_stop + { + \if_meaning:w \q_no_value ##2 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } + \clist_tmp:w , #1 , #2 , \q_no_value \q_stop + } +\cs_generate_variant:Nn \clist_if_in:NnT { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnT { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:NnF { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnF { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:NnTF { NV , No } +\cs_generate_variant:Nn \clist_if_in:NnTF { c , cV , co } +\cs_generate_variant:Nn \clist_if_in:nnT { nV , no } +\cs_generate_variant:Nn \clist_if_in:nnF { nV , no } +\cs_generate_variant:Nn \clist_if_in:nnTF { nV , no } +% \end{macrocode} +% \end{macro} +% +% \subsection{Mapping to comma lists} +% +% \begin{macro}{\clist_map_function:NN, \clist_map_function:cN} +% \UnitTested +% \begin{macro}{\clist_map_function:nN} +% \UnitTested +% \begin{macro}[aux]{\clist_map_function_aux:Nw} +% Mapping to comma lists is pretty simple, if not massively efficient. +% \begin{macrocode} +\cs_new_nopar:Npn \clist_map_function:NN #1#2 + { + \clist_if_empty:NF #1 + { + \exp_last_unbraced:NNo \clist_map_function_aux:Nw #2 #1 + , \q_recursion_tail , \q_recursion_stop + } + } +\cs_new:Npn \clist_map_function:nN #1#2 + { + \tl_if_empty:nF {#1} + { + \clist_map_function_aux:Nw #2 #1 + , \q_recursion_tail , \q_recursion_stop + } + } +\cs_new:Npn \clist_map_function_aux:Nw #1#2 , + { + \quark_if_recursion_tail_stop:n {#2} + #1 {#2} + \clist_map_function_aux:Nw #1 + } +\cs_generate_variant:Nn \clist_map_function:NN { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{variable}{\g_clist_map_inline_int} +% For the nesting of mappings. +% \begin{macrocode} +\int_new:N \g_clist_map_inline_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\clist_map_inline:Nn, \clist_map_inline:cn} +% \UnitTested +% \begin{macro}{\clist_map_inline:nn} +% \UnitTested +% Inline mapping is done by creating a suitable function +% \enquote{on the fly}: +% this is done globally to avoid any issues with \TeX{}'s groups. +% \begin{macrocode} +\cs_new_protected:Npn \clist_map_inline:Nn #1#2 + { + \int_gincr:N \g_clist_map_inline_int + \cs_gset:cpn { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + ##1 + {#2} + \exp_args:NNc \clist_map_function:NN #1 + { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + \int_gdecr:N \g_clist_map_inline_int + } +\cs_new_protected:Npn \clist_map_inline:nn #1#2 + { + \int_gincr:N \g_clist_map_inline_int + \cs_gset:cpn { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + ##1 + {#2} + \exp_args:Nnc \clist_map_function:nN {#1} + { clist_map_inline_ \int_use:N \g_clist_map_inline_int :n } + \int_gdecr:N \g_clist_map_inline_int + } +\cs_generate_variant:Nn \clist_map_inline:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_map_variable:NNn, \clist_map_variable:cNn} +% \UnitTested +% This is just a dedicated version of the inline mapping. +% \begin{macrocode} +\cs_new_protected:Npn \clist_map_variable:NNn #1#2#3 + { + \clist_map_inline:Nn #1 + { + \tl_set:Nn #2 {##1} + #3 + } + } +\cs_new_protected:Npn \clist_map_variable:nNn #1#2#3 + { + \clist_map_inline:nn {#1} + { + \tl_set:Nn #2 {##1} + #3 + } + } +\cs_generate_variant:Nn \clist_map_variable:NNn { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_map_break:} +% \UnitTested +% \begin{macro}{\clist_map_break:n} +% Both are simple renaming. +% \begin{macrocode} +\cs_new_eq:NN \clist_map_break: \use_none_delimit_by_q_recursion_stop:w +\cs_new_eq:NN \clist_map_break:n \use_i_delimit_by_q_recursion_stop:nw +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \section{Viewing comma lists} +% +% \begin{macro}{\clist_show:N, \clist_show:c} +% \UnitTested +% \begin{macro}[aux]{\clist_show_aux:n} +% \begin{macro}[aux]{\clist_show_aux:w} +% The aim of the mapping here is to create a token list containing the +% formatted comma list. The very first item needs the new line and \verb*|> | +% removing, which is achieved using a \texttt{w}-type auxiliary. To avoid +% a low-level \TeX{} error if there is an empty comma list, a simple test is +% used to keep the output \enquote{clean}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \clist_show:N #1 + { + \clist_if_empty:NTF #1 + { + \iow_term:x { Comma~list~\token_to_str:N #1 \c_space_tl is~empty } + \tl_show:n { } + } + { + \iow_term:x + { + Comma~list~\token_to_str:N #1 \c_space_tl + contains~the~items~(without~outer~braces): + } + \tl_set:Nx \l_clist_show_tl + { \clist_map_function:NN #1 \clist_show_aux:n } + \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN + { \exp_after:wN \clist_show_aux:w \l_clist_show_tl } + } + } +\cs_new:Npn \clist_show_aux:n #1 + { + \iow_newline: > \c_space_tl \c_space_tl + \iow_char:N \{ \exp_not:n {#1} \iow_char:N \} + } +\cs_new:Npn \clist_show_aux:w #1 > ~ { } +\cs_generate_variant:Nn \clist_show:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsection{Experimental functions} +% +% \begin{macro}{\clist_length:N, \clist_length:c} +% \begin{macro}{\clist_length:n} +% \begin{macro}[aux]{\clist_length_aux:n} +% Counting the items in a comma list is done using the same approach as for +% other length functions: turn each entry into a \texttt{+1} then use +% integer evaluation to actually do the mathematics. +% \begin{macrocode} +\cs_new:Npn \clist_length:N #1 + { + \int_eval:n + { + 0 + \clist_map_function:NN #1 \clist_length_aux:n + } + } +\cs_new:Npn \clist_length:n #1 + { + \int_eval:n + { + 0 + \clist_map_function:nN {#1} \clist_length_aux:n + } + } +\cs_new:Npn \clist_length_aux:n #1 { +1 } +\cs_generate_variant:Nn \clist_length:N { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_item:Nn, \clist_item:cn} +% \begin{macro}{\clist_item:nn} +% \begin{macro}[aux]{\clist_item_aux:nnn} +% The idea here is to find the offset of the item from the left, then use +% a loop to grab the correct item. If the resulting offset is too large, +% then \cs{quark_if_recursion_stop:n} will be true, +% terminating the loop and returning nothing at all. +% \begin{macrocode} +\cs_set_nopar:Npn \clist_item:Nn #1#2 + { \exp_args:No \clist_item:nn #1 {#2} } +\cs_set:Npn \clist_item:nn #1#2 + { + \int_compare:nNnTF {#2} < \c_zero + { + \exp_args:Nf \clist_item_aux:nw + { \int_eval:n { \clist_length:n {#1} + #2 } } + #1 , \q_recursion_tail \q_recursion_stop + } + { \clist_item_aux:nw {#2} #1 , \q_recursion_tail \q_recursion_stop } + } +\cs_set:Npn \clist_item_aux:nw #1#2 , #3 + { + \int_compare:nNnTF {#1} = \c_zero + { \use_i_delimit_by_q_recursion_stop:nw {#2} } + { + \quark_if_recursion_tail_stop:n {#3} + \exp_args:Nf \clist_item_aux:nw + { \int_eval:n { #1 - 1 } } + #3 + } + } +\cs_generate_variant:Nn \clist_item:Nn { c } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \clist_set_from_seq:NN, \clist_set_from_seq:cN, +% \clist_set_from_seq:Nc, \clist_set_from_seq:cc +% } +% \begin{macro} +% { +% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, +% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc +% } +% Setting a comma list from a comma-separated list is done using a simple +% mapping. We wrap each item with braces, \cs{exp_not:n}, and a comma. The +% first comma must be removed, except in the case of an empty comma-list. +% \begin{macrocode} +\cs_new_protected:Npn \clist_set_from_seq:NN #1#2 + { + \seq_if_empty:NTF #2 + { \clist_clear:N #1 } + { + \seq_push_item_def:n { , \exp_not:n {{##1}} } + \tl_set:Nx #1 + { \exp_after:wN \use_none:n \tex_romannumeral:D -`\0 #2 } + \seq_pop_item_def: + } + } +\cs_new_protected:Npn \clist_gset_from_seq:NN #1#2 + { + \seq_if_empty:NTF #2 + { \clist_gclear:N #1 } + { + \seq_push_item_def:n { , \exp_not:n {##1} } + \tl_gset:Nx #1 + { \exp_after:wN \use_none:n \tex_romannumeral:D -`\0 #2 } + \seq_pop_item_def: + } + } +\cs_generate_variant:Nn \clist_set_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_set_from_seq:NN { c , cc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { Nc } +\cs_generate_variant:Nn \clist_gset_from_seq:NN { c , cc } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Deprecated interfaces} +% +% Deprecated on 2011-05-27, for removal by 2011-08-31. +% +% \begin{macro}{\clist_top:NN, \clist_top:cN} +% These are old stack functions. +% \begin{macrocode} +\cs_new_eq:NN \clist_top:NN \clist_get:NN +\cs_new_eq:NN \clist_top:cN \clist_get:cN +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_remove_element:Nn} +% \begin{macro}{\clist_gremove_element:Nn} +% An older name for \cs{clist_remove_all:Nn}. +% \begin{macrocode} +\cs_new_eq:NN \clist_remove_element:Nn \clist_remove_all:Nn +\cs_new_eq:NN \clist_gremove_element:Nn \clist_gremove_all:Nn +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_display:N, \clist_display:c} +% An older name for \cs{clist_show:N}. +% \begin{macrocode} +\cs_new_eq:NN \clist_display:N \clist_show:N +\cs_new_eq:NN \clist_display:c \clist_show:c +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex
\ No newline at end of file |