From 6ac3dbed4b71022bd6bb0cc25e8fc3df81198498 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Wed, 1 May 2024 03:00:54 +0000 Subject: CTAN sync 202405010300 --- macros/latex/contrib/l3kernel/l3clist.dtx | 2248 ----------------------------- 1 file changed, 2248 deletions(-) delete mode 100644 macros/latex/contrib/l3kernel/l3clist.dtx (limited to 'macros/latex/contrib/l3kernel/l3clist.dtx') diff --git a/macros/latex/contrib/l3kernel/l3clist.dtx b/macros/latex/contrib/l3kernel/l3clist.dtx deleted file mode 100644 index ad65a4b174..0000000000 --- a/macros/latex/contrib/l3kernel/l3clist.dtx +++ /dev/null @@ -1,2248 +0,0 @@ -% \iffalse meta-comment -% -%% File: l3clist.dtx -% -% Copyright (C) 2004-2011 Frank Mittelbach, The LaTeX Project -% (C) 2012-2024 The LaTeX Project -% -% It may be distributed and/or modified under the conditions of the -% LaTeX Project Public License (LPPL), either version 1.3c of this -% license or (at your option) any later version. The latest version -% of this license is in the file -% -% https://www.latex-project.org/lppl.txt -% -% This file is part of the "l3kernel bundle" (The Work in LPPL) -% and all files in that bundle must be distributed together. -% -% ----------------------------------------------------------------------- -% -% The development version of the bundle can be found at -% -% https://github.com/latex3/latex3 -% -% for those people who are interested. -% -%<*driver> -\documentclass[full,kernel]{l3doc} -\begin{document} - \DocInput{\jobname.dtx} -\end{document} -% -% \fi -% -% \title{^^A -% The \pkg{l3clist} module\\ Comma separated lists^^A -% } -% -% \author{^^A -% The \LaTeX{} Project\thanks -% {^^A -% E-mail: -% \href{mailto:latex-team@latex-project.org} -% {latex-team@latex-project.org}^^A -% }^^A -% } -% -% \date{Released 2024-03-14} -% -% \maketitle -% -% \begin{documentation} -% -% Comma lists (in short, |clist|) contain ordered data where items can -% be added to the left or right end of the list. This data type allows -% basic list -% manipulations such as adding/removing items, applying a function to -% every item, removing duplicate items, extracting a given item, using -% the comma list with specified separators, and so on. Sequences -% (defined in \pkg{l3seq}) are safer, faster, and provide more features, -% so they should often be preferred to comma lists. Comma lists are -% mostly useful when interfacing with \LaTeXe{} or other code that -% expects or provides items separated by commas. -% -% Several items can be added at once. To ease input of comma lists from -% data provided by a user outside an \cs{ExplSyntaxOn} \ldots{} -% \cs{ExplSyntaxOff} block, spaces are removed from both sides of each -% comma-delimited argument upon input. Blank arguments are ignored, to -% allow for trailing commas or repeated commas (which may otherwise -% arise when concatenating comma lists \enquote{by hand}). In addition, -% a set of braces is removed if the result of space-trimming is braced: -% this allows the storage of any item in a comma list. For instance, -% \begin{verbatim} -% \clist_new:N \l_my_clist -% \clist_put_left:Nn \l_my_clist { ~a~ , ~{b}~ , c~\d } -% \clist_put_right:Nn \l_my_clist { ~{e~} , , {{f}} , } -% \end{verbatim} -% results in |\l_my_clist| containing |a,b,c~\d,{e~},{{f}}| namely the -% five items |a|, |b|, |c~\d|, |e~| and~|{f}|. Comma lists normally do -% not contain empty or blank items so the following gives an empty comma list: -% \begin{verbatim} -% \clist_clear_new:N \l_my_clist -% \clist_set:Nn \l_my_clist { , ~ , , } -% \clist_if_empty:NTF \l_my_clist { true } { false } -% \end{verbatim} -% and it leaves \texttt{true} in the input stream. To include an -% \enquote{unsafe} item (empty, or one that contains a comma, or starts -% or ends with a space, or is a single brace group), surround it with -% braces. -% -% Any |n|-type token list is a valid comma list input for \pkg{l3clist} -% functions, which will split the token list at every comma and process -% the items as described above. On the other hand, |N|-type functions -% expect comma list variables, which are particular token list variables -% in which this processing of items (and removal of blank items) has -% already occurred. Because comma list variables are token list -% variables, expanding them once yields their items separated by commas, -% and \pkg{l3tl} functions such as \cs{tl_show:N} can be applied to -% them. (These functions often have \pkg{l3clist} analogues, which -% should be preferred.) -% -% Almost all operations on comma lists are -% noticeably slower than those on sequences so converting the data to -% sequences using \cs{seq_set_from_clist:Nn} (see \pkg{l3seq}) may be -% advisable if speed is important. The exception is that -% \cs{clist_if_in:NnTF} and \cs{clist_remove_duplicates:N} may be faster -% than their sequence analogues for large lists. However, these -% functions work slowly for \enquote{unsafe} items that must be braced, -% and may produce errors when their argument contains |{|, |}| or |#| -% (assuming the usual \TeX{} category codes apply). The sequence -% data type should thus certainly be preferred to comma lists to store -% such items. -% -% \section{Creating and initialising comma lists} -% -% \begin{function}{\clist_new:N, \clist_new:c} -% \begin{syntax} -% \cs{clist_new:N} \meta{clist~var} -% \end{syntax} -% Creates a new \meta{clist~var} or raises an error if the name is -% already taken. The declaration is global. The \meta{clist~var} -% initially contains no items. -% \end{function} -% -% \begin{function}[added = 2014-07-05] -% { -% \clist_const:Nn, \clist_const:Ne, -% \clist_const:cn, \clist_const:ce -% } -% \begin{syntax} -% \cs{clist_const:Nn} \meta{clist~var} \Arg{comma list} -% \end{syntax} -% Creates a new constant \meta{clist~var} or raises an error -% if the name is already taken. The value of the -% \meta{clist~var} is set globally to the -% \meta{comma list}. -% \end{function} -% -% \begin{function} -% {\clist_clear:N, \clist_clear:c, \clist_gclear:N, \clist_gclear:c} -% \begin{syntax} -% \cs{clist_clear:N} \meta{clist~var} -% \end{syntax} -% Clears all items from the \meta{clist~var}. -% \end{function} -% -% \begin{function} -% { -% \clist_clear_new:N, \clist_clear_new:c, -% \clist_gclear_new:N, \clist_gclear_new:c -% } -% \begin{syntax} -% \cs{clist_clear_new:N} \meta{clist~var} -% \end{syntax} -% Ensures that the \meta{clist~var} exists globally by applying -% \cs{clist_new:N} if necessary, then applies -% \cs[index=clist_clear:N]{clist_(g)clear:N} to leave -% the list empty. -% \end{function} -% -% \begin{function} -% { -% \clist_set_eq:NN, \clist_set_eq:cN, -% \clist_set_eq:Nc, \clist_set_eq:cc, -% \clist_gset_eq:NN, \clist_gset_eq:cN, -% \clist_gset_eq:Nc, \clist_gset_eq:cc -% } -% \begin{syntax} -% \cs{clist_set_eq:NN} \meta{clist~var_1} \meta{clist~var_2} -% \end{syntax} -% Sets the content of \meta{clist~var_1} equal to that of -% \meta{clist~var_2}. To set a token list variable equal to a comma -% list variable, use \cs{tl_set_eq:NN}. Conversely, setting a comma -% list variable to a token list is unadvisable unless one checks -% space-trimming and related issues. -% \end{function} -% -% \begin{function}[added = 2014-07-17] -% { -% \clist_set_from_seq:NN, \clist_set_from_seq:cN, -% \clist_set_from_seq:Nc, \clist_set_from_seq:cc, -% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, -% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc -% } -% \begin{syntax} -% \cs{clist_set_from_seq:NN} \meta{clist~var} \meta{seq~var} -% \end{syntax} -% Converts the data in the \meta{seq~var} into a \meta{clist~var}: -% the original \meta{seq~var} is unchanged. -% Items which contain either spaces or commas are surrounded by braces. -% \end{function} -% -% \begin{function} -% { -% \clist_concat:NNN, \clist_concat:ccc, -% \clist_gconcat:NNN, \clist_gconcat:ccc -% } -% \begin{syntax} -% \cs{clist_concat:NNN} \meta{clist~var_1} \meta{clist~var_2} \meta{clist~var_3} -% \end{syntax} -% Concatenates the content of \meta{clist~var_2} and \meta{clist~var_3} -% together and saves the result in \meta{clist~var_1}. The items in -% \meta{clist~var_2} are placed at the left side of the new comma list. -% \end{function} -% -% \begin{function}[EXP, pTF, added=2012-03-03] -% {\clist_if_exist:N, \clist_if_exist:c} -% \begin{syntax} -% \cs{clist_if_exist_p:N} \meta{clist~var} -% \cs{clist_if_exist:NTF} \meta{clist~var} \Arg{true code} \Arg{false code} -% \end{syntax} -% Tests whether the \meta{clist~var} is currently defined. This does -% not check that the \meta{clist~var} really is a comma list. -% \end{function} -% -% \section{Adding data to comma lists} -% -% \begin{function}[added = 2011-09-06] -% { -% \clist_set:Nn, \clist_set:NV, \clist_set:Ne, -% \clist_set:No, -% \clist_set:cn, \clist_set:cV, \clist_set:ce, -% \clist_set:co, -% \clist_gset:Nn, \clist_gset:NV, \clist_gset:Ne, -% \clist_gset:No, -% \clist_gset:cn, \clist_gset:cV, \clist_gset:ce, -% \clist_gset:co -% } -% \begin{syntax} -% \cs{clist_set:Nn} \meta{clist~var} |{|\meta{item_1},\ldots{},\meta{item_n}|}| -% \end{syntax} -% Sets \meta{clist~var} to contain the \meta{items}, -% removing any previous content from the variable. -% Blank items are omitted, spaces are removed from both sides of each -% item, then a set of braces is removed if the resulting space-trimmed -% item is braced. -% To store some \meta{tokens} as a single \meta{item} even if the -% \meta{tokens} contain commas or spaces, add a set of braces: -% \cs{clist_set:Nn} \meta{clist~var} |{| \Arg{tokens} |}|. -% \end{function} -% -% \begin{function}[updated = 2011-09-05] -% { -% \clist_put_left:Nn, \clist_put_left:NV, -% \clist_put_left:Nv, \clist_put_left:Ne, -% \clist_put_left:No, -% \clist_put_left:cn, \clist_put_left:cV, -% \clist_put_left:cv, \clist_put_left:ce, -% \clist_put_left:co, -% \clist_gput_left:Nn, \clist_gput_left:NV, -% \clist_gput_left:Nv, \clist_gput_left:Ne, -% \clist_gput_left:No, -% \clist_gput_left:cn, \clist_gput_left:cV, -% \clist_gput_left:cv, \clist_gput_left:ce, -% \clist_gput_left:co -% } -% \begin{syntax} -% \cs{clist_put_left:Nn} \meta{clist~var} |{|\meta{item_1},\ldots{},\meta{item_n}|}| -% \end{syntax} -% Appends the \meta{items} to the left of the \meta{clist~var}. -% Blank items are omitted, spaces are removed from both sides of each -% item, then a set of braces is removed if the resulting space-trimmed -% item is braced. -% To append some \meta{tokens} as a single \meta{item} even if the -% \meta{tokens} contain commas or spaces, add a set of braces: -% \cs{clist_put_left:Nn} \meta{clist~var} |{| \Arg{tokens} |}|. -% \end{function} -% -% \begin{function}[updated = 2011-09-05] -% { -% \clist_put_right:Nn, \clist_put_right:NV, -% \clist_put_right:Nv, \clist_put_right:Ne, -% \clist_put_right:No, -% \clist_put_right:cn, \clist_put_right:cV, -% \clist_put_right:cv, \clist_put_right:ce, -% \clist_put_right:co, -% \clist_gput_right:Nn, \clist_gput_right:NV, -% \clist_gput_right:Nv, \clist_gput_right:Ne, -% \clist_gput_right:No, -% \clist_gput_right:cn, \clist_gput_right:cV, -% \clist_gput_right:cv, \clist_gput_right:ce, -% \clist_gput_right:co -% } -% \begin{syntax} -% \cs{clist_put_right:Nn} \meta{clist~var} |{|\meta{item_1},\ldots{},\meta{item_n}|}| -% \end{syntax} -% Appends the \meta{items} to the right of the \meta{clist~var}. -% Blank items are omitted, spaces are removed from both sides of each -% item, then a set of braces is removed if the resulting space-trimmed -% item is braced. -% To append some \meta{tokens} as a single \meta{item} even if the -% \meta{tokens} contain commas or spaces, add a set of braces: -% \cs{clist_put_right:Nn} \meta{clist~var} |{| \Arg{tokens} |}|. -% \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, -% \clist_gremove_duplicates:N, \clist_gremove_duplicates:c -% } -% \begin{syntax} -% \cs{clist_remove_duplicates:N} \meta{clist~var} -% \end{syntax} -% Removes duplicate items from the \meta{clist~var}, leaving the -% left most copy of each item in the \meta{clist~var}. The \meta{item} -% comparison takes place on a token basis, as for \cs{tl_if_eq:nnTF}. -% \begin{texnote} -% This function iterates through every item in the \meta{clist~var} and -% does a comparison with the \meta{items} already checked. It is therefore -% relatively slow with large comma lists. -% Furthermore, it may fail if any of the items in the -% \meta{clist~var} contains |{|, |}|, or |#| -% (assuming the usual \TeX{} category codes apply). -% \end{texnote} -% \end{function} -% -% \begin{function}[updated = 2011-09-06] -% { -% \clist_remove_all:Nn, \clist_remove_all:cn, -% \clist_remove_all:NV, \clist_remove_all:cV, -% \clist_gremove_all:Nn, \clist_gremove_all:cn, -% \clist_gremove_all:NV, \clist_gremove_all:cV -% } -% \begin{syntax} -% \cs{clist_remove_all:Nn} \meta{clist~var} \Arg{item} -% \end{syntax} -% Removes every occurrence of \meta{item} from the \meta{clist~var}. -% The \meta{item} comparison takes place on a token basis, as for -% \cs{tl_if_eq:nnTF}. -% \begin{texnote} -% The function may fail if the \meta{item} contains |{|, |}|, or |#| -% (assuming the usual \TeX{} category codes apply). -% \end{texnote} -% \end{function} -% -% \begin{function}[added = 2014-07-18] -% { -% \clist_reverse:N, \clist_reverse:c, -% \clist_greverse:N, \clist_greverse:c -% } -% \begin{syntax} -% \cs{clist_reverse:N} \meta{clist~var} -% \end{syntax} -% Reverses the order of items stored in the \meta{clist~var}. -% \end{function} -% -% \begin{function}[added = 2014-07-18]{\clist_reverse:n} -% \begin{syntax} -% \cs{clist_reverse:n} \Arg{comma list} -% \end{syntax} -% Leaves the items in the \meta{comma list} in the input stream in -% reverse order. Contrarily to other what is done for other -% \texttt{n}-type \meta{comma list} arguments, braces and spaces are -% preserved by this process. -% \begin{texnote} -% The result is returned within \tn{unexpanded}, which means that the -% comma list does not expand further when appearing in an -% \texttt{e}-type or \texttt{x}-type argument expansion. -% \end{texnote} -% \end{function} -% -% \begin{function}[added = 2017-02-06] -% {\clist_sort:Nn, \clist_sort:cn, \clist_gsort:Nn, \clist_gsort:cn} -% \begin{syntax} -% \cs{clist_sort:Nn} \meta{clist var} \Arg{comparison code} -% \end{syntax} -% Sorts the items in the \meta{clist var} according to the -% \meta{comparison code}, and assigns the result to -% \meta{clist var}. The details of sorting comparison are -% described in Section~\ref{sec:l3sort:mech}. -% \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{clist~var} -% \cs{clist_if_empty:NTF} \meta{clist~var} \Arg{true code} \Arg{false code} -% \end{syntax} -% Tests if the \meta{clist~var} is empty (containing no items). -% \end{function} -% -% \begin{function}[EXP, pTF, added = 2014-07-05]{\clist_if_empty:n} -% \begin{syntax} -% \cs{clist_if_empty_p:n} \Arg{comma list} -% \cs{clist_if_empty:nTF} \Arg{comma list} \Arg{true code} \Arg{false code} -% \end{syntax} -% Tests if the \meta{clist~var} is empty (containing no items). -% The rules for space trimming are as for other \texttt{n}-type -% comma-list functions, hence the comma list |{~,~,,~}| (without -% outer braces) is empty, while |{~,{},}| (without outer braces) -% contains one element, which happens to be empty: the comma-list -% is not empty. -% \end{function} -% -% \begin{function}[updated = 2011-09-06, 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{clist~var} \Arg{item} \Arg{true code} \Arg{false code} -% \end{syntax} -% Tests if the \meta{item} is present in the \meta{clist~var}. -% In the case of an \texttt{n}-type \meta{comma list}, the usual rules -% of space trimming and brace stripping apply. Hence, -% \begin{verbatim} -% \clist_if_in:nnTF { a , {b}~ , {b} , c } { b } {true} {false} -% \end{verbatim} -% yields \texttt{true}. -% \begin{texnote} -% The function may fail if the \meta{item} contains |{|, |}|, or |#| -% (assuming the usual \TeX{} category codes apply). -% \end{texnote} -% \end{function} -% -% \section{Mapping over comma lists} -% -% The functions described in this section apply a specified function -% to each item of a comma list. -% All mappings are done at the current group level, \emph{i.e.}~any -% local assignments made by the \meta{function} or \meta{code} discussed -% below remain in effect after the loop. -% -% When the comma list is given explicitly, as an \texttt{n}-type argument, -% spaces are trimmed around each item. -% If the result of trimming spaces is empty, the item is ignored. -% Otherwise, if the item is surrounded by braces, one set is removed, -% and the result is passed to the mapped function. Thus, if the -% comma list that is being mapped is \verb*|{a , {{b} }, ,{}, {c},}| -% then the arguments passed to the mapped function are -% `\verb*|a|', `\verb*|{b} |', an empty argument, and `\verb*|c|'. -% -% When the comma list is given as an \texttt{N}-type argument, spaces -% have already been trimmed on input, and items are simply stripped -% of one set of braces if any. This case is more efficient than using -% \texttt{n}-type comma lists. -% -% \begin{function}[rEXP, updated = 2012-06-29] -% {\clist_map_function:NN, \clist_map_function:cN, \clist_map_function:nN, \clist_map_function:eN} -% \begin{syntax} -% \cs{clist_map_function:NN} \meta{clist~var} \meta{function} -% \end{syntax} -% Applies \meta{function} to every \meta{item} stored in the -% \meta{clist~var}. The \meta{function} receives 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}. -% \end{function} -% -% \begin{function}[updated = 2012-06-29] -% {\clist_map_inline:Nn, \clist_map_inline:cn, \clist_map_inline:nn} -% \begin{syntax} -% \cs{clist_map_inline:Nn} \meta{clist~var} \Arg{inline function} -% \end{syntax} -% Applies \meta{inline function} to every \meta{item} stored -% within the \meta{clist~var}. The \meta{inline function} should -% consist of code which receives the \meta{item} as |#1|. -% The \meta{items} are returned from left to right. -% \end{function} -% -% \begin{function}[updated = 2012-06-29] -% {\clist_map_variable:NNn, \clist_map_variable:cNn, \clist_map_variable:nNn} -% \begin{syntax} -% \cs{clist_map_variable:NNn} \meta{clist~var} \meta{variable} \Arg{code} -% \end{syntax} -% Stores each \meta{item} of the \meta{clist~var} in turn in the -% (token list) \meta{variable} and applies the \meta{code}. The -% \meta{code} will usually make use of the \meta{variable}, but this -% is not enforced. The assignments to the \meta{variable} are local. -% Its value after the loop is the last \meta{item} in the \meta{clist~var}, -% or its original value if there were no \meta{item}. The -% \meta{items} are returned from left to right. -% \end{function} -% -% \begin{function}[rEXP, added = 2021-05-05] -% {\clist_map_tokens:Nn, \clist_map_tokens:cn, \clist_map_tokens:nn} -% \begin{syntax} -% \cs{clist_map_tokens:Nn} \meta{clist~var} \Arg{code} -% \cs{clist_map_tokens:nn} \Arg{comma list} \Arg{code} -% \end{syntax} -% Calls \meta{code} \Arg{item} for every \meta{item} stored in the -% \meta{clist~var}. The \meta{code} receives each \meta{item} as a -% trailing brace group. If the \meta{code} consists of a single -% function this is equivalent to \cs{clist_map_function:nN}. -% \end{function} -% -% \begin{function}[rEXP, updated = 2012-06-29]{\clist_map_break:} -% \begin{syntax} -% \cs{clist_map_break:} -% \end{syntax} -% Used to terminate a \cs[no-index]{clist_map_\ldots{}} function before all -% entries in the \meta{comma list} have been processed. This -% normally takes 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[no-index]{clist_map_\ldots{}} scenario leads to low -% level \TeX{} errors. -% \begin{texnote} -% When the mapping is broken, additional tokens may be inserted -% before further items are taken -% from the input stream. This depends on the design of the mapping -% function. -% \end{texnote} -% \end{function} -% -% \begin{function}[updated = 2012-06-29, rEXP]{\clist_map_break:n} -% \begin{syntax} -% \cs{clist_map_break:n} \Arg{code} -% \end{syntax} -% Used to terminate a \cs[no-index]{clist_map_\ldots{}} function before all -% entries in the \meta{comma list} have been processed, inserting -% the \meta{code} after the mapping has ended. This -% normally takes 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 { } } -% { -% % Do something useful -% } -% } -% \end{verbatim} -% Use outside of a \cs[no-index]{clist_map_\ldots{}} scenario leads to low -% level \TeX{} errors. -% \begin{texnote} -% When the mapping is broken, additional tokens may be inserted -% before the \meta{code} is -% inserted into the input stream. -% This depends on the design of the mapping function. -% \end{texnote} -% \end{function} -% -% \begin{function}[EXP, added = 2012-07-13] -% {\clist_count:N, \clist_count:c, \clist_count:n, \clist_count:e} -% \begin{syntax} -% \cs{clist_count:N} \meta{clist~var} -% \end{syntax} -% Leaves the number of items in the \meta{clist~var} in the input -% stream as an \meta{integer denotation}. The total number of items -% in a \meta{clist~var} includes those which are duplicates, -% \emph{i.e.}~every item in a \meta{clist~var} is counted. -% \end{function} -% -% \section{Using the content of comma lists directly} -% -% \begin{function}[EXP, added = 2013-05-26]{\clist_use:Nnnn, \clist_use:cnnn} -% \begin{syntax} -% \cs{clist_use:Nnnn} \meta{clist~var} \Arg{separator~between~two} \Arg{separator~between~more~than~two} \Arg{separator~between~final~two} -% \end{syntax} -% Places the contents of the \meta{clist~var} in the input stream, -% with the appropriate \meta{separator} between the items. Namely, if -% the comma list has more than two items, the \meta{separator between -% more than two} is placed between each pair of items except the -% last, for which the \meta{separator between final two} is used. If -% the comma list has exactly two items, then they are placed in the input -% stream separated by the \meta{separator between two}. If the comma -% list has a single item, it is placed in the input stream, and a comma -% list with no items produces no output. An error is raised if -% the variable does not exist or if it is invalid. -% -% For example, -% \begin{verbatim} -% \clist_set:Nn \l_tmpa_clist { a , b , , c , {de} , f } -% \clist_use:Nnnn \l_tmpa_clist { ~and~ } { ,~ } { ,~and~ } -% \end{verbatim} -% inserts \enquote{\texttt{a, b, c, de, and f}} in the input -% stream. The first separator argument is not used in this case -% because the comma list has more than $2$ items. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{items} -% do not expand further when appearing in an \texttt{e}-type -% or \texttt{x}-type argument expansion. -% \end{texnote} -% \end{function} -% -% \begin{function}[EXP, added = 2013-05-26]{\clist_use:Nn, \clist_use:cn} -% \begin{syntax} -% \cs{clist_use:Nn} \meta{clist~var} \Arg{separator} -% \end{syntax} -% Places the contents of the \meta{clist~var} in the input stream, -% with the \meta{separator} between the items. If the comma -% list has a single item, it is placed in the input stream, and a comma -% list with no items produces no output. An error is raised if -% the variable does not exist or if it is invalid. -% -% For example, -% \begin{verbatim} -% \clist_set:Nn \l_tmpa_clist { a , b , , c , {de} , f } -% \clist_use:Nn \l_tmpa_clist { ~and~ } -% \end{verbatim} -% inserts \enquote{\texttt{a and b and c and de and f}} in the input -% stream. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{items} -% do not expand further when appearing in an \texttt{e}-type -% or \texttt{x}-type argument expansion. -% \end{texnote} -% \end{function} -% -% \begin{function}[EXP, added = 2021-05-10]{\clist_use:nnnn, \clist_use:nn} -% \begin{syntax} -% \cs{clist_use:nnnn} \meta{comma~list} \Arg{separator~between~two} \Arg{separator~between~more~than~two} \Arg{separator~between~final~two} -% \cs{clist_use:nn} \meta{comma~list} \Arg{separator} -% \end{syntax} -% Places the contents of the \meta{comma~list} in the input stream, -% with the appropriate \meta{separator} between the items. As for -% \cs{clist_set:Nn}, blank items are omitted, spaces are removed from -% both sides of each item, then a set of braces is removed if the -% resulting space-trimmed item is braced. The \meta{separators} are -% then inserted in the same way as for \cs{clist_use:Nnnn} and -% \cs{clist_use:Nn}, respectively. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{items} -% do not expand further when appearing in an \texttt{e}-type -% or \texttt{x}-type argument expansion. -% \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}[noTF, added = 2012-05-14, updated = 2019-02-16] -% {\clist_get:NN, \clist_get:cN} -% \begin{syntax} -% \cs{clist_get:NN} \meta{clist~var} \meta{token list variable} -% \end{syntax} -% Stores the left-most item from a \meta{clist~var} in the -% \meta{token list variable} without removing it from the -% \meta{clist~var}. The \meta{token list variable} is assigned locally. -% In the non-branching version, if the \meta{clist~var} is empty the -% \meta{token list variable} is set to the marker value \cs{q_no_value}. -% \end{function} -% -% \begin{function}[updated = 2011-09-06]{\clist_pop:NN, \clist_pop:cN} -% \begin{syntax} -% \cs{clist_pop:NN} \meta{clist~var} \meta{token list variable} -% \end{syntax} -% Pops the left-most item from a \meta{clist~var} 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{clist~var} \meta{token list variable} -% \end{syntax} -% Pops the left-most item from a \meta{clist~var} 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{clist~var} is modified globally, while the assignment of -% the \meta{token list variable} is local. -% \end{function} -% -% \begin{function}[TF, added = 2012-05-14]{\clist_pop:NN, \clist_pop:cN} -% \begin{syntax} -% \cs{clist_pop:NNTF} \meta{clist~var} \meta{token list variable} \Arg{true code} \Arg{false code} -% \end{syntax} -% If the \meta{clist~var} is empty, leaves the \meta{false code} in the -% input stream. The value of the \meta{token list variable} is -% not defined in this case and should not be relied upon. If the -% \meta{clist~var} is non-empty, pops the top item from the -% \meta{clist~var} in the \meta{token list variable}, \emph{i.e.}~removes -% the item from the \meta{clist~var}. Both the \meta{clist~var} and the -% \meta{token list variable} are assigned locally. -% \end{function} -% -% \begin{function}[TF, added = 2012-05-14]{\clist_gpop:NN, \clist_gpop:cN} -% \begin{syntax} -% \cs{clist_gpop:NNTF} \meta{clist~var} \meta{token list variable} \Arg{true code} \Arg{false code} -% \end{syntax} -% If the \meta{clist~var} is empty, leaves the \meta{false code} in the -% input stream. The value of the \meta{token list variable} is -% not defined in this case and should not be relied upon. If the -% \meta{clist~var} is non-empty, pops the top item from the -% \meta{clist~var} in the \meta{token list variable}, \emph{i.e.}~removes -% the item from the \meta{clist~var}. The \meta{clist~var} is modified -% globally, while the \meta{token list variable} is assigned locally. -% \end{function} -% -% \begin{function} -% { -% \clist_push:Nn, \clist_push:NV, \clist_push:No, -% \clist_push:cn, \clist_push:cV, \clist_push:co, -% \clist_gpush:Nn, \clist_gpush:NV, \clist_gpush:No, -% \clist_gpush:cn, \clist_gpush:cV, \clist_gpush:co, -% } -% \begin{syntax} -% \cs{clist_push:Nn} \meta{clist~var} \Arg{items} -% \end{syntax} -% Adds the \Arg{items} to the top of the \meta{clist~var}. -% Spaces are removed from both sides of each item as for any -% \texttt{n}-type comma list. -% \end{function} -% -% \section{Using a single item} -% -% \begin{function}[added = 2014-07-17, EXP] -% {\clist_item:Nn, \clist_item:cn, \clist_item:nn, \clist_item:en} -% \begin{syntax} -% \cs{clist_item:Nn} \meta{clist~var} \Arg{int expr} -% \end{syntax} -% Indexing items in the \meta{clist~var} from~$1$ at the top (left), this -% function evaluates the \meta{int expr} and leaves the -% appropriate item from the comma list in the input stream. If the -% \meta{int expr} is negative, indexing occurs from the -% bottom (right) of the comma list. When the \meta{int expr} -% is larger than the number of items in the \meta{clist~var} (as -% calculated by \cs{clist_count:N}) then the function expands to -% nothing. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{item} -% does not expand further when appearing in an \texttt{e}-type -% or \texttt{x}-type argument expansion. -% \end{texnote} -% \end{function} -% -% \begin{function}[EXP, added = 2016-12-06] -% {\clist_rand_item:N, \clist_rand_item:n, \clist_rand_item:c} -% \begin{syntax} -% \cs{clist_rand_item:N} \meta{clist~var} -% \cs{clist_rand_item:n} \Arg{comma list} -% \end{syntax} -% Selects a pseudo-random item of the \meta{clist~var}/\meta{comma list}. -% If the \meta{comma list} has no item, the result is empty. -% \begin{texnote} -% The result is returned within the \tn{unexpanded} -% primitive (\cs{exp_not:n}), which means that the \meta{item} -% does not expand further when appearing in an \texttt{e}-type -% or \texttt{x}-type argument expansion. -% \end{texnote} -% \end{function} -% -% \section{Viewing comma lists} -% -% \begin{function}[updated = 2021-04-29]{\clist_show:N, \clist_show:c} -% \begin{syntax} -% \cs{clist_show:N} \meta{clist~var} -% \end{syntax} -% Displays the entries in the \meta{clist~var} in the terminal. -% \end{function} -% -% \begin{function}[updated = 2013-08-03]{\clist_show:n} -% \begin{syntax} -% \cs{clist_show:n} \Arg{tokens} -% \end{syntax} -% Displays the entries in the comma list in the terminal. -% \end{function} -% -% \begin{function}[added = 2014-08-22, updated = 2021-04-29]{\clist_log:N, \clist_log:c} -% \begin{syntax} -% \cs{clist_log:N} \meta{clist~var} -% \end{syntax} -% Writes the entries in the \meta{clist~var} in the log file. See -% also \cs{clist_show:N} which displays the result in the terminal. -% \end{function} -% -% \begin{function}[added = 2014-08-22]{\clist_log:n} -% \begin{syntax} -% \cs{clist_log:n} \Arg{tokens} -% \end{syntax} -% Writes the entries in the comma list in the log file. See also -% \cs{clist_show:n} which displays the result in the terminal. -% \end{function} -% -% \section{Constant and scratch comma lists} -% -% \begin{variable}[added = 2012-07-02]{\c_empty_clist} -% Constant that is always empty. -% \end{variable} -% -% \begin{variable}[added = 2011-09-06]{\l_tmpa_clist, \l_tmpb_clist} -% Scratch comma lists for local assignment. These are never used by -% the kernel code, and so are safe for use with any \LaTeX3-defined -% function. However, they may be overwritten by other non-kernel -% code and so should only be used for short-term storage. -% \end{variable} -% -% \begin{variable}[added = 2011-09-06]{\g_tmpa_clist, \g_tmpb_clist} -% Scratch comma lists for global assignment. These are never used by -% the kernel code, and so are safe for use with any \LaTeX3-defined -% function. However, they may be overwritten by other non-kernel -% code and so should only be used for short-term storage. -% \end{variable} -% -% \end{documentation} -% -% \begin{implementation} -% -% \section{\pkg{l3clist} implementation} -% -% \TestFiles{m3clist002} -% -% \begin{macrocode} -%<*package> -% \end{macrocode} -% -% \begin{macrocode} -%<@@=clist> -% \end{macrocode} -% -% \begin{variable}{\c_empty_clist} -% An empty comma list is simply an empty token list. -% \begin{macrocode} -\cs_new_eq:NN \c_empty_clist \c_empty_tl -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\l_@@_internal_clist} -% Scratch space for various internal uses. This comma list variable -% cannot be declared as such because it comes before \cs{clist_new:N} -% \begin{macrocode} -\tl_new:N \l_@@_internal_clist -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\s_@@_mark,\s_@@_stop} -% Internal scan marks. -% \begin{macrocode} -\scan_new:N \s_@@_mark -\scan_new:N \s_@@_stop -% \end{macrocode} -% \end{variable} -% -% \begin{macro}[EXP]{ -% \@@_use_none_delimit_by_s_mark:w, -% \@@_use_none_delimit_by_s_stop:w, -% \@@_use_i_delimit_by_s_stop:nw -% } -% Functions to gobble up to a scan mark. -% \begin{macrocode} -\cs_new:Npn \@@_use_none_delimit_by_s_mark:w #1 \s_@@_mark { } -\cs_new:Npn \@@_use_none_delimit_by_s_stop:w #1 \s_@@_stop { } -\cs_new:Npn \@@_use_i_delimit_by_s_stop:nw #1 #2 \s_@@_stop {#1} -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\@@_tmp:w} -% A temporary function for various purposes. -% \begin{macrocode} -\cs_new_protected:Npn \@@_tmp:w { } -% \end{macrocode} -% \end{macro} -% -% \subsection{Removing spaces around items} -% -% \begin{macro}{\@@_trim_next:w} -% Called as \cs{exp:w} \cs{@@_trim_next:w} \cs{prg_do_nothing:} -% \meta{comma list} \ldots{} it expands to \Arg{trimmed item} where -% the \meta{trimmed item} is the first non-empty result from removing -% spaces from both ends of comma-delimited items in the \meta{comma -% list}. The \cs{prg_do_nothing:} marker avoids losing braces. The -% test for blank items is a somewhat optimized \cs{tl_if_empty:oTF} -% construction; if blank, another item is sought, otherwise trim -% spaces. -% \begin{macrocode} -\cs_new:Npn \@@_trim_next:w #1 , - { - \tl_if_empty:oTF { \use_none:nn #1 ? } - { \@@_trim_next:w \prg_do_nothing: } - { \tl_trim_spaces_apply:oN {#1} \exp_end: } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[rEXP]{\@@_sanitize:n} -% \begin{macro}{\@@_sanitize:Nn} -% The auxiliary \cs{@@_sanitize:Nn} receives a delimiter -% (\cs{c_empty_tl} the first time, afterwards a comma) and that item -% as arguments. Unless we are done with the loop it calls -% \cs{@@_wrap_item:w} to unbrace the item (using a comma delimiter is -% safe since |#2| came from removing spaces from an argument delimited -% by a comma) and possibly re-brace it if needed. -% \begin{macrocode} -\cs_new:Npn \@@_sanitize:n #1 - { - \exp_after:wN \@@_sanitize:Nn \exp_after:wN \c_empty_tl - \exp:w \@@_trim_next:w \prg_do_nothing: - #1 , \s_@@_stop \prg_break: , \prg_break_point: - } -\cs_new:Npn \@@_sanitize:Nn #1#2 - { - \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop - #1 \@@_wrap_item:w #2 , - \exp_after:wN \@@_sanitize:Nn \exp_after:wN , - \exp:w \@@_trim_next:w \prg_do_nothing: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[TF]{\@@_if_wrap:n} -% \begin{macro}{\@@_if_wrap:w} -% True if the argument must be wrapped to avoid getting altered by some -% clist operations. That is the case whenever the argument -% \begin{itemize} -% \item starts or end with a space or contains a comma, -% \item is empty, or -% \item consists of a single braced group. -% \end{itemize} -% If the argument starts or ends with a space or contains -% a comma then one of the three arguments of \cs{@@_if_wrap:w} will -% have its end delimiter (partly) in one of the three copies of |#1| -% in \cs{@@_if_wrap:nTF}; this has a knock-on effect meaning that the -% result of the expansion is not empty; in that case, wrap. -% Otherwise, the argument is safe unless it starts with a brace group -% (or is empty) and it is empty or consists of a single -% \texttt{n}-type argument. -% \begin{macrocode} -\prg_new_conditional:Npnn \@@_if_wrap:n #1 { TF } - { - \tl_if_empty:oTF - { - \@@_if_wrap:w - \s_@@_mark ? #1 ~ \s_@@_mark ? ~ #1 - \s_@@_mark , ~ \s_@@_mark #1 , - } - { - \tl_if_head_is_group:nTF { #1 { } } - { - \tl_if_empty:nTF {#1} - { \prg_return_true: } - { - \tl_if_empty:oTF { \use_none:n #1} - { \prg_return_true: } - { \prg_return_false: } - } - } - { \prg_return_false: } - } - { \prg_return_true: } - } -\cs_new:Npn \@@_if_wrap:w #1 \s_@@_mark ? ~ #2 ~ \s_@@_mark #3 , { } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\@@_wrap_item:w} -% Safe items are put in \cs{exp_not:n}, otherwise we put an extra set -% of braces. -% \begin{macrocode} -\cs_new:Npn \@@_wrap_item:w #1 , - { \@@_if_wrap:nTF {#1} { \exp_not:n { {#1} } } { \exp_not:n {#1} } } -% \end{macrocode} -% \end{macro} -% -% \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_const:Nn, \clist_const:Ne, \clist_const:Nx, -% \clist_const:cn, \clist_const:ce, \clist_const:cx -% } -% Creating and initializing a constant comma list is done by -% sanitizing all items (stripping spaces and braces). -% \begin{macrocode} -\cs_new_protected:Npn \clist_const:Nn #1#2 - { \tl_const:Ne #1 { \@@_sanitize:n {#2} } } -\cs_generate_variant:Nn \clist_const:Nn { Ne , c , ce } -\cs_generate_variant:Nn \clist_const:Nn { Nx , cx } -% \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_set_from_seq:NN, \clist_set_from_seq:cN, -% \clist_set_from_seq:Nc, \clist_set_from_seq:cc -% } -% \UnitTested -% \begin{macro} -% { -% \clist_gset_from_seq:NN, \clist_gset_from_seq:cN, -% \clist_gset_from_seq:Nc, \clist_gset_from_seq:cc -% } -% \UnitTested -% \begin{macro}{\@@_set_from_seq:NNNN, \@@_set_from_seq:n} -% Setting a comma list from a comma-separated list is done using a -% simple mapping. Safe items are put in \cs{exp_not:n}, otherwise we -% put an extra set of braces. 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 - { \@@_set_from_seq:NNNN \clist_clear:N \__kernel_tl_set:Nx } -\cs_new_protected:Npn \clist_gset_from_seq:NN - { \@@_set_from_seq:NNNN \clist_gclear:N \__kernel_tl_gset:Nx } -\cs_new_protected:Npn \@@_set_from_seq:NNNN #1#2#3#4 - { - \seq_if_empty:NTF #4 - { #1 #3 } - { - #2 #3 - { - \exp_after:wN \use_none:n \exp:w \exp_end_continue_f:w - \seq_map_function:NN #4 \@@_set_from_seq:n - } - } - } -\cs_new:Npn \@@_set_from_seq:n #1 - { - , - \@@_if_wrap:nTF {#1} - { \exp_not:n { {#1} } } - { \exp_not:n {#1} } - } -\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} -% \end{macro} -% -% \begin{macro}{\clist_concat:NNN, \clist_concat:ccc} -% \UnitTested -% \begin{macro}{\clist_gconcat:NNN, \clist_gconcat:ccc} -% \UnitTested -% \begin{macro}{\@@_concat:NNNN} -% Concatenating comma lists is not quite as easy as it seems, as -% there needs to be the correct addition of a comma to the output. So -% a little work to do. -% \begin{macrocode} -\cs_new_protected:Npn \clist_concat:NNN - { \@@_concat:NNNN \__kernel_tl_set:Nx } -\cs_new_protected:Npn \clist_gconcat:NNN - { \@@_concat:NNNN \__kernel_tl_gset:Nx } -\cs_new_protected:Npn \@@_concat:NNNN #1#2#3#4 - { - #1 #2 - { - \exp_not:o #3 - \clist_if_empty:NF #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} -% -% \begin{macro}[pTF]{\clist_if_exist:N, \clist_if_exist:c} -% Copies of the \texttt{cs} functions defined in \pkg{l3basics}. -% \begin{macrocode} -\prg_new_eq_conditional:NNn \clist_if_exist:N \cs_if_exist:N - { TF , T , F , p } -\prg_new_eq_conditional:NNn \clist_if_exist:c \cs_if_exist:c - { TF , T , F , p } -% \end{macrocode} -% \end{macro} -% -% \subsection{Adding data to comma lists} -% -% \begin{macro} -% { -% \clist_set:Nn, \clist_set:NV, \clist_set:Ne, -% \clist_set:No, \clist_set:Nx, -% \clist_set:cn, \clist_set:cV, \clist_set:ce, -% \clist_set:co, \clist_set:cx -% } -% \begin{macro} -% { -% \clist_gset:Nn, \clist_gset:NV, \clist_gset:Ne, -% \clist_gset:No, \clist_gset:Nx, -% \clist_gset:cn, \clist_gset:cV, \clist_gset:ce, -% \clist_gset:co, \clist_gset:cx, -% } -% \begin{macrocode} -\cs_new_protected:Npn \clist_set:Nn #1#2 - { \__kernel_tl_set:Nx #1 { \@@_sanitize:n {#2} } } -\cs_new_protected:Npn \clist_gset:Nn #1#2 - { \__kernel_tl_gset:Nx #1 { \@@_sanitize:n {#2} } } -\cs_generate_variant:Nn \clist_set:Nn { NV , Ne , c , cV , ce } -\cs_generate_variant:Nn \clist_set:Nn { No , Nx , co , cx } -\cs_generate_variant:Nn \clist_gset:Nn { NV , Ne , c , cV , ce } -\cs_generate_variant:Nn \clist_gset:Nn { No , Nx , co , cx } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \clist_put_left:Nn, \clist_put_left:NV, -% \clist_put_left:Nv, \clist_put_left:Ne, -% \clist_put_left:No, \clist_put_left:Nx, -% \clist_put_left:cn, \clist_put_left:cV, -% \clist_put_left:cv, \clist_put_left:ce, -% \clist_put_left:co, \clist_put_left:cx, -% } -% \UnitTested -% \begin{macro} -% { -% \clist_gput_left:Nn, \clist_gput_left:NV, -% \clist_gput_left:Nv, \clist_gput_left:Ne, -% \clist_gput_left:No, \clist_gput_left:Nx, -% \clist_gput_left:cn, \clist_gput_left:cV, -% \clist_gput_left:cv, \clist_gput_left:ce, -% \clist_gput_left:co, \clist_gput_left:cx, -% } -% \UnitTested -% \begin{macro}{\@@_put_left:NNNn} -% Everything is based on concatenation after storing in -% \cs{l_@@_internal_clist}. This avoids having to worry here about -% space-trimming and so on. -% \begin{macrocode} -\cs_new_protected:Npn \clist_put_left:Nn - { \@@_put_left:NNNn \clist_concat:NNN \clist_set:Nn } -\cs_new_protected:Npn \clist_gput_left:Nn - { \@@_put_left:NNNn \clist_gconcat:NNN \clist_set:Nn } -\cs_new_protected:Npn \@@_put_left:NNNn #1#2#3#4 - { - #2 \l_@@_internal_clist {#4} - #1 #3 \l_@@_internal_clist #3 - } -\cs_generate_variant:Nn \clist_put_left:Nn { NV , Nv , Ne , c , cV , cv , ce } -\cs_generate_variant:Nn \clist_put_left:Nn { No , Nx , co , cx } -\cs_generate_variant:Nn \clist_gput_left:Nn { NV , Nv , Ne , c , cV , cv , ce } -\cs_generate_variant:Nn \clist_gput_left:Nn { No , Nx , co , cx } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \clist_put_right:Nn, \clist_put_right:NV, -% \clist_put_right:Nv, \clist_put_right:Ne, -% \clist_put_right:No, \clist_put_right:Nx, -% \clist_put_right:cn, \clist_put_right:cV, -% \clist_put_right:cv, \clist_put_right:ce, -% \clist_put_right:co, \clist_put_right:cx -% } -% \UnitTested -% \begin{macro} -% { -% \clist_gput_right:Nn, \clist_gput_right:NV, -% \clist_gput_right:Nv, \clist_gput_right:Ne, -% \clist_gput_right:No, \clist_gput_right:Nx, -% \clist_gput_right:cn, \clist_gput_right:cV, -% \clist_gput_right:cv, \clist_gput_right:ce, -% \clist_gput_right:cx, \clist_gput_right:co -% } -% \UnitTested -% \begin{macro}{\@@_put_right:NNNn} -% \begin{macrocode} -\cs_new_protected:Npn \clist_put_right:Nn - { \@@_put_right:NNNn \clist_concat:NNN \clist_set:Nn } -\cs_new_protected:Npn \clist_gput_right:Nn - { \@@_put_right:NNNn \clist_gconcat:NNN \clist_set:Nn } -\cs_new_protected:Npn \@@_put_right:NNNn #1#2#3#4 - { - #2 \l_@@_internal_clist {#4} - #1 #3 #3 \l_@@_internal_clist - } -\cs_generate_variant:Nn \clist_put_right:Nn - { NV , Nv , Ne , c , cV , cv , ce } -\cs_generate_variant:Nn \clist_put_right:Nn - { No , Nx , co , cx } -\cs_generate_variant:Nn \clist_gput_right:Nn - { NV , Nv , Ne , c , cV , cv , ce } -\cs_generate_variant:Nn \clist_gput_right:Nn - { No , Nx , co , cx } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Comma lists as stacks} -% -% \begin{macro}{\clist_get:NN, \clist_get:cN} -% \UnitTested -% \begin{macro}{\@@_get:wN} -% Getting an item from the left of a comma list is pretty easy: just -% trim off the first item using the comma. No need to trim spaces as -% comma-list \emph{variables} are assumed to have \enquote{cleaned-up} -% items. (Note that grabbing a comma-delimited item removes an outer -% pair of braces if present, exactly as needed to uncover the -% underlying item.) -% \begin{macrocode} -\cs_new_protected:Npn \clist_get:NN #1#2 - { - \if_meaning:w #1 \c_empty_clist - \tl_set:Nn #2 { \q_no_value } - \else: - \exp_after:wN \@@_get:wN #1 , \s_@@_stop #2 - \fi: - } -\cs_new_protected:Npn \@@_get:wN #1 , #2 \s_@@_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} -% {\@@_pop:NNN, \@@_pop:wwNNN, \@@_pop:wN} -% An empty clist leads to \cs{q_no_value}, otherwise grab until the -% first comma and assign to the variable. The second argument of -% \cs{@@_pop:wwNNN} is a comma list ending in a comma and -% \cs{s_@@_mark}, unless the original clist contained exactly one item: -% then the argument is just \cs{s_@@_mark}. The next auxiliary picks -% either \cs{exp_not:n} or \cs{use_none:n} as |#2|, ensuring that the -% result can safely be an empty comma list. -% \begin{macrocode} -\cs_new_protected:Npn \clist_pop:NN - { \@@_pop:NNN \__kernel_tl_set:Nx } -\cs_new_protected:Npn \clist_gpop:NN - { \@@_pop:NNN \__kernel_tl_gset:Nx } -\cs_new_protected:Npn \@@_pop:NNN #1#2#3 - { - \if_meaning:w #2 \c_empty_clist - \tl_set:Nn #3 { \q_no_value } - \else: - \exp_after:wN \@@_pop:wwNNN #2 , \s_@@_mark \s_@@_stop #1#2#3 - \fi: - } -\cs_new_protected:Npn \@@_pop:wwNNN #1 , #2 \s_@@_stop #3#4#5 - { - \tl_set:Nn #5 {#1} - #3 #4 - { - \@@_pop:wN \prg_do_nothing: - #2 \exp_not:o - , \s_@@_mark \use_none:n - \s_@@_stop - } - } -\cs_new:Npn \@@_pop:wN #1 , \s_@@_mark #2 #3 \s_@@_stop { #2 {#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} -% -% \begin{macro}[TF]{\clist_get:NN, \clist_get:cN} -% \begin{macro}[TF]{\clist_pop:NN, \clist_pop:cN} -% \begin{macro}[TF]{\clist_gpop:NN, \clist_gpop:cN} -% \begin{macro}{\@@_pop_TF:NNN} -% The same, as branching code: very similar to the above. -% \begin{macrocode} -\prg_new_protected_conditional:Npnn \clist_get:NN #1#2 { T , F , TF } - { - \if_meaning:w #1 \c_empty_clist - \prg_return_false: - \else: - \exp_after:wN \@@_get:wN #1 , \s_@@_stop #2 - \prg_return_true: - \fi: - } -\prg_generate_conditional_variant:Nnn \clist_get:NN { c } { T , F , TF } -\prg_new_protected_conditional:Npnn \clist_pop:NN #1#2 { T , F , TF } - { \@@_pop_TF:NNN \__kernel_tl_set:Nx #1 #2 } -\prg_new_protected_conditional:Npnn \clist_gpop:NN #1#2 { T , F , TF } - { \@@_pop_TF:NNN \__kernel_tl_gset:Nx #1 #2 } -\cs_new_protected:Npn \@@_pop_TF:NNN #1#2#3 - { - \if_meaning:w #2 \c_empty_clist - \prg_return_false: - \else: - \exp_after:wN \@@_pop:wwNNN #2 , \s_@@_mark \s_@@_stop #1#2#3 - \prg_return_true: - \fi: - } -\prg_generate_conditional_variant:Nnn \clist_pop:NN { c } { T , F , TF } -\prg_generate_conditional_variant:Nnn \clist_gpop:NN { c } { T , F , TF } -% \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 comma list is the same as adding on the left. -% \begin{macrocode} -\cs_new_eq:NN \clist_push:Nn \clist_put_left:Nn -\cs_generate_variant:Nn \clist_push:Nn { NV , No , Nx , c , cV , co , cx } -\cs_new_eq:NN \clist_gpush:Nn \clist_gput_left:Nn -\cs_generate_variant:Nn \clist_gpush:Nn { NV , No , Nx , c , cV , co , cx } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsection{Modifying comma lists} -% -% \begin{variable}{\l_@@_internal_remove_clist, \l_@@_internal_remove_seq} -% An internal comma list and a sequence for the removal routines. -% \begin{macrocode} -\clist_new:N \l_@@_internal_remove_clist -\seq_new:N \l_@@_internal_remove_seq -% \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}{\@@_remove_duplicates:NN} -% Removing duplicates means making a new list then copying it. -% \begin{macrocode} -\cs_new_protected:Npn \clist_remove_duplicates:N - { \@@_remove_duplicates:NN \clist_set_eq:NN } -\cs_new_protected:Npn \clist_gremove_duplicates:N - { \@@_remove_duplicates:NN \clist_gset_eq:NN } -\cs_new_protected:Npn \@@_remove_duplicates:NN #1#2 - { - \clist_clear:N \l_@@_internal_remove_clist - \clist_map_inline:Nn #2 - { - \clist_if_in:NnF \l_@@_internal_remove_clist {##1} - { - \tl_put_right:Ne \l_@@_internal_remove_clist - { - \clist_if_empty:NF \l_@@_internal_remove_clist { , } - \@@_if_wrap:nTF {##1} { \exp_not:n { {##1} } } { \exp_not:n {##1} } - } - } - } - #1 #2 \l_@@_internal_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, -% \clist_remove_all:NV, \clist_remove_all:cV -% } -% \UnitTested -% \begin{macro} -% { -% \clist_gremove_all:Nn, \clist_gremove_all:cn, -% \clist_gremove_all:NV, \clist_gremove_all:cV -% } -% \UnitTested -% \begin{macro}{\@@_remove_all:NNNn} -% \begin{macro}{\@@_remove_all:w} -% \begin{macro}{\@@_remove_all:} -% The method used here for safe items is very similar to -% \cs{tl_replace_all:Nnn}. However, if the item contains commas or -% leading/trailing spaces, or is empty, or consists of a single brace -% group, we know that it can only appear within braces so the code -% would fail; instead just convert to a sequence and do the removal -% with \pkg{l3seq} code (it involves somewhat elaborate code to do -% most of the work expandably but the final token list comparisons -% non-expandably). -% -% For \enquote{safe} items, build a function delimited by the -% \meta{item} that should be removed, -% surrounded with commas, and call that function followed by -% the expanded comma list, and another copy of the \meta{item}. -% The loop is controlled by the argument grabbed by -% \cs{@@_remove_all:w}: when the item was found, -% the \cs{s_@@_mark} delimiter used is the one inserted by -% \cs{@@_tmp:w}, and \cs{@@_use_none_delimit_by_s_stop:w} -% is deleted. At the end, the final \meta{item} is -% grabbed, and the argument of \cs{@@_tmp:w} contains -% \cs{s_@@_mark}: in that case, \cs{@@_remove_all:w} -% removes the second \cs{s_@@_mark} (inserted by \cs{@@_tmp:w}), -% and lets \cs{@@_use_none_delimit_by_s_stop:w} act. -% -% No brace is lost because items are always grabbed with a leading comma. -% The result of the first assignment has an extra leading comma, -% which we remove in a second assignment. -% Two exceptions: if the clist lost all of its elements, the result -% is empty, and we shouldn't remove anything; if the clist started up -% empty, the first step happens to turn it into a single comma, and -% the second step removes it. -% \begin{macrocode} -\cs_new_protected:Npn \clist_remove_all:Nn - { \@@_remove_all:NNNn \clist_set_from_seq:NN \__kernel_tl_set:Nx } -\cs_new_protected:Npn \clist_gremove_all:Nn - { \@@_remove_all:NNNn \clist_gset_from_seq:NN \__kernel_tl_gset:Nx } -\cs_new_protected:Npn \@@_remove_all:NNNn #1#2#3#4 - { - \@@_if_wrap:nTF {#4} - { - \seq_set_from_clist:NN \l_@@_internal_remove_seq #3 - \seq_remove_all:Nn \l_@@_internal_remove_seq {#4} - #1 #3 \l_@@_internal_remove_seq - } - { - \cs_set:Npn \@@_tmp:w ##1 , #4 , - { - ##1 - , \s_@@_mark , \@@_use_none_delimit_by_s_stop:w , - \@@_remove_all: - } - #2 #3 - { - \exp_after:wN \@@_remove_all: - #3 , \s_@@_mark , #4 , \s_@@_stop - } - \clist_if_empty:NF #3 - { - #2 #3 - { - \exp_args:No \exp_not:o - { \exp_after:wN \use_none:n #3 } - } - } - } - } -\cs_new:Npn \@@_remove_all: - { \exp_after:wN \@@_remove_all:w \@@_tmp:w , } -\cs_new:Npn \@@_remove_all:w #1 , \s_@@_mark , #2 , { \exp_not:n {#1} } -\cs_generate_variant:Nn \clist_remove_all:Nn { c , NV , cV } -\cs_generate_variant:Nn \clist_gremove_all:Nn { c , NV , cV } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \clist_reverse:N, \clist_reverse:c, -% \clist_greverse:N, \clist_greverse:c -% } -% Use \cs{clist_reverse:n} in an \texttt{e}-expanding assignment. The -% extra work that \cs{clist_reverse:n} does to preserve braces and -% spaces would not be needed for the well-controlled case of -% \texttt{N}-type comma lists, but the slow-down is not too bad. -% \begin{macrocode} -\cs_new_protected:Npn \clist_reverse:N #1 - { \__kernel_tl_set:Nx #1 { \exp_args:No \clist_reverse:n {#1} } } -\cs_new_protected:Npn \clist_greverse:N #1 - { \__kernel_tl_gset:Nx #1 { \exp_args:No \clist_reverse:n {#1} } } -\cs_generate_variant:Nn \clist_reverse:N { c } -\cs_generate_variant:Nn \clist_greverse:N { c } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[EXP]{\clist_reverse:n} -% \begin{macro}[EXP]{\@@_reverse:wwNww, \@@_reverse_end:ww} -% The reversed token list is built one item at a time, and stored -% between \cs{s_@@_stop} and \cs{s_@@_mark}, in the form of |?| followed by -% zero or more instances of \enquote{\meta{item}\texttt{,}}. We start from a comma -% list \enquote{\meta{item_1}\texttt{,\ldots,}\meta{item_n}}. During the loop, -% the auxiliary \cs{@@_reverse:wwNww} receives \enquote{\texttt{?}\meta{item_i}} as -% |#1|, \enquote{\meta{item_{i+1}}\texttt{,\ldots,}\meta{item_n}} as |#2|, -% \cs{@@_reverse:wwNww} as |#3|, what remains until \cs{s_@@_stop} as -% |#4|, and \enquote{\meta{item_{i-1}}\texttt{,\ldots,}\meta{item_1}\texttt{,}} as |#5|. -% The auxiliary moves |#1| just before |#5|, with a comma, and calls -% itself (|#3|). After the last item is moved, \cs{@@_reverse:wwNww} -% receives \enquote{\cs{s_@@_mark} \cs{@@_reverse:wwNww} \texttt{!}} as its argument -% |#1|, thus \cs{@@_reverse_end:ww} as its argument |#3|. This second -% auxiliary cleans up until the marker~|!|, removes the trailing comma -% (introduced when the first item was moved after \cs{s_@@_stop}), and -% leaves its argument~|#1| within \cs{exp_not:n}. There is also a -% need to remove a leading comma, hence \cs{exp_not:o} and -% \cs{use_none:n}. -% \begin{macrocode} -\cs_new:Npn \clist_reverse:n #1 - { - \@@_reverse:wwNww ? #1 , - \s_@@_mark \@@_reverse:wwNww ! , - \s_@@_mark \@@_reverse_end:ww - \s_@@_stop ? \s_@@_mark - } -\cs_new:Npn \@@_reverse:wwNww - #1 , #2 \s_@@_mark #3 #4 \s_@@_stop ? #5 \s_@@_mark - { #3 ? #2 \s_@@_mark #3 #4 \s_@@_stop #1 , #5 \s_@@_mark } -\cs_new:Npn \@@_reverse_end:ww #1 ! #2 , \s_@@_mark - { \exp_not:o { \use_none:n #2 } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% {\clist_sort:Nn, \clist_sort:cn, \clist_gsort:Nn, \clist_gsort:cn} -% Implemented in \pkg{l3sort}. -% \end{macro} -% -% \subsection{Comma list conditionals} -% -% \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}[EXP, pTF]{\clist_if_empty:n} -% \begin{macro}[EXP]{\@@_if_empty_n:w} -% \begin{macro}[EXP]{\@@_if_empty_n:wNw} -% As usual, we insert a token (here |?|) before grabbing -% any argument: this avoids losing braces. The argument -% of \cs{tl_if_empty:oTF} is empty if |#1| is |?| followed -% by blank spaces (besides, this particular variant of -% the emptiness test is optimized). If the item of the -% comma list is blank, grab the next one. As soon as one -% item is non-blank, exit: the second auxiliary grabs -% \cs{prg_return_false:} as |#2|, unless every item in -% the comma list was blank and the loop actually got broken -% by the trailing \cs{s_@@_mark} \cs{prg_return_false:} item. -% \begin{macrocode} -\prg_new_conditional:Npnn \clist_if_empty:n #1 { p , T , F , TF } - { - \@@_if_empty_n:w ? #1 - , \s_@@_mark \prg_return_false: - , \s_@@_mark \prg_return_true: - \s_@@_stop - } -\cs_new:Npn \@@_if_empty_n:w #1 , - { - \tl_if_empty:oTF { \use_none:nn #1 ? } - { \@@_if_empty_n:w ? } - { \@@_if_empty_n:wNw } - } -\cs_new:Npn \@@_if_empty_n:wNw #1 \s_@@_mark #2#3 \s_@@_stop {#2} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \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, -% \clist_if_in:nn, \clist_if_in:nV, \clist_if_in:no -% } -% \begin{macro}{\@@_if_in_return:nnN} -% \UnitTested -% For \enquote{safe} items, we simply surround the comma list, and the -% item, with commas, then use the same code as for \cs{tl_if_in:Nn}. -% For \enquote{unsafe} items we follow the same route as -% \cs{seq_if_in:Nn}, mapping through the list a comparison function. -% If found, return \texttt{true} and remove \cs{prg_return_false:}. -% \begin{macrocode} -\prg_new_protected_conditional:Npnn \clist_if_in:Nn #1#2 { T , F , TF } - { - \exp_args:No \@@_if_in_return:nnN #1 {#2} #1 - } -\prg_new_protected_conditional:Npnn \clist_if_in:nn #1#2 { T , F , TF } - { - \clist_set:Nn \l_@@_internal_clist {#1} - \exp_args:No \@@_if_in_return:nnN \l_@@_internal_clist {#2} - \l_@@_internal_clist - } -\cs_new_protected:Npn \@@_if_in_return:nnN #1#2#3 - { - \@@_if_wrap:nTF {#2} - { - \cs_set:Npe \@@_tmp:w ##1 - { - \exp_not:N \tl_if_eq:nnT {##1} - \exp_not:n - { - {#2} - { \clist_map_break:n { \prg_return_true: \use_none:n } } - } - } - \clist_map_function:NN #3 \@@_tmp:w - \prg_return_false: - } - { - \cs_set:Npn \@@_tmp:w ##1 ,#2, { } - \tl_if_empty:oTF - { \@@_tmp:w ,#1, {} {} ,#2, } - { \prg_return_false: } { \prg_return_true: } - } - } -\prg_generate_conditional_variant:Nnn \clist_if_in:Nn - { NV , No , c , cV , co } { T , F , TF } -\prg_generate_conditional_variant:Nnn \clist_if_in:nn - { nV , no } { T , F , TF } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsection{Mapping over comma lists} -% -% \begin{macro}{\clist_map_function:NN, \clist_map_function:cN} -% \UnitTested -% \begin{macro}{\@@_map_function:Nw, \@@_map_function_end:w} -% If the variable is empty, the mapping is skipped (otherwise, -% that comma-list would be seen as consisting of one empty item). -% Then loop over the comma-list, grabbing eight comma-delimited items -% at a time. The end is marked by \cs{s_@@_stop}, which may not appear -% in any of the items. Once the last group of eight items has been -% reached, we go through them more slowly using -% \cs{@@_map_function_end:w}. The auxiliary function -% \cs{@@_map_function:Nw} is also used in some other clist mappings. -% \begin{macrocode} -\cs_new:Npn \clist_map_function:NN #1#2 - { - \clist_if_empty:NF #1 - { - \exp_after:wN \@@_map_function:Nw \exp_after:wN #2 #1 , - \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , - \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , - \prg_break_point:Nn \clist_map_break: { } - } - } -\cs_new:Npn \@@_map_function:Nw #1 #2, #3, #4, #5, #6, #7, #8, #9, - { - \@@_use_none_delimit_by_s_stop:w - #9 \@@_map_function_end:w \s_@@_stop - #1 {#2} #1 {#3} #1 {#4} #1 {#5} #1 {#6} #1 {#7} #1 {#8} #1 {#9} - \@@_map_function:Nw #1 - } -\cs_new:Npn \@@_map_function_end:w \s_@@_stop #1#2 - { - \@@_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s_@@_stop - #1 {#2} - \@@_map_function_end:w \s_@@_stop - } -\cs_generate_variant:Nn \clist_map_function:NN { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\clist_map_function:nN, \clist_map_function:eN} -% \UnitTested -% \begin{macro}{\@@_map_function_n:Nn} -% \begin{macro}{\@@_map_unbrace:wn} -% The \texttt{n}-type mapping function is a bit more awkward, -% since spaces must be trimmed from each item. -% Space trimming is again based on \cs{@@_trim_next:w}. -% The auxiliary \cs{@@_map_function_n:Nn} receives as arguments the -% function, and the next non-empty item (after space trimming but -% before brace removal). One level of braces is removed by -% \cs{@@_map_unbrace:wn}. -% \begin{macrocode} -\cs_new:Npn \clist_map_function:nN #1#2 - { - \exp_after:wN \@@_map_function_n:Nn \exp_after:wN #2 - \exp:w \@@_trim_next:w \prg_do_nothing: #1 , - \s_@@_stop \clist_map_break: , - \prg_break_point:Nn \clist_map_break: { } - } -\cs_generate_variant:Nn \clist_map_function:nN { e } -\cs_new:Npn \@@_map_function_n:Nn #1 #2 - { - \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop - \@@_map_unbrace:wn #2 , #1 - \exp_after:wN \@@_map_function_n:Nn \exp_after:wN #1 - \exp:w \@@_trim_next:w \prg_do_nothing: - } -\cs_new:Npn \@@_map_unbrace:wn #1, #2 { #2 {#1} } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \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. We use a different -% function for each level of nesting. -% -% Since the mapping is non-expandable, we can perform -% the space-trimming needed by the \texttt{n} version -% simply by storing the comma-list in a variable. We -% don't need a different comma-list for each nesting -% level: the comma-list is expanded before the mapping -% starts. -% \begin{macrocode} -\cs_new_protected:Npn \clist_map_inline:Nn #1#2 - { - \clist_if_empty:NF #1 - { - \int_gincr:N \g__kernel_prg_map_int - \cs_gset_protected:cpn - { @@_map_ \int_use:N \g__kernel_prg_map_int :w } ##1 {#2} - \exp_last_unbraced:Nco \@@_map_function:Nw - { @@_map_ \int_use:N \g__kernel_prg_map_int :w } - #1 , - \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , - \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , - \prg_break_point:Nn \clist_map_break: - { \int_gdecr:N \g__kernel_prg_map_int } - } - } -\cs_new_protected:Npn \clist_map_inline:nn #1 - { - \clist_set:Nn \l_@@_internal_clist {#1} - \clist_map_inline:Nn \l_@@_internal_clist - } -\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 -% \begin{macro}{\clist_map_variable:nNn} -% \begin{macro}{\@@_map_variable:Nnn} -% The |N|-type version is a straightforward application of -% \cs{clist_map_tokens:Nn}, calling \cs{@@_map_variable:Nnn} for each -% item to assign the variable and run the user's code. The |n|-type -% version is \emph{not} implemented in terms of the |n|-type function -% \cs{clist_map_tokens:Nn}, because here we are allowed to clean up -% the |n|-type comma list non-expandably. -% \begin{macrocode} -\cs_new_protected:Npn \clist_map_variable:NNn #1#2#3 - { \clist_map_tokens:Nn #1 { \@@_map_variable:Nnn #2 {#3} } } -\cs_generate_variant:Nn \clist_map_variable:NNn { c } -\cs_new_protected:Npn \@@_map_variable:Nnn #1#2#3 - { \tl_set:Nn #1 {#3} #2 } -\cs_new_protected:Npn \clist_map_variable:nNn #1 - { - \clist_set:Nn \l_@@_internal_clist {#1} - \clist_map_variable:NNn \l_@@_internal_clist - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\clist_map_tokens:Nn, \clist_map_tokens:cn} -% \begin{macro}{\@@_map_tokens:nw, \@@_map_tokens_end:w} -% Essentially a copy of \cs{clist_map_function:NN} with braces added. -% \begin{macrocode} -\cs_new:Npn \clist_map_tokens:Nn #1#2 - { - \clist_if_empty:NF #1 - { - \exp_last_unbraced:Nno \@@_map_tokens:nw {#2} #1 , - \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , - \s_@@_stop , \s_@@_stop , \s_@@_stop , \s_@@_stop , - \prg_break_point:Nn \clist_map_break: { } - } - } -\cs_new:Npn \@@_map_tokens:nw #1 #2, #3, #4, #5, #6, #7, #8, #9, - { - \@@_use_none_delimit_by_s_stop:w - #9 \@@_map_tokens_end:w \s_@@_stop - \use:n {#1} {#2} \use:n {#1} {#3} \use:n {#1} {#4} \use:n {#1} {#5} - \use:n {#1} {#6} \use:n {#1} {#7} \use:n {#1} {#8} \use:n {#1} {#9} - \@@_map_tokens:nw {#1} - } -\cs_new:Npn \@@_map_tokens_end:w \s_@@_stop \use:n #1#2 - { - \@@_use_none_delimit_by_s_stop:w #2 \clist_map_break: \s_@@_stop - #1 {#2} - \@@_map_tokens_end:w \s_@@_stop - } -\cs_generate_variant:Nn \clist_map_tokens:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\clist_map_tokens:nn, \@@_map_tokens_n:nw} -% Similar to \cs{clist_map_function:nN} but with a different way of -% grabbing items because we cannot use \cs{exp_after:wN} to pass the -% \meta{code}. -% \begin{macrocode} -\cs_new:Npn \clist_map_tokens:nn #1#2 - { - \@@_map_tokens_n:nw {#2} - \prg_do_nothing: #1 , \s_@@_stop \clist_map_break: , - \prg_break_point:Nn \clist_map_break: { } - } -\cs_new:Npn \@@_map_tokens_n:nw #1#2 , - { - \tl_if_empty:oF { \use_none:nn #2 ? } - { - \@@_use_none_delimit_by_s_stop:w #2 \s_@@_stop - \tl_trim_spaces_apply:oN {#2} \use_ii_i:nn - \@@_map_unbrace:wn , {#1} - } - \@@_map_tokens_n:nw {#1} \prg_do_nothing: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\clist_map_break:, \clist_map_break:n} -% The break statements use the general \cs{prg_map_break:Nn} mechanism. -% \begin{macrocode} -\cs_new:Npn \clist_map_break: - { \prg_map_break:Nn \clist_map_break: { } } -\cs_new:Npn \clist_map_break:n - { \prg_map_break:Nn \clist_map_break: } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\clist_count:N, \clist_count:c, \clist_count:n, \clist_count:e} -% \begin{macro}{\@@_count:n} -% \begin{macro}{\@@_count:w} -% Counting the items in a comma list is done using the same approach as for -% other token count functions: turn each entry into a \texttt{+1} then use -% integer evaluation to actually do the mathematics. -% In the case of an \texttt{n}-type comma-list, we could of course use -% \cs{clist_map_function:nN}, but that is very slow, because it carefully -% removes spaces. Instead, we loop manually, and skip blank items -% (but not |{}|, hence the extra spaces). -% \begin{macrocode} -\cs_new:Npn \clist_count:N #1 - { - \int_eval:n - { - 0 - \clist_map_function:NN #1 \@@_count:n - } - } -\cs_generate_variant:Nn \clist_count:N { c } -\cs_new:Npn \@@_count:n #1 { + 1 } -\cs_set_protected:Npn \@@_tmp:w #1 - { - \cs_new:Npn \clist_count:n ##1 - { - \int_eval:n - { - 0 - \@@_count:w #1 - ##1 , \s_@@_stop \prg_break: , \prg_break_point: - } - } - \cs_new:Npn \@@_count:w ##1 , - { - \@@_use_none_delimit_by_s_stop:w ##1 \s_@@_stop - \tl_if_blank:nF {##1} { + 1 } - \@@_count:w #1 - } - } -\exp_args:No \@@_tmp:w \c_space_tl -\cs_generate_variant:Nn \clist_count:n { e } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Using comma lists} -% -% \begin{macro}[EXP]{\clist_use:Nnnn, \clist_use:cnnn} -% \begin{macro}[EXP] -% {\@@_use:wwn, \@@_use:nwwwwnwn, \@@_use:nwwn} -% \begin{macro}[EXP]{\clist_use:Nn, \clist_use:cn} -% First check that the variable exists. Then count the items in the -% comma list. If it has none, output nothing. If it has one item, -% output that item, brace stripped (note that space-trimming has -% already been done when the comma list was assigned). If it has two, -% place the \meta{separator~between~two} in the middle. -% -% Otherwise, \cs{@@_use:nwwwwnwn} takes the following arguments; 1: -% a \meta{separator}, 2, 3, 4: three items from the comma list (or -% quarks), 5: the rest of the comma list, 6: a \meta{continuation} -% function (\texttt{use_ii} or \texttt{use_iii} with its -% \meta{separator} argument), 7: junk, and 8: the temporary result, -% which is built in a brace group following \cs{s_@@_stop}. The -% \meta{separator} and the first of the three items are placed in the -% result, then we use the \meta{continuation}, placing the remaining -% two items after it. When we begin this loop, the three items really -% belong to the comma list, the first \cs{s_@@_mark} is taken as a -% delimiter to the \texttt{use_ii} function, and the continuation is -% \texttt{use_ii} itself. When we reach the last two items of the -% original token list, \cs{s_@@_mark} is taken as a third item, and now -% the second \cs{s_@@_mark} serves as a delimiter to \texttt{use_ii}, -% switching to the other \meta{continuation}, \texttt{use_iii}, which -% uses the \meta{separator between final two}. -% \begin{macrocode} -\cs_new:Npn \clist_use:Nnnn #1#2#3#4 - { - \clist_if_exist:NTF #1 - { - \int_case:nnF { \clist_count:N #1 } - { - { 0 } { } - { 1 } { \exp_after:wN \@@_use:wwn #1 , , { } } - { 2 } { \exp_after:wN \@@_use:wwn #1 , {#2} } - } - { - \exp_after:wN \@@_use:nwwwwnwn - \exp_after:wN { \exp_after:wN } #1 , - \s_@@_mark , { \@@_use:nwwwwnwn {#3} } - \s_@@_mark , { \@@_use:nwwn {#4} } - \s_@@_stop { } - } - } - { - \msg_expandable_error:nnn - { kernel } { bad-variable } {#1} - } - } -\cs_generate_variant:Nn \clist_use:Nnnn { c } -\cs_new:Npn \@@_use:wwn #1 , #2 , #3 { \exp_not:n { #1 #3 #2 } } -\cs_new:Npn \@@_use:nwwwwnwn - #1#2 , #3 , #4 , #5 \s_@@_mark , #6#7 \s_@@_stop #8 - { #6 {#3} , {#4} , #5 \s_@@_mark , {#6} #7 \s_@@_stop { #8 #1 #2 } } -\cs_new:Npn \@@_use:nwwn #1#2 , #3 \s_@@_stop #4 - { \exp_not:n { #4 #1 #2 } } -\cs_new:Npn \clist_use:Nn #1#2 - { \clist_use:Nnnn #1 {#2} {#2} {#2} } -\cs_generate_variant:Nn \clist_use:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro} -% { -% \clist_use:nnnn, \clist_use:nn, \@@_use:Nw, -% \@@_use_one:w, \@@_use_end:w, \@@_use_more:w -% } -% Items are grabbed by \cs{@@_use:Nw}, which detects blank items with -% a \cs{tl_if_empty:oTF} test (in which case it recurses). Non-blank -% items are either the end of the list, in which case the argument -% |#1| of \cs{@@_use:Nw} is used to properly end the list, or are -% normal items, which must be trimmed and properly unbraced. As we -% find successive items, the long list of \cs{@@_use:Nw} calls gets -% shortened and we end up calling \cs{@@_use_more:w} once we have -% found $3$ items. This auxiliary leaves the first-found item and the -% general separator, and calls \cs{@@_use:Nw} to find more items. -% A subtlety is that we use \cs{@@_use_end:w} both in the case of a -% two-item list and for the last two items of a general list: to get -% the correct separator, \cs{@@_use_more:w} replaces the -% separator-of-two by the last-separator when called, namely as soon -% as we have found three items. -% \begin{macrocode} -\cs_new:Npn \clist_use:nnnn #1#2#3#4 - { - \@@_use:Nw \@@_use_none_delimit_by_s_stop:w - \@@_use:Nw \@@_use_one:w - \@@_use:Nw \@@_use_end:w - \@@_use_more:w ; - {#2} {#3} {#4} ; - \prg_do_nothing: #1 , \s_@@_mark , - \s_@@_stop - } -\cs_new:Npn \@@_use:Nw #1#2 ; #3 ; #4 , - { - \tl_if_empty:oTF { \use_none:nn #4 ? } - { \@@_use:Nw #1#2 ; } - { - \@@_use_none_delimit_by_s_mark:w #4 #1 \s_@@_mark - \tl_trim_spaces_apply:oN {#4} \use_ii_i:nn - \@@_map_unbrace:wn , { #2 ; } - } - #3 ; \prg_do_nothing: - } -\cs_new:Npn \@@_use_one:w \s_@@_mark #1 , #2#3#4 \s_@@_stop - { \exp_not:n {#3} } -\cs_new:Npn \@@_use_end:w - \s_@@_mark #1 , #2#3#4#5#6 \s_@@_stop - { \exp_not:n { #4 #5 #3 } } -\cs_new:Npn \@@_use_more:w ; #1#2#3#4#5#6 ; - { - \exp_not:n { #3 #5 } - \@@_use:Nw \@@_use_end:w \@@_use_more:w ; - {#1} {#2} {#6} {#5} {#6} ; - } -\cs_new:Npn \clist_use:nn #1#2 { \clist_use:nnnn {#1} {#2} {#2} {#2} } -% \end{macrocode} -% \end{macro} -% -% \subsection{Using a single item} -% -% \begin{macro}{\clist_item:Nn, \clist_item:cn} -% \begin{macro}{\@@_item:nnnN, \@@_item:ffoN, \@@_item:ffnN} -% \begin{macro}{\@@_item_N_loop:nw} -% To avoid needing to test the end of the list at each step, -% we first compute the \meta{length} of the list. If the item number -% is~$0$, less than $-\meta{length}$, or more than $\meta{length}$, -% the result is empty. If it is negative, but not less than $-\meta{length}$, -% add $\meta{length}+1$ to the item number before performing the loop. -% The loop itself is very simple, return the item if the counter -% reached~$1$, otherwise, decrease the counter and repeat. -% \begin{macrocode} -\cs_new:Npn \clist_item:Nn #1#2 - { - \@@_item:ffoN - { \clist_count:N #1 } - { \int_eval:n {#2} } - #1 - \@@_item_N_loop:nw - } -\cs_new:Npn \@@_item:nnnN #1#2#3#4 - { - \int_compare:nNnTF {#2} < 0 - { - \int_compare:nNnTF {#2} < { - #1 } - { \@@_use_none_delimit_by_s_stop:w } - { \exp_args:Nf #4 { \int_eval:n { #2 + 1 + #1 } } } - } - { - \int_compare:nNnTF {#2} > {#1} - { \@@_use_none_delimit_by_s_stop:w } - { #4 {#2} } - } - { } , #3 , \s_@@_stop - } -\cs_generate_variant:Nn \@@_item:nnnN { ffo, ff } -\cs_new:Npn \@@_item_N_loop:nw #1 #2, - { - \int_compare:nNnTF {#1} = 0 - { \@@_use_i_delimit_by_s_stop:nw { \exp_not:n {#2} } } - { \exp_args:Nf \@@_item_N_loop:nw { \int_eval:n { #1 - 1 } } } - } -\cs_generate_variant:Nn \clist_item:Nn { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\clist_item:nn, \clist_item:en} -% \begin{macro}{ -% \@@_item_n:nw, -% \@@_item_n_loop:nw, -% \@@_item_n_end:n, -% \@@_item_n_strip:n, -% \@@_item_n_strip:w} -% This starts in the same way as \cs{clist_item:Nn} by counting the items -% of the comma list. The final item should be space-trimmed before being -% brace-stripped, hence we insert a couple of odd-looking -% \cs{prg_do_nothing:} to avoid losing braces. Blank items are ignored. -% \begin{macrocode} -\cs_new:Npn \clist_item:nn #1#2 - { - \@@_item:ffnN - { \clist_count:n {#1} } - { \int_eval:n {#2} } - {#1} - \@@_item_n:nw - } -\cs_generate_variant:Nn \clist_item:nn { e } -\cs_new:Npn \@@_item_n:nw #1 - { \@@_item_n_loop:nw {#1} \prg_do_nothing: } -\cs_new:Npn \@@_item_n_loop:nw #1 #2, - { - \exp_args:No \tl_if_blank:nTF {#2} - { \@@_item_n_loop:nw {#1} \prg_do_nothing: } - { - \int_compare:nNnTF {#1} = 0 - { \exp_args:No \@@_item_n_end:n {#2} } - { - \exp_args:Nf \@@_item_n_loop:nw - { \int_eval:n { #1 - 1 } } - \prg_do_nothing: - } - } - } -\cs_new:Npn \@@_item_n_end:n #1 #2 \s_@@_stop - { \tl_trim_spaces_apply:nN {#1} \@@_item_n_strip:n } -\cs_new:Npn \@@_item_n_strip:n #1 { \@@_item_n_strip:w #1 , } -\cs_new:Npn \@@_item_n_strip:w #1 , { \exp_not:n {#1} } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\clist_rand_item:n, \clist_rand_item:N, \clist_rand_item:c} -% \begin{macro}{\@@_rand_item:nn} -% The |N|-type function is not implemented through the |n|-type -% function for efficiency: for instance comma-list variables do not -% require space-trimming of their items. Even testing for emptyness -% of an |n|-type comma-list is slow, so we count items first and use -% that both for the emptyness test and the pseudo-random integer. -% Importantly, \cs{clist_item:Nn} and \cs{clist_item:nn} only evaluate -% their argument once. -% \begin{macrocode} -\cs_new:Npn \clist_rand_item:n #1 - { \exp_args:Nf \@@_rand_item:nn { \clist_count:n {#1} } {#1} } -\cs_new:Npn \@@_rand_item:nn #1#2 - { - \int_compare:nNnF {#1} = 0 - { \clist_item:nn {#2} { \int_rand:nn { 1 } {#1} } } - } -\cs_new:Npn \clist_rand_item:N #1 - { - \clist_if_empty:NF #1 - { \clist_item:Nn #1 { \int_rand:nn { 1 } { \clist_count:N #1 } } } - } -\cs_generate_variant:Nn \clist_rand_item:N { c } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsection{Viewing comma lists} -% -% \begin{macro}{\clist_show:N, \clist_show:c, \clist_log:N, \clist_log:c, \@@_show:NN} -% Apply the general \cs{__kernel_chk_tl_type:NnnT} with \cs{exp_not:o} -% |#2| serving as a dummy code to prevent a check performed by this -% auxiliary. -% \begin{macrocode} -\cs_new_protected:Npn \clist_show:N { \@@_show:NN \msg_show:nneeee } -\cs_generate_variant:Nn \clist_show:N { c } -\cs_new_protected:Npn \clist_log:N { \@@_show:NN \msg_log:nneeee } -\cs_generate_variant:Nn \clist_log:N { c } -\cs_new_protected:Npn \@@_show:NN #1#2 - { - \__kernel_chk_tl_type:NnnT #2 { clist } { \exp_not:o #2 } - { - \int_compare:nNnTF { \clist_count:N #2 } - = { \exp_args:No \clist_count:n #2 } - { - #1 { clist } { show } - { \token_to_str:N #2 } - { \clist_map_function:NN #2 \msg_show_item:n } - { } { } - } - { - \msg_error:nnee { clist } { non-clist } - { \token_to_str:N #2 } { \tl_to_str:N #2 } - } - } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\clist_show:n, \clist_log:n, \@@_show:Nn} -% A variant of the above: no existence check, empty first argument for -% the message. -% \begin{macrocode} -\cs_new_protected:Npn \clist_show:n { \@@_show:Nn \msg_show:nneeee } -\cs_new_protected:Npn \clist_log:n { \@@_show:Nn \msg_log:nneeee } -\cs_new_protected:Npn \@@_show:Nn #1#2 - { - #1 { clist } { show } - { } { \clist_map_function:nN {#2} \msg_show_item:n } { } { } - } -% \end{macrocode} -% \end{macro} -% -% \subsection{Scratch comma lists} -% -% \begin{variable}{\l_tmpa_clist, \l_tmpb_clist} -% \begin{variable}{\g_tmpa_clist, \g_tmpb_clist} -% Temporary comma list variables. -% \begin{macrocode} -\clist_new:N \l_tmpa_clist -\clist_new:N \l_tmpb_clist -\clist_new:N \g_tmpa_clist -\clist_new:N \g_tmpb_clist -% \end{macrocode} -% \end{variable} -% \end{variable} -% -% \begin{macrocode} -% -% \end{macrocode} -% -% \end{implementation} -% -% \PrintIndex -- cgit v1.2.3