% \iffalse meta-comment % %% File: l3tl.dtx Copyright (C) 1990-2011 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: l3tl.dtx 2566 2011-08-13 22:04:42Z bruno $ {L3 Experimental token lists} % %<*driver> \documentclass[full]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3tl} package\\ Token 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} % % \LaTeX3 stores lists of token in variables also called \enquote{token lists}. % Variables of this type get the suffix |tl| and functions of this type % have the prefix |tl|. To use a token list variable you simply call % the corresponding variable. % % Often you find yourself with not a token list variable but an % arbitrary token list which has to undergo certain tests. We will \emph{also} % prefix these functions with |tl|. While token list variables are % always single tokens, token lists are always surrounded by % braces. Many of the functions for token lists and token list variables % are very similar, and so are grouped together here. % % A token list can be seen either as a list of \enquote{items}, % or a list of \enquote{tokens}. An item is whatever \cs{use_none:n} % grabs as its argument: either a single token or a brace group, % with optional leading explicit space characters (each item is thus % itself a token list). A token is either a normal \texttt{N} argument, % or | |, |{|, or |}| (assuming normal \TeX{} category codes). % Functions which act on items are often faster than their analog acting % directly on tokens. % % \section{Creating and initialising token list variables} % % \begin{function}{\tl_new:N, \tl_new:c} % \begin{syntax} % \cs{tl_new:N} \meta{tl~var} % \end{syntax} % Creates a new \meta{tl~var} or raises an error if the % name is already taken. The declaration is global. The % \meta{tl~var} will initially be empty. % \end{function} % % \begin{function}{\tl_const:Nn, \tl_const:Nx, \tl_const:cn, \tl_const:cx} % \begin{syntax} % \cs{tl_const:Nn} \meta{tl~var} \Arg{token list} % \end{syntax} % Creates a new constant \meta{tl~var} or raises an error % if the name is already taken. The value of the % \meta{tl~var} will be set globally to the % \meta{token list}. % \end{function} % % \begin{function}{\tl_clear:N, \tl_clear:c} % \begin{syntax} % \cs{tl_clear:N} \meta{tl~var} % \end{syntax} % Clears all entries from the \meta{tl~var} within the scope of % the current \TeX{} group. % \end{function} % % \begin{function}{\tl_gclear:N, \tl_gclear:c} % \begin{syntax} % \cs{tl_gclear:N} \meta{tl~var} % \end{syntax} % Clears all entries from the \meta{tl~var} globally. % \end{function} % % \begin{function}{\tl_clear_new:N, \tl_clear_new:c} % \begin{syntax} % \cs{tl_clear_new:N} \meta{tl~var} % \end{syntax} % If the \meta{tl~var} already exists, clears it within the scope % of the current \TeX{} group. If the \meta{tl~var} is not defined, % it will be created (using \cs{tl_new:N}). Thus the sequence is % guaranteed to be available and clear within the current \TeX{} % group. The \meta{tl~var} will exist globally, but the content % outside of the current \TeX{} group is not specified. % \end{function} % % \begin{function}{\tl_gclear_new:N, \tl_gclear_new:c} % \begin{syntax} % \cs{tl_gclear_new:N} \meta{tl~var} % \end{syntax} % If the \meta{tl~var} already exists, clears it globally. If the % \meta{tl~var} is not defined, it will be created (using % \cs{tl_new:N}). Thus the sequence is guaranteed to be available % and globally clear. % \end{function} % % \begin{function}{\tl_set_eq:NN, \tl_set_eq:cN, \tl_set_eq:Nc, \tl_set_eq:cc} % \begin{syntax} % \cs{tl_set_eq:NN} \meta{tl~var1} \meta{tl~var2} % \end{syntax} % Sets the content of \meta{tl~var1} equal to that of % \meta{tl~var2}. This assignment is restricted to the current % \TeX{} group level. % \end{function} % % \begin{function} % {\tl_gset_eq:NN, \tl_gset_eq:cN, \tl_gset_eq:Nc, \tl_gset_eq:cc} % \begin{syntax} % \cs{tl_gset_eq:NN} \meta{tl~var1} \meta{tl~var2} % \end{syntax} % Sets the content of \meta{tl~var1} equal to that of % \meta{tl~var2}. This assignment is global and so is not % limited by the current \TeX{} group level. % \end{function} % % \section{Adding data to token list variables} % % \begin{function} % { % \tl_set:Nn, \tl_set:NV, \tl_set:Nv, \tl_set:No, \tl_set:Nf, \tl_set:Nx, % \tl_set:cn, \tl_set:NV, \tl_set:Nv, \tl_set:co, \tl_set:cf, \tl_set:cx % } % \begin{syntax} % \cs{tl_set:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Sets \meta{tl~var} to contain \meta{tokens}, % removing any previous content from the variable. This assignment % is restricted to the current \TeX{} group. % \end{function} % % \begin{function} % { % \tl_gset:Nn, \tl_gset:NV, \tl_gset:Nv, % \tl_gset:No, \tl_gset:Nf, \tl_gset:Nx, % \tl_gset:cn, \tl_gset:cV, \tl_gset:cv, % \tl_gset:co, \tl_gset:cf, \tl_gset:cx % } % \begin{syntax} % \cs{tl_gset:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Sets \meta{tl~var} to contain \meta{tokens}, % removing any previous content from the variable. This assignment % is global and is not limited to the current \TeX{} group level. % \end{function} % % \begin{function} % { % \tl_put_left:Nn, \tl_put_left:NV, \tl_put_left:No, \tl_put_left:Nx, % \tl_put_left:cn, \tl_put_left:cV, \tl_put_left:co, \tl_put_left:cx % } % \begin{syntax} % \cs{tl_put_left:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Appends \meta{tokens} to the left side of the current content of % \meta{tl~var}. This modification is restricted to the % current \TeX{} group level. % \end{function} % % \begin{function} % { % \tl_gput_left:Nn, \tl_gput_left:NV, \tl_gput_left:No, \tl_gput_left:Nx, % \tl_gput_left:cn, \tl_gput_left:cV, \tl_gput_left:co, \tl_gput_left:cx % } % \begin{syntax} % \cs{tl_gput_left:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Globally appends \meta{tokens} to the left side of the current % content of \meta{tl~var}. This modification is not % limited by \TeX{} grouping. % \end{function} % % \begin{function} % { % \tl_put_right:Nn, \tl_put_right:NV, \tl_put_right:No, \tl_put_right:Nx, % \tl_put_right:cn, \tl_put_right:cV, \tl_put_right:co, \tl_put_right:cx % } % \begin{syntax} % \cs{tl_put_right:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Appends \meta{tokens} to the right side of the current content of % \meta{tl~var}. This modification is restricted to the % current \TeX{} group level. % \end{function} % % \begin{function} % { % \tl_gput_right:Nn, \tl_gput_right:NV, \tl_gput_right:No, % \tl_gput_right:Nx, % \tl_gput_right:cn, \tl_gput_right:cV, \tl_gput_right:co, % \tl_gput_right:cx % } % \begin{syntax} % \cs{tl_gput_right:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Globally appends \meta{tokens} to the right side of the current % content of \meta{tl~var}. This modification is not % limited by \TeX{} grouping. % \end{function} % % \section{Modifying token list variables} % % \begin{function}{\tl_replace_once:Nnn, \tl_replace_once:cnn} % \begin{syntax} % \cs{tl_replace_once:Nnn} \meta{tl~var} \Arg{old tokens} % ~~\Arg{new tokens} % \end{syntax} % Replaces the first (leftmost) occurrence of \meta{old tokens} in the % \meta{tl~var} with \meta{new tokens}. \meta{Old tokens} % cannot contain |{|, |}| or |#| % (assuming normal \TeX{} category codes). The assignment is % restricted to the current \TeX{} group. % \end{function} % % \begin{function}{\tl_greplace_once:Nnn, \tl_greplace_once:cnn} % \begin{syntax} % \cs{tl_greplace_once:Nnn} \meta{tl~var} \Arg{old tokens} % ~~\Arg{new tokens} % \end{syntax} % Replaces the first (leftmost) occurrence of \meta{old tokens} in the % \meta{tl~var} with \meta{new tokens}. \meta{Old tokens} % cannot contain |{|, |}| or |#| % (assuming normal \TeX{} category codes). The assignment is % applied globally. % \end{function} % % \begin{function}{\tl_replace_all:Nnn, \tl_replace_all:cnn} % \begin{syntax} % \cs{tl_replace_all:Nnn} \meta{tl~var} \Arg{old tokens} % ~~\Arg{new tokens} % \end{syntax} % Replaces all occurrences of \meta{old tokens} in the % \meta{tl~var} with \meta{new tokens}. \meta{Old tokens} % cannot contain |{|, |}| or |#| % (assuming normal \TeX{} category codes). As this function % operates from left to right, the pattern \meta{old tokens} % may remain after the replacement (see \cs{tl_remove_all:Nn} % for an example). The assignment is % restricted to the current \TeX{} group. % \end{function} % % \begin{function}{\tl_greplace_all:Nnn, \tl_greplace_all:cnn} % \begin{syntax} % \cs{tl_greplace_all:Nnn} \meta{tl~var} \Arg{old tokens} % ~~\Arg{new tokens} % \end{syntax} % Replaces all occurrences of \meta{old tokens} in the % \meta{tl~var} with \meta{new tokens}. \meta{Old tokens} % cannot contain |{|, |}| or |#| % (assuming normal \TeX{} category codes). As this function % operates from left to right, the pattern \meta{old tokens} % may remain after the replacement (see \cs{tl_remove_all:Nn} % for an example). The assignment is applied globally. % \end{function} % % \begin{function}{\tl_remove_once:Nn, \tl_remove_once:cn} % \begin{syntax} % \cs{tl_remove_once:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Removes the first (leftmost) occurrence of \meta{tokens} from the % \meta{tl~var}. \meta{Tokens} cannot contain |{|, |}| or % |#| (assuming normal \TeX{} category codes). The assignment is % restricted to the current \TeX{} group. % \end{function} % % \begin{function}{\tl_gremove_once:Nn, \tl_gremove_once:cn} % \begin{syntax} % \cs{tl_gremove_once:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Removes the first (leftmost) occurrence of \meta{tokens} from the % \meta{tl~var}. \meta{Tokens} cannot contain |{|, |}| or % |#| (assuming normal \TeX{} category codes). The assignment is % applied globally. % \end{function} % % \begin{function}{\tl_remove_all:Nn, \tl_remove_all:cn} % \begin{syntax} % \cs{tl_remove_all:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Removes all occurrences of \meta{tokens} from the % \meta{tl~var}. \meta{Tokens} cannot contain |{|, |}| or % |#| (assuming normal \TeX{} category codes). As this function % operates from left to right, the pattern \meta{tokens} % may remain after the removal, for instance, % \begin{quote} % \cs{tl_set:Nn} \cs{l_tmpa_tl} |{abbccd}| % \cs{tl_remove_all:Nn} \cs{l_tmpa_tl} |{bc}| % \end{quote} % will result in \cs{l_tmpa_tl} containing \texttt{abcd}. % The assignment is restricted to the current \TeX{} group. % \end{function} % % \begin{function}{\tl_gremove_all:Nn, \tl_gremove_all:cn} % \begin{syntax} % \cs{tl_gremove_all:Nn} \meta{tl~var} \Arg{tokens} % \end{syntax} % Removes all occurrences of \meta{tokens} from the % \meta{tl~var}. \meta{Tokens} cannot contain |{|, |}| or % |#| (assuming normal \TeX{} category codes). As this function % operates from left to right, the pattern \meta{tokens} % may remain after the removal (see \cs{tl_remove_all:Nn} % for an example). The assignment is % applied globally. % \end{function} % % \section{Reassigning token list category codes} % % \begin{function} % { % \tl_set_rescan:Nnn, \tl_set_rescan:Nno, \tl_set_rescan:Nnx, % \tl_set_rescan:cnn, \tl_set_rescan:cno, \tl_set_rescan:cnx, % } % \begin{syntax} % \cs{tl_set_rescan:Nnn} \meta{tl~var} \Arg{setup} % ~~\Arg{tokens} % \end{syntax} % Sets \meta{tl~var} to contain \meta{tokens}, % applying the category code r\'egime specified in the % \meta{setup} before carrying out the assignment. This allows the % \meta{tl~var} to contain material with category codes % other than those that apply when \meta{tokens} are absorbed. The % assignment is local to the current \TeX{} group. See also % \cs{tl_rescan:nn}. % \end{function} % % \begin{function} % { % \tl_gset_rescan:Nnn, \tl_gset_rescan:Nno, \tl_gset_rescan:Nnx, % \tl_gset_rescan:cnn, \tl_gset_rescan:cno, \tl_gset_rescan:cnx, % } % \begin{syntax} % \cs{tl_gset_rescan:Nnn} \meta{tl~var} \Arg{setup} % ~~\Arg{tokens} % \end{syntax} % Sets \meta{tl~var} to contain \meta{tokens}, % applying the category code r\'egime specified in the % \meta{setup} before carrying out the assignment. This allows the % \meta{tl~var} to contain material with category codes % other than those that apply when \meta{tokens} are absorbed. The % assignment is global. See also \cs{tl_rescan:nn}. % \end{function} % % \begin{function}{\tl_rescan:nn} % \begin{syntax} % \cs{tl_rescan:nn} \Arg{setup} \Arg{tokens} % \end{syntax} % Rescans \meta{tokens} applying the category code r\'egime specified % in the \meta{setup}, and leaves the resulting tokens in the input % stream. See also \cs{tl_set_rescan:Nnn}. % \end{function} % % \section{Reassigning token list character codes} % % \begin{function}{\tl_to_lowercase:n} % \begin{syntax} % \cs{tl_to_lowercase:n} \Arg{tokens} % \end{syntax} % Works through all of the \meta{tokens}, replacing each character % with the lower case equivalent as defined by \cs{char_set_lccode:nn}. % Characters with no defined lower case character code are left % unchanged. This process does not alter the category code assigned % to the \meta{tokens}. % \begin{texnote} % This is the \TeX{} primitive \cs{lowercase} renamed. % As a result, this function takes place on execution and % not on expansion. % \end{texnote} % \end{function} % % \begin{function}{\tl_to_uppercase:n} % \begin{syntax} % \cs{tl_to_uppercase:n} \Arg{tokens} % \end{syntax} % Works through all of the \meta{tokens}, replacing each character % with the upper case equivalent as defined by \cs{char_set_uccode:nn}. % Characters with no defined lower case character code are left % unchanged. This process does not alter the category code assigned % to the \meta{tokens}. % \begin{texnote} % This is the \TeX{} primitive \cs{uppercase} renamed. % As a result, this function takes place on execution and % not on expansion. % \end{texnote} % \end{function} % % \section{Token list conditionals} % % \begin{function}[EXP,pTF]{\tl_if_blank:n, \tl_if_blank:V, \tl_if_blank:o} % \begin{syntax} % \cs{tl_if_blank_p:n} \Arg{token list} % \cs{tl_if_blank:nTF} \Arg{token list} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \meta{token list} consists only of blank spaces % (\emph{i.e.}~contains no item). The test is \texttt{true} if % \meta{token list} is zero or more explicit tokens of character code~$32$ % and category code~$10$, and is \texttt{false} otherwise. % 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]{\tl_if_empty:N, \tl_if_empty:c} % \begin{syntax} % \cs{tl_if_empty_p:N} \meta{tl var} % \cs{tl_if_empty:NTF} \meta{tl var} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \meta{token list variable} is entirely empty % (\emph{i.e.}~contains no tokens at all). 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]{\tl_if_empty:n, \tl_if_empty:V, \tl_if_empty:o} % \begin{syntax} % \cs{tl_if_empty_p:n} \Arg{token list} % \cs{tl_if_empty:nTF} \Arg{token list} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \meta{token list} is entirely empty % (\emph{i.e.}~contains no tokens at all). 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] % {\tl_if_eq:NN, \tl_if_eq:Nc, \tl_if_eq:cN, \tl_if_eq:cc} % \begin{syntax} % \cs{tl_if_eq_p:NN} \Arg{tl var1} \Arg{tl var2} % \cs{tl_if_eq:NNTF} \Arg{tl var1} \Arg{tl var2} \Arg{true code} % ~~\Arg{false code} % \end{syntax} % Compares the content of two \meta{token list variables} and % is logically \texttt{true} if the two contain the same list of % tokens (\emph{i.e.}~identical in both the list of characters they % contain and the category codes of those characters). Thus for example % \begin{verbatim} % \tl_set:Nn \l_tmpa_tl { abc } % \tl_set:Nx \l_tmpb_tl { \tl_to_str:n { abc } } % \tl_if_eq_p:NN \l_tmpa_tl \l_tmpb_tl % \end{verbatim} % is logically \texttt{false}. 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]{\tl_if_eq:nn} % \begin{syntax} % \cs{tl_if_eq:nnTF} \meta{token list1} \Arg{token list2} \Arg{true code} % ~~\Arg{false code} % \end{syntax} % Tests if \meta{token list1} and \meta{token list2} are equal, both in % respect of character codes and category codes. Either the % \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. % \end{function} % % \begin{function}[TF]{\tl_if_in:Nn, \tl_if_in:cn} % \begin{syntax} % \cs{tl_if_in:NnTF} \meta{tl~var} \Arg{token list} \Arg{true code} % ~~\Arg{false code} % \end{syntax} % Tests if the \meta{token list} is found in the content of the % \meta{token list variable}. The \meta{token list} cannot contain % the tokens |{|, |}| or |#| (assuming the usual \TeX{} category % codes apply). 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} % % \begin{function}[TF] % {\tl_if_in:nn, \tl_if_in:Vn, \tl_if_in:on, \tl_if_in:on} % \begin{syntax} % \cs{tl_if_in:nnTF} \meta{token list1} \Arg{token list2} \Arg{true code} % ~~\Arg{false code} % \end{syntax} % Tests if the \meta{token list1} is found inside \meta{token list2}. % The \meta{token list} cannot contain the tokens |{|, |}| or |#| % (assuming the usual \TeX{} category codes apply). 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} % % \begin{function}[EXP,pTF]{\tl_if_single:N, \tl_if_single:c} % \begin{syntax} % \cs{tl_if_single_p:N} \Arg{tl~var} % \cs{tl_if_single:NTF} \Arg{tl~var} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the content of the \meta{tl~var} consists of a single item, % \emph{i.e.}~is either a single normal token (excluding spaces, % and brace tokens) or a single brace group, surrounded by optional % spaces on both sides. In other words, such a token list has length % $1$ according to \cs{tl_length:N}. 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]{\tl_if_single:n} % \begin{syntax} % \cs{tl_if_single_p:n} \Arg{token list} % \cs{tl_if_single:nTF} \Arg{token list} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % Tests if the token list has exactly one item, \emph{i.e.}~is either % a single normal token or a single brace group, surrounded by % optional spaces on both sides. In other words, such a token list % has length $1$ according to \cs{tl_length:n}. % The branching versions 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. % \end{function} % % \begin{function}[EXP,pTF]{\tl_if_single_token:n} % \begin{syntax} % \cs{tl_if_single_token_p:n} \Arg{token list} % \cs{tl_if_single_token:nTF} \Arg{token list} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % Tests if the token list consists of exactly one token, \emph{i.e.}~is % either a single space character or a single \enquote{normal} token. % Token groups (|{|\ldots|}|) are not single tokens. % The branching versions 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. % \end{function} % % \section{Mapping to token lists} % % \begin{function}[EXP]{\tl_map_function:NN, \tl_map_function:cN} % \begin{syntax} % \cs{tl_map_function:NN} \meta{tl~var} \meta{function} % \end{syntax} % Applies \meta{function} to every \meta{item} in the \meta{tl~var}. % The \meta{function} will receive one argument for each iteration. % This may be a number of tokens if the \meta{item} was stored within % braces. Hence the \meta{function} should anticipate receiving % \texttt{n}-type arguments. See also \cs{tl_map_function:nN}. % \end{function} % % \begin{function}[EXP]{\tl_map_function:nN} % \begin{syntax} % \cs{tl_map_function:nN} \meta{token list} \meta{function} % \end{syntax} % Applies \meta{function} to every \meta{item} in the \meta{token list}, % The \meta{function} will receive one argument for each iteration. % This may be a number of tokens if the \meta{item} was stored within % braces. Hence the \meta{function} should anticipate receiving % \texttt{n}-type arguments. See also \cs{tl_map_function:NN}. % \end{function} % % \begin{function}{\tl_map_inline:Nn, \tl_map_inline:cn} % \begin{syntax} % \cs{tl_map_inline:Nn} \meta{tl~var} \Arg{inline function} % \end{syntax} % Applies the \meta{inline function} to every \meta{item} stored within the % \meta{tl~var}. 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. See also \cs{tl_map_function:Nn}. % \end{function} % % \begin{function}{\tl_map_inline:nn} % \begin{syntax} % \cs{tl_map_inline:nn} \meta{token list} \Arg{inline function} % \end{syntax} % Applies the \meta{inline function} to every \meta{item} stored within the % \meta{token 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. See also \cs{tl_map_function:nn}. % \end{function} % % \begin{function}{\tl_map_variable:NNn, \tl_map_variable:cNn} % \begin{syntax} % \cs{tl_map_variable:NNn} \meta{tl~var} \meta{variable} \Arg{function} % \end{syntax} % Applies the \meta{function} to every \meta{item} stored % within the \meta{tl~var}. The \meta{function} should consist of code % which will receive the \meta{item} stored in the \meta{variable}. % One variable mapping can be nested inside another. See also % \cs{tl_map_inline:Nn}. % \end{function} % % \begin{function}{\tl_map_variable:nNn} % \begin{syntax} % \cs{tl_map_variable:nNn} \meta{token list} \meta{variable} \Arg{function} % \end{syntax} % Applies the \meta{function} to every \meta{item} stored % within the \meta{token list}. The \meta{function} should consist of code % which will receive the \meta{item} stored in the \meta{variable}. % One variable mapping can be nested inside another. See also % \cs{tl_map_inline:nn}. % \end{function} % % \begin{function}[EXP]{\tl_map_break:} % \begin{syntax} % \cs{tl_map_break:} % \end{syntax} % Used to terminate a \cs{tl_map_\ldots} function before all % entries in the \meta{token list variable} have been processed. This % will normally take place within a conditional statement, for example % \begin{verbatim} % \tl_map_inline:Nn \l_my_tl % { % \str_if_eq:nnTF { #1 } { bingo } % { \tl_map_break: } % { % % Do something useful % } % } % \end{verbatim} % Use outside of a \cs{tl_map_\ldots} scenario will lead low % level \TeX{} errors. % \end{function} % % \section{Using token lists} % % \begin{function}[EXP]{\tl_to_str:N, \tl_to_str:c} % \begin{syntax} % \cs{tl_to_str:N} \meta{tl~var} % \end{syntax} % Converts the content of the \meta{tl~var} into a series of characters % with category code $12$ (other) with the exception of spaces, which % retain category code $10$ (space). This \meta{string} is then left % in the input stream. % \end{function} % % \begin{function}[EXP]{\tl_to_str:n} % \begin{syntax} % \cs{tl_to_str:n} \Arg{tokens} % \end{syntax} % Converts the given \meta{tokens} into a series of characters with % category code $12$ (other) with the exception of spaces, which % retain category code $10$ (space). This \meta{string} is then left % in the input stream. Note that this function requires only a single % expansion. % \begin{texnote} % This is the \eTeX{} primitive \cs{detokenize}. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\tl_use:N, \tl_use:c} % \begin{syntax} % \cs{tl_use:N} \meta{tl~var} % \end{syntax} % Recovers the content of a \meta{tl~var} and places it % directly in the input stream. An error will be raised if the variable % does not exist or if it is invalid. Note that it is possible to use % a \meta{tl~var} directly without an accessor function. % \end{function} % % \section{Working with the content of token lists} % % \begin{function}[EXP] % {\tl_length:n, \tl_length:V, \tl_length:o} % \begin{syntax} % \cs{tl_length:n} \Arg{tokens} % \end{syntax} % Counts the number of \meta{items} in \meta{tokens} and leaves this % information in the input stream. Unbraced tokens count as one % element as do each token group (|{|\ldots|}|). This process will % ignore any unprotected spaces within \meta{tokens}. See also % \cs{tl_length:N}. This function requires three expansions, % giving an \meta{integer denotation}. % \end{function} % % \begin{function}[EXP]{\tl_length:N, \tl_length:c} % \begin{syntax} % \cs{tl_length:N} \Arg{tl~var} % \end{syntax} % Counts the number of token groups in the \meta{tl~var} % and leaves this information in the input stream. Unbraced tokens % count as one element as do each token group (|{|\ldots|}|). This % process will ignore any unprotected spaces within \meta{tokens}. % See also \cs{tl_length:n}. This function requires three expansions, % giving an \meta{integer denotation}. % \end{function} % % \begin{function}[EXP]{\tl_reverse:n, \tl_reverse:V, \tl_reverse:o} % \begin{syntax} % \cs{tl_reverse:n} \Arg{token list} % \end{syntax} % Reverses the order of the \meta{items} in the \meta{token list}, % so that \meta{item1}\meta{item2}\meta{item3} \ldots \meta{item$_n$} % becomes \meta{item$_n$}\ldots \meta{item3}\meta{item2}\meta{item1}. % This process will preserve unprotected space within the % \meta{token list}. Tokens are not reversed within braced token % groups, which keep their outer set of braces. % In situations where performance is important, % consider \cs{tl_reverse_items:n}. % See also \cs{tl_reverse:N}. % \end{function} % % \begin{function}{\tl_reverse:N, \tl_reverse:c} % \begin{syntax} % \cs{tl_reverse:N} \Arg{tl~var} % \end{syntax} % Reverses the order of the \meta{items} stored in \meta{tl~var}, so % that \meta{item1}\meta{item2}\meta{item3} \ldots \meta{item$_n$} % becomes \meta{item$_n$}\ldots \meta{item3}\meta{item2}\meta{item1}. % This process will preserve unprotected spaces within the % \meta{token list variable}. Braced token groups are copied without % reversing the order of tokens, but keep the outer set of braces. % The reversal is local to the current % \TeX{} group. See also \cs{tl_reverse:n}. % \end{function} % % \begin{function}[EXP]{\tl_reverse_items:n} % \begin{syntax} % \cs{tl_reverse_items:n} \Arg{token list} % \end{syntax} % Reverses the order of the \meta{items} stored in \meta{tl~var}, % so that \Arg{item1}\Arg{item2}\Arg{item3} \ldots \Arg{item$_n$} % becomes \Arg{item$_n$} \ldots{} \Arg{item3}\Arg{item2}\Arg{item1}. % This process will remove any unprotected space within the % \meta{token list}. Braced token groups are copied without % reversing the order of tokens, and keep the outer set of braces. % Items which are initially not braced are copied with braces in % the result. In cases where preserving spaces is important, % consider \cs{tl_reverse:n} or \cs{tl_reverse_tokens:n}. % \end{function} % % \begin{function}[EXP]{\tl_trim_spaces:n} % \begin{syntax} % \cs{tl_trim_spaces:n} \meta{token list} % \end{syntax} % Removes any leading and trailing explicit space characters % from the \meta{token list} and leaves the result in the input % stream. This process requires two expansions. % \begin{texnote} % The result is return within the \cs{etex_unexpanded:D} % primitive (\cs{exp_not:n}), which means that the token % list will not expand further when appearing in an x-type % argument expansion. % \end{texnote} % \end{function} % % \begin{function}{\tl_trim_spaces:N, \tl_trim_spaces:c} % \begin{syntax} % \cs{tl_trim_spaces:N} \meta{tl~var} % \end{syntax} % Removes any leading and trailing explicit space characters % from the content of the \meta{tl~var} within the current \TeX{} group. % \end{function} % % \begin{function}{\tl_gtrim_spaces:N, \tl_gtrim_spaces:c} % \begin{syntax} % \cs{tl_gtrim_spaces:N} \meta{tl~var} % \end{syntax} % Removes any leading and trailing explicit space characters % from the content of the \meta{tl~var} globally. % \end{function} % % \section{The first token from a token list} % % Functions which deal with either only the very first token of a % token list or everything except the first token. % % \begin{function}[EXP]{\tl_head:n, \tl_head:V, \tl_head:v, \tl_head:f} % \begin{syntax} % \cs{tl_head:n} \Arg{tokens} % \end{syntax} % Leaves in the input stream the first non-space token from the % \meta{tokens}. Any leading space tokens will be discarded, and thus for % example % \begin{verbatim} % \tl_head:n { abc } % \end{verbatim} % and % \begin{verbatim} % \tl_head:n { ~ abc } % \end{verbatim} % will both leave |a| in the input stream. % An empty list of \meta{tokens} or one which consists % only of space (category code $10$) tokens will result in \cs{tl_head:n} % leaving nothing in the input stream. % \end{function} % % \begin{function}[EXP]{\tl_head:w} % \begin{syntax} % \cs{tl_head:w} \meta{tokens} \cs{q_stop} % \end{syntax} % Leaves in the input stream the first non-space token from the % \meta{tokens}. An empty list of \meta{tokens} or one which consists % only of space (category code $10$) tokens will result in an error, and % thus \meta{tokens} must \emph{not} be \enquote{blank} as determined by % \cs{tl_if_blank:n(TF)}. This function requires only a single expansion, % and thus is suitable for use within an \texttt{o}-type expansion. In % general, \cs{tl_head:n} should be preferred if the number of expansions % is not critical. % \end{function} % % \begin{function}[EXP]{\tl_tail:n, \tl_tail:V, \tl_tail:v, \tl_tail:f} % \begin{syntax} % \cs{tl_tail:n} \Arg{tokens} % \end{syntax} % Discards the all leading space tokens and the first non-space token % in the \meta{tokens}, and leaves the remaining tokens in the % input stream. Thus for example % \begin{verbatim} % \tl_tail:n { abc } % \end{verbatim} % and % \begin{verbatim} % \tl_tail:n { ~ abc } % \end{verbatim} % will both leave |bc| in the input stream. % An empty list of \meta{tokens} or one which consists % only of space (category code $10$) tokens will result in \cs{tl_tail:n} % leaving nothing in the input stream. % \end{function} % % \begin{function}[EXP]{\tl_tail:w} % \begin{syntax} % \cs{tl_tail:w} \Arg{tokens} \cs{q_stop} % \end{syntax} % Discards the all leading space tokens and the first non-space token % in the \meta{tokens}, and leaves the remaining tokens in the % input stream. % An empty list of \meta{tokens} or one which consists % only of space (category code $10$) tokens will result in an error, and % thus \meta{tokens} must \emph{not} be \enquote{blank} as determined by % \cs{tl_if_blank:n(TF)}. This function requires only a single expansion, % and thus is suitable for use within an \texttt{o}-type expansion. In % general, \cs{tl_tail:n} should be preferred if the number of expansions % is not critical. % \end{function} % % \begin{function}[EXP]{\str_head:n,\str_tail:n} % \begin{syntax} % \cs{str_head:n} \Arg{tokens} % \cs{str_tail:n} \Arg{tokens} % \end{syntax} % Converts the \meta{tokens} into a string, as described for % \cs{tl_to_str:n}. The \cs{str_head:n} function then leaves % the first character of this string in the input stream. % The \cs{str_tail:n} function leaves all characters except % the first in the input stream. The first character may be % a space. If the \meta{tokens} argument is entirely empty, % nothing is left in the input stream. % \end{function} % % \begin{function}[EXP,pTF]{\tl_if_head_eq_catcode:nN} % \begin{syntax} % \cs{tl_if_head_eq_catcode_p:nN} \Arg{token list} \meta{test token} % \cs{tl_if_head_eq_catcode:nNTF} \Arg{token list} \meta{test token} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % Tests if the first \meta{token} in the \meta{token list} has the same % category code as the \meta{test token}. In the case where % \meta{token list} is empty, its head is considered to be \cs{q_nil}, % and the test will be true if \meta{test token} is a control sequence. % 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] % {\tl_if_head_eq_charcode:nN, \tl_if_head_eq_charcode:fN} % \begin{syntax} % \cs{tl_if_head_eq_charcode_p:nN} \Arg{token list} \meta{test token} % \cs{tl_if_head_eq_charcode:nNTF} \Arg{token list} \meta{test token} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % Tests if the first \meta{token} in the \meta{token list} has the same % character code as the \meta{test token}. In the case where % \meta{token list} is empty, its head is considered to be \cs{q_nil}, % and the test will be true if \meta{test token} is a control sequence. % 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]{\tl_if_head_eq_meaning:nN} % \begin{syntax} % \cs{tl_if_head_eq_meaning_p:nN} \Arg{token list} \meta{test token} % \cs{tl_if_head_eq_meaning:nNTF} \Arg{token list} \meta{test token} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % Tests if the first \meta{token} in the \meta{token list} has the same % meaning as the \meta{test token}. In the case where \meta{token list} % is empty, its head is considered to be \cs{q_nil}, and the test will % be true if \meta{test token} has the same meaning as \cs{q_nil}. % 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,int]{\tl_if_head_group:n} % \begin{syntax} % \cs{tl_if_head_group_p:n} \Arg{token list} % \cs{tl_if_head_group:nTF} \Arg{token list} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % Tests if the first \meta{token} in the \meta{token list} % is an explicit begin-group character (with category code~1 % and any character code), in other words, if the \meta{token list} % starts with a brace group. In particular, the test is false % if the \meta{token list} starts with an implicit token such as % \cs{c_group_begin_token}, or if it empty. % This function is useful to implement actions on token lists on % a token by token basis. % The branching versions 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. % \end{function} % % \begin{function}[EXP,pTF,int]{\tl_if_head_N_type:n} % \begin{syntax} % \cs{tl_if_head_N_type_p:n} \Arg{token list} % \cs{tl_if_head_N_type:nTF} \Arg{token list} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % Tests if the first \meta{token} in the \meta{token list} % is a normal \texttt{N}-type argument. In other words, % it is neither an explicit space character (with category code~10 % and character code~32) nor an explicit begin-group character % (with category code~1 and any character code). An empty % argument yields false, as it does not have a \enquote{normal} % first token. % This function is useful to implement actions on token lists on % a token by token basis. % The branching versions 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. % \end{function} % % \begin{function}[EXP,pTF,int]{\tl_if_head_space:n} % \begin{syntax} % \cs{tl_if_head_space_p:n} \Arg{token list} % \cs{tl_if_head_space:nTF} \Arg{token list} % ~~\Arg{true code} \Arg{false code} % \end{syntax} %^^A We need to add a discussion of %^^A explicit vs implicit tokens somewhere in the doc. % Tests if the first \meta{token} in the \meta{token list} % is an explicit space character (with category code~$10$ % and character code~$32$). If \meta{token list} starts with % an implicit token such as \cs{c_space_token}, the test % will yield false, as well as if the argument is empty. % This function is useful to implement actions on token lists on % a token by token basis. % The branching versions 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. % \begin{texnote} % When \TeX{} reads a character of category code $10$ for the % first time, it is converted to an explicit space token, with % character code $32$, regardless of the initial character code. % \enquote{Funny} spaces with a different category code, can be produced % using \cs{tex_lowercase:D}. Explicit spaces are also produced % as a result of \cs{token_to_str:N}, \cs{tl_to_str:n}, etc. % \end{texnote} % \end{function} % % \section{Viewing token lists} % % \begin{function}{\tl_show:N, \tl_show:c} % \begin{syntax} % \cs{tl_show:N} \meta{tl~var} % \end{syntax} % Displays the content of the \meta{tl~var} on the terminal. % \begin{texnote} % \cs{tl_show:N} is the \TeX{} primitive \cs{show}. % \end{texnote} % \end{function} % % \begin{function}{\tl_show:n} % \begin{syntax} % \cs{tl_show:n} \meta{token list} % \end{syntax} % Displays the \meta{token list} on the terminal. % \begin{texnote} % \cs{tl_show:n} is the \eTeX{} primitive \cs{showtokens}. % \end{texnote} % \end{function} % % \section{Constant token lists} % % \begin{variable}{\c_job_name_tl} % Constant that gets the \enquote{job name} assigned when \TeX{} starts. % \begin{texnote} % This is the new name for the primitive \cs{jobname}. It is a constant % that is set by \TeX{} and should not be overwritten by the package. % \end{texnote} % \end{variable} % % \begin{variable}{\c_empty_tl} % Constant that is always empty. % \end{variable} % % \begin{variable}{\c_space_tl} % A space token contained in a token list (compare this with % \cs{c_space_token}). For use where an explicit space is required. % \end{variable} % % \section{Scratch token lists} % % \begin{variable}{\l_tmpa_tl, \l_tmpb_tl} % Scratch token 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}{\g_tmpa_tl, \g_tmpb_tl} % Scratch token 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} % % \section{Experimental token list functions} % % \begin{function}[EXP]{\tl_reverse_tokens:n} % \begin{syntax} % \cs{tl_reverse_tokens:n} \Arg{tokens} % \end{syntax} % This function, which works directly on \TeX{} tokens, reverses % the order of the \meta{tokens}: the first will be the last and % the last will become first. Spaces are preserved. The reversal % also operates within brace groups, but the braces themselves % are not exchanged, as this would lead to an unbalanced token % list. For instance, \cs{tl_reverse_tokens:n} |{a~{b()}}| % leaves |{)(b}~a| in the input stream. This function requires % two steps of expansion. % \end{function} % % \begin{function}[EXP]{\tl_length_tokens:n} % \begin{syntax} % \cs{tl_length_tokens:n} \Arg{tokens} % \end{syntax} % Counts the number of \TeX{} tokens in the \meta{tokens} and leaves % this information in the input stream. Every token, including spaces and % braces, contributes one to the total; thus for instance, the length of % |a~{bc}| is $6$. % This function requires three expansions, % giving an \meta{integer denotation}. % \end{function} % % \begin{function}[EXP]{\tl_expandable_uppercase:n,\tl_expandable_lowercase:n} % \begin{syntax} % \cs{tl_expandable_uppercase:n} \Arg{tokens} % \cs{tl_expandable_lowercase:n} \Arg{tokens} % \end{syntax} % The \cs{tl_expandable_uppercase:n} function works through all of % the \meta{tokens}, replacing characters in the range |a|--|z| % (with arbitrary category code) by the corresponding letter % in the range |A|--|Z|, with category code $11$ (letter). Similarly, % \cs{tl_expandable_lowercase:n} replaces characters in the range % |A|--|Z| by letters in the range |a|--|z|, and leaves other tokens % unchanged. This function requires two steps of expansion. % \begin{texnote} % Begin-group and end-group characters are normalized and become % |{| and |}|, respectively. % \end{texnote} % \end{function} % % \section{Internal functions} % % \begin{variable}{\q_tl_act_mark,\q_tl_act_stop} % Quarks which are only used for the particular purposes of % \cs{tl_act_...} functions. % \end{variable} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3tl} implementation} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \package_check_loaded_expl: % % \end{macrocode} % % A token list variable is a \TeX{} macro that holds tokens. By using the % \eTeX{} primitive \cs{unexpanded} inside a \TeX{} \cs{edef} it is % possible to store any tokens, including |#|, in this way. % % \subsection{Functions} % % \begin{macro}{\tl_new:N, \tl_new:c} % Creating new token list variables is a case of checking for an % existing definition and if free doing the definition. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_new:N #1 { \chk_if_free_cs:N #1 \cs_gset_eq:NN #1 \c_empty_tl } \cs_generate_variant:Nn \tl_new:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\tl_const:Nn, \tl_const:Nx, \tl_const:cn, \tl_const:cx} % Constants are also easy to generate. % \begin{macrocode} \cs_new_protected:Npn \tl_const:Nn #1#2 { \chk_if_free_cs:N #1 \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } } \cs_new_protected:Npn \tl_const:Nx #1#2 { \chk_if_free_cs:N #1 \cs_gset_nopar:Npx #1 {#2} } \cs_generate_variant:Nn \tl_const:Nn { c } \cs_generate_variant:Nn \tl_const:Nx { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\tl_clear:N, \tl_clear:c} % \begin{macro}{\tl_gclear:N, \tl_gclear:c} % Clearing a token list variable means setting it to an empty value. % Error checking will be sorted out by the parent function. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_clear:N #1 { \tl_set_eq:NN #1 \c_empty_tl } \cs_new_protected_nopar:Npn \tl_gclear:N #1 { \tl_gset_eq:NN #1 \c_empty_tl } \cs_generate_variant:Nn \tl_clear:N { c } \cs_generate_variant:Nn \tl_gclear:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\tl_clear_new:N, \tl_clear_new:c} % \begin{macro}{\tl_gclear_new:N, \tl_gclear_new:c} % Clearing a token list variable means setting it to an empty value. % Error checking will be sorted out by the parent function. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_clear_new:N #1 { \cs_if_exist:NTF #1 { \tl_clear:N #1 } { \tl_new:N #1 } } \cs_new_protected_nopar:Npn \tl_gclear_new:N #1 { \cs_if_exist:NTF #1 { \tl_gclear:N #1 } { \tl_new:N #1 } } \cs_generate_variant:Nn \tl_clear_new:N { c } \cs_generate_variant:Nn \tl_gclear_new:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\tl_set_eq:NN, \tl_set_eq:Nc, \tl_set_eq:cN, \tl_set_eq:cc} % \begin{macro}{\tl_gset_eq:NN, \tl_gset_eq:Nc, \tl_gset_eq:cN, \tl_gset_eq:cc} % For setting token list variables equal to each other. % \begin{macrocode} \cs_new_eq:NN \tl_set_eq:NN \cs_set_eq:NN \cs_new_eq:NN \tl_set_eq:cN \cs_set_eq:cN \cs_new_eq:NN \tl_set_eq:Nc \cs_set_eq:Nc \cs_new_eq:NN \tl_set_eq:cc \cs_set_eq:cc \cs_new_eq:NN \tl_gset_eq:NN \cs_gset_eq:NN \cs_new_eq:NN \tl_gset_eq:cN \cs_gset_eq:cN \cs_new_eq:NN \tl_gset_eq:Nc \cs_gset_eq:Nc \cs_new_eq:NN \tl_gset_eq:cc \cs_gset_eq:cc % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Adding to token list variables} % % \begin{macro} % { % \tl_set:Nn, \tl_set:NV, \tl_set:Nv, \tl_set:No, \tl_set:Nf, \tl_set:Nx, % \tl_set:cn, \tl_set:NV, \tl_set:Nv, \tl_set:co, \tl_set:cf, \tl_set:cx % } % \begin{macro} % { % \tl_gset:Nn, \tl_gset:NV, \tl_gset:Nv, % \tl_gset:No, \tl_gset:Nf, \tl_gset:Nx, % \tl_gset:cn, \tl_gset:NV, \tl_gset:Nv, % \tl_gset:co, \tl_gset:cf, \tl_gset:cx % } % By using \cs{exp_not:n} token list variables can contain |#| tokens, % which makes the token list registers provided by \TeX{} % more or less redundant. The \cs{tl_set:No} version is done % \enquote{by hand} as it is used quite a lot. % \begin{macrocode} \cs_new_protected:Npn \tl_set:Nn #1#2 { \cs_set_nopar:Npx #1 { \exp_not:n {#2} } } \cs_new_protected:Npn \tl_set:No #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o {#2} } } \cs_new_protected:Npn \tl_set:Nx #1#2 { \cs_set_nopar:Npx #1 {#2} } \cs_new_protected:Npn \tl_gset:Nn #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:n {#2} } } \cs_new_protected:Npn \tl_gset:No #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o {#2} } } \cs_new_protected:Npn \tl_gset:Nx #1#2 { \cs_gset_nopar:Npx #1 {#2} } \cs_generate_variant:Nn \tl_set:Nn { NV , Nv , Nf } \cs_generate_variant:Nn \tl_set:Nx { c } \cs_generate_variant:Nn \tl_set:Nn { c, co , cV , cv , cf } \cs_generate_variant:Nn \tl_gset:Nn { NV , Nv , Nf } \cs_generate_variant:Nn \tl_gset:Nx { c } \cs_generate_variant:Nn \tl_gset:Nn { c, co , cV , cv , cf } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \tl_put_left:Nn, \tl_put_left:NV, \tl_put_left:No, \tl_put_left:Nx, % \tl_put_left:cn, \tl_put_left:cV, \tl_put_left:co, \tl_put_left:cx % } % \begin{macro} % { % \tl_gput_left:Nn, \tl_gput_left:NV, \tl_gput_left:No, \tl_gput_left:Nx, % \tl_gput_left:cn, \tl_gput_left:cV, \tl_gput_left:co, \tl_gput_left:cx % } % Adding to the left is done directly to gain a little performance. % \begin{macrocode} \cs_new_protected:Npn \tl_put_left:Nn #1#2 { \cs_set_nopar:Npx #1 { \exp_not:n {#2} \exp_not:o #1 } } \cs_new_protected:Npn \tl_put_left:NV #1#2 { \cs_set_nopar:Npx #1 { \exp_not:V #2 \exp_not:o #1 } } \cs_new_protected:Npn \tl_put_left:No #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o {#2} \exp_not:o #1 } } \cs_new_protected:Npn \tl_put_left:Nx #1#2 { \cs_set_nopar:Npx #1 { #2 \exp_not:o #1 } } \cs_new_protected:Npn \tl_gput_left:Nn #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:n {#2} \exp_not:o #1 } } \cs_new_protected:Npn \tl_gput_left:NV #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:V #2 \exp_not:o #1 } } \cs_new_protected:Npn \tl_gput_left:No #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o {#2} \exp_not:o #1 } } \cs_new_protected:Npn \tl_gput_left:Nx #1#2 { \cs_gset_nopar:Npx #1 { #2 \exp_not:o {#1} } } \cs_generate_variant:Nn \tl_put_left:Nn { c } \cs_generate_variant:Nn \tl_put_left:NV { c } \cs_generate_variant:Nn \tl_put_left:No { c } \cs_generate_variant:Nn \tl_put_left:Nx { c } \cs_generate_variant:Nn \tl_gput_left:Nn { c } \cs_generate_variant:Nn \tl_gput_left:NV { c } \cs_generate_variant:Nn \tl_gput_left:No { c } \cs_generate_variant:Nn \tl_gput_left:Nx { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro} % { % \tl_put_right:Nn, \tl_put_right:NV, \tl_put_right:No, \tl_put_right:Nx, % \tl_put_right:cn, \tl_put_right:cV, \tl_put_right:co, \tl_put_right:cx % } % \begin{macro} % { % \tl_gput_right:Nn, \tl_gput_right:NV, \tl_gput_right:No, % \tl_gput_right:Nx, % \tl_gput_right:cn, \tl_gput_right:cV, \tl_gput_right:co, % \tl_gput_right:cx % } % The same on the right. % \begin{macrocode} \cs_new_protected:Npn \tl_put_right:Nn #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } } \cs_new_protected:Npn \tl_put_right:NV #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:V #2 } } \cs_new_protected:Npn \tl_put_right:No #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o #1 \exp_not:o {#2} } } \cs_new_protected:Npn \tl_put_right:Nx #1#2 { \cs_set_nopar:Npx #1 { \exp_not:o #1 #2 } } \cs_new_protected:Npn \tl_gput_right:Nn #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:n {#2} } } \cs_new_protected:Npn \tl_gput_right:NV #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:V #2 } } \cs_new_protected:Npn \tl_gput_right:No #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o #1 \exp_not:o {#2} } } \cs_new_protected:Npn \tl_gput_right:Nx #1#2 { \cs_gset_nopar:Npx #1 { \exp_not:o {#1} #2 } } \cs_generate_variant:Nn \tl_put_right:Nn { c } \cs_generate_variant:Nn \tl_put_right:NV { c } \cs_generate_variant:Nn \tl_put_right:No { c } \cs_generate_variant:Nn \tl_put_right:Nx { c } \cs_generate_variant:Nn \tl_gput_right:Nn { c } \cs_generate_variant:Nn \tl_gput_right:NV { c } \cs_generate_variant:Nn \tl_gput_right:No { c } \cs_generate_variant:Nn \tl_gput_right:Nx { c } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Reassigning token list category codes} % % \begin{variable}{\c_tl_rescan_marker_tl} % The rescanning code needs a special token list containing the same % character with two different category codes. This is set up here, % while the detail is described below. % \begin{macrocode} \group_begin: \tex_lccode:D `\A = `\@ \scan_stop: \tex_lccode:D `\B = `\@ \scan_stop: \tex_catcode:D `\A = 8 \scan_stop: \tex_catcode:D `\B = 3 \scan_stop: \tex_lowercase:D { \group_end: \tl_const:Nn \c_tl_rescan_marker_tl { A B } } % \end{macrocode} % \end{variable} % % \begin{variable}{\l_tl_rescan_tl} % A token list variable to actually store the material being processed. % \begin{macrocode} \tl_new:N \l_tl_rescan_tl % \end{macrocode} % \end{variable} % % \begin{macro} % { % \tl_set_rescan:Nnn, \tl_set_rescan:Nno, % \tl_set_rescan:cnn, \tl_set_rescan:cno % } % \begin{macro} % { % \tl_gset_rescan:Nnn, \tl_gset_rescan:Nno, % \tl_gset_rescan:cnn, \tl_gset_rescan:cno % } % \begin{macro}[aux]{\tl_set_rescan_aux:NNnn} % \begin{macro}[aux]{\tl_rescan_aux:w} % The idea here is to deal cleanly with the problem that % \cs{tex_scantokens:D} treats the argument as a file, and without % the correct settings a \TeX{} error occurs: % \begin{verbatim} % ! File ended while scanning definition of ... % \end{verbatim} % When expanding a token list this can be handled using \cs{exp_not:N} % but this fails if the token list is not being expanded. So instead % a delimited argument is used with an end marker which cannot appear % within the token list which is scanned: two |@| symbols with different % category codes. The rescanned token list cannot contain the end marker, % because all |@| present in the token list are read with the same category % code. As every character with charcode \cs{tex_newlinechar:D} is replaced % by the \cs{tex_endlinechar:D}, and an extra \cs{tex_endlinechar:D} is % added at the end, we need to set both of those to $-1$, % \enquote{unprintable}. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_set_rescan:Nnn { \tl_set_rescan_aux:NNnn \tl_set:Nn } \cs_new_protected_nopar:Npn \tl_gset_rescan:Nnn { \tl_set_rescan_aux:NNnn \tl_gset:Nn } \cs_new_protected:Npn \tl_set_rescan_aux:NNnn #1#2#3#4 { \group_begin: \exp_args:No \etex_everyeof:D { \c_tl_rescan_marker_tl } \tex_endlinechar:D \c_minus_one \tex_newlinechar:D \c_minus_one #3 \tl_clear:N \l_tl_rescan_tl \exp_after:wN \tl_rescan_aux:w \etex_scantokens:D {#4} \exp_args:NNNo \group_end: #1 #2 \l_tl_rescan_tl } \cs_new_nopar:Npx \tl_rescan_aux:w { \cs_set_protected:Npn \exp_not:N \tl_rescan_aux:w ##1 \c_tl_rescan_marker_tl { \tl_set:Nn \exp_not:N \l_tl_rescan_tl {##1} } } \tl_rescan_aux:w \cs_generate_variant:Nn \tl_set_rescan:Nnn { Nno } \cs_generate_variant:Nn \tl_set_rescan:Nnn { c , cno } \cs_generate_variant:Nn \tl_gset_rescan:Nnn { Nno } \cs_generate_variant:Nn \tl_gset_rescan:Nnn { c , cno } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_set_rescan:Nnx, \tl_set_rescan:cnx} % \begin{macro}{\tl_gset_rescan:Nnx, \tl_gset_rescan:cnx} % \begin{macro}[aux]{\tl_set_rescan_aux:NNnx} % With \texttt{x}-type expansion the \cs{tex_everyoef:D} method % does apply and the code is simple. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_set_rescan:Nnx { \tl_set_rescan_aux:NNnx \tl_set:Nn } \cs_new_protected_nopar:Npn \tl_gset_rescan:Nnx { \tl_set_rescan_aux:NNnx \tl_gset:Nn } \cs_new_protected_nopar:Npn \tl_set_rescan_aux:NNnx #1#2#3#4 { \group_begin: \etex_everyeof:D { \exp_not:N } \tex_endlinechar:D \c_minus_one \tex_newlinechar:D \c_minus_one #3 \tl_set:Nx \l_tl_rescan_tl { \etex_scantokens:D {#4} } \exp_args:NNNo \group_end: #1 #2 \l_tl_rescan_tl } \cs_generate_variant:Nn \tl_set_rescan:Nnx { c } \cs_generate_variant:Nn \tl_gset_rescan:Nnx { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_rescan:nn} % The same idea is also applied to in line token lists. % \begin{macrocode} \cs_new_protected:Npn \tl_rescan:nn #1#2 { \group_begin: \exp_args:No \etex_everyeof:D { \c_tl_rescan_marker_tl } \tex_endlinechar:D \c_minus_one \tex_newlinechar:D \c_minus_one #1 \exp_after:wN \tl_rescan_aux:w \etex_scantokens:D {#2} \exp_args:No \group_end: \l_tl_rescan_tl } % \end{macrocode} % \end{macro} % % \subsection{Reassigning token list character codes} % % \begin{macro}{\tl_to_lowercase:n} % \begin{macro}{\tl_to_uppercase:n} % Just some names for a few primitives. % \begin{macrocode} \cs_new_eq:NN \tl_to_lowercase:n \tex_lowercase:D \cs_new_eq:NN \tl_to_uppercase:n \tex_uppercase:D % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Modifying token list variables} % % \begin{variable}{\l_tl_replace_tl} % A scratch variable for doing token replacement. % \begin{macrocode} \tl_new:N \l_tl_replace_tl % \end{macrocode} % \end{variable} % % % \begin{macro}{\tl_replace_all:Nnn, \tl_replace_all:cnn} % \begin{macro}{\tl_greplace_all:Nnn, \tl_greplace_all:cnn} % \begin{macro}{\tl_replace_once:Nnn, \tl_replace_once:cnn} % \begin{macro}{\tl_greplace_once:Nnn, \tl_greplace_once:cnn} % \begin{macro}[aux]{\tl_replace_aux:NNNnn, \tl_replace_aux_ii:w} % \begin{macro}[aux]{\tl_replace_all_aux:, \tl_replace_once_aux:} % \begin{macro}[aux]{\tl_replace_once_aux_end:w} % All of the replace functions are based on \cs{tl_replace_aux:NNNnn}, % whose arguments are: \meta{function}, \cs{tl_(g)set:Nx}, \meta{tl~var}, % \meta{search tokens}, \meta{replacement tokens}. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_replace_once:Nnn { \tl_replace_aux:NNNnn \tl_replace_once_aux: \tl_set:Nx } \cs_new_protected_nopar:Npn \tl_greplace_once:Nnn { \tl_replace_aux:NNNnn \tl_replace_once_aux: \tl_gset:Nx } \cs_new_protected_nopar:Npn \tl_replace_all:Nnn { \tl_replace_aux:NNNnn \tl_replace_all_aux: \tl_set:Nx } \cs_new_protected_nopar:Npn \tl_greplace_all:Nnn { \tl_replace_aux:NNNnn \tl_replace_all_aux: \tl_gset:Nx } \cs_generate_variant:Nn \tl_replace_once:Nnn { c } \cs_generate_variant:Nn \tl_greplace_once:Nnn { c } \cs_generate_variant:Nn \tl_replace_all:Nnn { c } \cs_generate_variant:Nn \tl_greplace_all:Nnn { c } % \end{macrocode} % The idea is easier to understand by considering the case of % \cs{tl_replace_all:Nnn}. The replacement happens within an % \texttt{x}-type expansion. We use an auxiliary function \cs{tl_tmp:w}, % which essentially replaces the next \meta{search tokens} by % \meta{replacement tokens}. To avoid runaway arguments, % we expand something like \cs{tl_tmp:w} \meta{token list} \cs{q_mark} % \meta{search tokens} \cs{q_stop}, repeating until the end. How do we % detect that we have reached the last occurrence of \meta{search tokens}? % The last replacement is characterized by the fact that the argument of % \cs{tl_tmp:w} contains \cs{q_mark}. In the code below, % \cs{tl_replace_aux_ii:w} takes an argument delimited by \cs{q_mark}, % and removes the following token. Before we reach the end, this gobbles % \cs{q_mark} \cs{use_none_delimit_by_q_stop:w} which appear in the % definition of \cs{tl_tmp:w}, and leaves the \meta{replacement tokens}, % passed to \cs{exp_not:n}, to be included in the \texttt{x}-expanding % definition. At the end, the first \cs{q_mark} is within the argument % of \cs{tl_tmp:w}, and \cs{tl_replace_aux_ii:w} gobbles the second % \cs{q_mark} as well, leaving \cs{use_none_delimit_by_q_stop:w}, % which ends the recursion cleanly. % \begin{macrocode} \cs_new_protected:Npn \tl_replace_aux:NNNnn #1#2#3#4#5 { \tl_if_empty:nTF {#4} { \msg_kernel_error:nnx { tl } { empty-search-pattern } { \tl_to_str:n {#5} } } { \cs_set:Npx \tl_tmp:w ##1##2 #4 { ##2 \exp_not:N \q_mark \exp_not:N \use_none_delimit_by_q_stop:w \exp_not:n { \exp_not:n {#5} } ##1 } #2 #3 { \exp_after:wN #1 #3 \q_mark #4 \q_stop } } } \cs_new:Npn \tl_replace_aux_ii:w #1 \q_mark #2 { \exp_not:o {#1} } % \end{macrocode} % The first argument of \cs{tl_tmp:w} is responsible for repeating % the replacement in the case of \texttt{replace_all}, and stopping % it early for \texttt{replace_once}. Note also that we build % \cs{tl_tmp:w} within an \texttt{x}-expansion so that the % \meta{replacement tokens} can contain |#|. The second % \cs{exp_not:n} ensures that the \meta{replacement tokens} % are not expanded by \cs{tl_(g)set:Nx}. % % Now on to the difference between \enquote{once} and \enquote{all}. % The \cs{prg_do_nothing:} and accompanying \texttt{o}-expansion % ensure that we don't lose braces in case the tokens between two % occurrences of the \meta{search tokens} form a brace group. % \begin{macrocode} \cs_new:Npn \tl_replace_all_aux: { \exp_after:wN \tl_replace_aux_ii:w \tl_tmp:w \tl_replace_all_aux: \prg_do_nothing: } \cs_new_nopar:Npn \tl_replace_once_aux: { \exp_after:wN \tl_replace_aux_ii:w \tl_tmp:w { \tl_replace_once_aux_end:w \prg_do_nothing: } \prg_do_nothing: } \cs_new:Npn \tl_replace_once_aux_end:w #1 \q_mark #2 \q_stop { \exp_not:o {#1} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_remove_once:Nn, \tl_remove_once:cn} % \begin{macro}{\tl_gremove_once:Nn, \tl_gremove_once:cn} % Removal is just a special case of replacement. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_remove_once:Nn #1#2 { \tl_replace_once:Nnn #1 {#2} { } } \cs_new_protected_nopar:Npn \tl_gremove_once:Nn #1#2 { \tl_greplace_once:Nnn #1 {#2} { } } \cs_generate_variant:Nn \tl_remove_once:Nn { c } \cs_generate_variant:Nn \tl_gremove_once:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\tl_remove_all:Nn, \tl_remove_all:cn} % \begin{macro}{\tl_gremove_all:Nn, \tl_gremove_all:cn} % Removal is just a special case of replacement. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_remove_all:Nn #1#2 { \tl_replace_all:Nnn #1 {#2} { } } \cs_new_protected_nopar:Npn \tl_gremove_all:Nn #1#2 { \tl_greplace_all:Nnn #1 {#2} { } } \cs_generate_variant:Nn \tl_remove_all:Nn { c } \cs_generate_variant:Nn \tl_gremove_all:Nn { c } % \end{macrocode} % \end{macro} % % \subsection{Token list conditionals} % % \begin{macro}[pTF]{\tl_if_blank:n,\tl_if_blank:V,\tl_if_blank:o} % \begin{macro}[aux]{\tl_if_blank_p_aux:NNw} % \TeX{} skips spaces when reading a non-delimited arguments. Thus, % a \meta{token list} is blank if and only if \cs{use_none:n} % \meta{token list} |?| is empty. For performance reasons, we hard-code % the emptyness test done in \cs{tl_if_empty:n(TF)}: convert to harmless % characters with \cs{tl_to_str:n}, and then use % \cs{if_meaning:w} \cs{q_nil} |...| \cs{q_nil}. % Note that converting to a string is done after reading the delimited % argument for \cs{use_none:n}. The similar construction % \cs{exp_after:wN} \cs{use_none:n} \cs{tl_to_str:n} \Arg{token list} |?| % would fail if the token list contains the control sequence \cs{ }, % while \cs{tex_escapechar:D} is a space or is unprintable. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_blank:n #1 { p , T , F , TF } { \tl_if_empty_return:o { \use_none:n #1 ? } } \cs_generate_variant:Nn \tl_if_blank_p:n { V } \cs_generate_variant:Nn \tl_if_blank:nT { V } \cs_generate_variant:Nn \tl_if_blank:nF { V } \cs_generate_variant:Nn \tl_if_blank:nTF { V } \cs_generate_variant:Nn \tl_if_blank_p:n { o } \cs_generate_variant:Nn \tl_if_blank:nT { o } \cs_generate_variant:Nn \tl_if_blank:nF { o } \cs_generate_variant:Nn \tl_if_blank:nTF { o } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\tl_if_empty:N,\tl_if_empty:c} % These functions check whether the token list in the argument is % empty and execute the proper code from their argument(s). % \begin{macrocode} \prg_set_conditional:Npnn \tl_if_empty:N #1 { p , T , F , TF } { \if_meaning:w #1 \c_empty_tl \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \tl_if_empty_p:N { c } \cs_generate_variant:Nn \tl_if_empty:NT { c } \cs_generate_variant:Nn \tl_if_empty:NF { c } \cs_generate_variant:Nn \tl_if_empty:NTF { c } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF]{\tl_if_empty:n,\tl_if_empty:V} % It would be tempting to just use |\if_meaning:w \q_nil #1 \q_nil| as % a test since this works really well. However, it fails on a token % list starting with |\q_nil| of course but more troubling is the % case where argument is a complete conditional such as |\if_true:| % a |\else:| b |\fi:| because then |\if_true:| is used by % |\if_meaning:w|, the test turns out false, the |\else:| executes % the false branch, the |\fi:| ends it and the |\q_nil| at the end % starts executing\dots{} A safer route is to convert the entire % token list into harmless characters first and then compare % that. This way the test will even accept |\q_nil| as the first % token. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_empty:n #1 { p , TF , T , F } { \exp_after:wN \if_meaning:w \exp_after:wN \q_nil \tl_to_str:n {#1} \q_nil \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \tl_if_empty_p:n { V } \cs_generate_variant:Nn \tl_if_empty:nTF { V } \cs_generate_variant:Nn \tl_if_empty:nT { V } \cs_generate_variant:Nn \tl_if_empty:nF { V } % \end{macrocode} % \end{macro} % % \begin{macro}[pTF]{\tl_if_empty:o} % \begin{macro}[EXP,aux]{\tl_if_empty_return:o} % The auxiliary function \cs{tl_if_empty_return:o} is for use % in conditionals on token lists, which mostly reduce to testing % if a given token list is empty after applying a simple function % to it. % The test for emptiness is based on \cs{tl_if_empty:n(TF)}, but % the expansion is hard-coded for efficiency, as this auxiliary % function is used in many places. % Note that this works because \cs{tl_to_str:n} expands tokens % that follow until reading a catcode $1$ (begin-group) token. % \begin{macrocode} \cs_new:Npn \tl_if_empty_return:o #1 { \exp_after:wN \if_meaning:w \exp_after:wN \q_nil \tl_to_str:n \exp_after:wN {#1} \q_nil \prg_return_true: \else: \prg_return_false: \fi: } \prg_new_conditional:Npnn \tl_if_empty:o #1 { p , TF , T , F } { \tl_if_empty_return:o {#1} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\tl_if_eq:NN, \tl_if_eq:Nc, \tl_if_eq:cN, \tl_if_eq:cc} % Returns \cs{c_true_bool} if and only if the two token list variables are % equal. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_eq:NN #1#2 { p , T , F , TF } { \if_meaning:w #1 #2 \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \tl_if_eq_p:NN { Nc , c , cc } \cs_generate_variant:Nn \tl_if_eq:NNTF { Nc , c , cc } \cs_generate_variant:Nn \tl_if_eq:NNT { Nc , c , cc } \cs_generate_variant:Nn \tl_if_eq:NNF { Nc , c , cc } % \end{macrocode} % \end{macro} % % \begin{macro}[TF]{\tl_if_eq:nn} % \begin{variable}{\l_tl_tmpa_tl, \l_tl_tmpb_tl} % A simple store and compare routine. % \begin{macrocode} \prg_new_protected_conditional:Npnn \tl_if_eq:nn #1#2 { T , F , TF } { \group_begin: \tl_set:Nn \l_tl_tmpa_tl {#1} \tl_set:Nn \l_tl_tmpb_tl {#2} \if_meaning:w \l_tl_tmpa_tl \l_tl_tmpb_tl \group_end: \prg_return_true: \else: \group_end: \prg_return_false: \fi: } \tl_new:N \l_tl_tmpa_tl \tl_new:N \l_tl_tmpb_tl % \end{macrocode} % \end{variable} % \end{macro} % % \begin{macro}[TF]{\tl_if_in:Nn, \tl_if_in:cn} % See \cs{tl_if_in:nn(TF)} for further comments. Here we simply % expand the token list variable and pass it to \cs{tl_if_in:nn(TF)}. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_if_in:NnT { \exp_args:No \tl_if_in:nnT } \cs_new_protected_nopar:Npn \tl_if_in:NnF { \exp_args:No \tl_if_in:nnF } \cs_new_protected_nopar:Npn \tl_if_in:NnTF { \exp_args:No \tl_if_in:nnTF } \cs_generate_variant:Nn \tl_if_in:NnT { c } \cs_generate_variant:Nn \tl_if_in:NnF { c } \cs_generate_variant:Nn \tl_if_in:NnTF { c } % \end{macrocode} % \end{macro} % % \begin{macro}[TF]{\tl_if_in:nn, \tl_if_in:Vn, \tl_if_in:on, \tl_if_in:no} % Once more, the test relies on \cs{tl_to_str:n} for robustness. % The function \cs{tl_tmp:w} removes tokens until the first occurrence % of |#2|. If this does not appear in |#1|, then the final |#2| is removed, % leaving an empty token list. Otherwise some tokens remain, and the % test is false. See \cs{tl_if_empty:n(TF)} for details on % the emptyness test. % % Special care is needed to treat correctly cases like % |\tl_if_in:nnTF {a state}{states}|, where |#1#2| contains |#2| before % the end. To cater for this case, we insert |{}{}| between the two token % lists. This marker may not appear in |#2| because of \TeX{} limitations % on what can delimit a parameter, hence we are safe. Using two brace % groups makes the test work also for empty arguments. % \begin{macrocode} \prg_new_protected_conditional:Npnn \tl_if_in:nn #1#2 { T , F , TF } { \cs_set:Npn \tl_tmp:w ##1 #2 { } \tl_if_empty:oTF { \tl_tmp:w #1 {} {} #2 } { \prg_return_false: } { \prg_return_true: } } \cs_generate_variant:Nn \tl_if_in:nnT { V } \cs_generate_variant:Nn \tl_if_in:nnF { V } \cs_generate_variant:Nn \tl_if_in:nnTF { V } \cs_generate_variant:Nn \tl_if_in:nnT { o } \cs_generate_variant:Nn \tl_if_in:nnF { o } \cs_generate_variant:Nn \tl_if_in:nnTF { o } \cs_generate_variant:Nn \tl_if_in:nnT { no } \cs_generate_variant:Nn \tl_if_in:nnF { no } \cs_generate_variant:Nn \tl_if_in:nnTF { no } % \end{macrocode} % \end{macro} % % \subsection{Mapping to token lists} % % \begin{macro}{\tl_map_function:nN} % \begin{macro}{\tl_map_function:NN, \tl_map_function:cN} % \begin{macro}[aux]{\tl_map_function_aux:NN} % Expandable loop macro for token lists. These have the advantage of not % needing to test if the argument is empty, because if it is, the stop % marker will be read immediately and the loop terminated. % \begin{macrocode} \cs_new:Npn \tl_map_function:nN #1#2 { \tl_map_function_aux:Nn #2 #1 \q_recursion_tail \q_recursion_stop } \cs_new_nopar:Npn \tl_map_function:NN #1#2 { \exp_after:wN \tl_map_function_aux:Nn \exp_after:wN #2 #1 \q_recursion_tail \q_recursion_stop } \cs_new:Npn \tl_map_function_aux:Nn #1#2 { \quark_if_recursion_tail_stop:n {#2} #1 {#2} \tl_map_function_aux:Nn #1 } \cs_generate_variant:Nn \tl_map_function:NN { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_map_inline:nn} % \begin{macro}{\tl_map_inline:Nn, \tl_map_inline:cn} % \begin{macro}[aux]{\tl_map_inline_aux:n} % \begin{variable}{\g_tl_inline_level_int} % The inline functions are straight forward by now. We use a little % trick with the counter \cs{g_tl_inline_level_int} to make % them nestable. We can also make use of \cs{tl_map_function:Nn} % from before. (\cs{g_tl_inline_level_int} is defined in \pkg{l3int} % for order-of-loading reasons.) % \begin{macrocode} \cs_new_protected:Npn \tl_map_inline:nn #1#2 { \int_gincr:N \g_tl_inline_level_int \cs_gset:cpn { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } ##1 {#2} \exp_args:Nc \tl_map_function_aux:Nn { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } #1 \q_recursion_tail \q_recursion_stop \int_gdecr:N \g_tl_inline_level_int } \cs_new_protected:Npn \tl_map_inline:Nn #1#2 { \int_gincr:N \g_tl_inline_level_int \cs_gset:cpn { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } ##1 {#2} \exp_last_unbraced:NcV \tl_map_function_aux:Nn { tl_map_inline_ \int_use:N \g_tl_inline_level_int :n } #1 \q_recursion_tail\q_recursion_stop \int_gdecr:N \g_tl_inline_level_int } \cs_generate_variant:Nn \tl_map_inline:Nn { c } % \end{macrocode} % \end{variable} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_map_variable:nNn} % \begin{macro}{\tl_map_variable:NNn, \tl_map_variable:cNn} % \begin{macro}[aux]{\tl_map_variable_aux:NnN} % \cs{tl_map_variable:nNn} \meta{token list} \meta{temp} \meta{action} % assigns % \meta{temp} to each element and executes \meta{action}. % \begin{macrocode} \cs_new_protected:Npn \tl_map_variable:nNn #1#2#3 { \tl_map_variable_aux:Nnn #2 {#3} #1 \q_recursion_tail \q_recursion_stop } \cs_new_protected_nopar:Npn \tl_map_variable:NNn { \exp_args:No \tl_map_variable:nNn } \cs_new_protected:Npn \tl_map_variable_aux:Nnn #1#2#3 { \tl_set:Nn #1 {#3} \quark_if_recursion_tail_stop:N #1 #2 \tl_map_variable_aux:Nnn #1 {#2} } \cs_generate_variant:Nn \tl_map_variable:NNn { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_map_break:} % The break statement. % \begin{macrocode} \cs_new_eq:NN \tl_map_break: \use_none_delimit_by_q_recursion_stop:w % \end{macrocode} % \end{macro} % % \subsection{Using token lists} % % \begin{macro}{\tl_to_str:n} % Another name for a primitive. % \begin{macrocode} \cs_new_eq:NN \tl_to_str:n \etex_detokenize:D % \end{macrocode} % \end{macro} % % \begin{macro}{\tl_to_str:N, \tl_to_str:c} % These functions return the replacement text of a token list as a % string. % \begin{macrocode} \cs_new_nopar:Npn \tl_to_str:N #1 { \etex_detokenize:D \exp_after:wN {#1} } \cs_generate_variant:Nn \tl_to_str:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}{\tl_use:N, \tl_use:c} % \begin{macro}[aux]{\tl_error_message:} % Token lists which are simply not defined will give a clear \TeX{} % error here. No such luck for ones equal to \cs{scan_stop:} so % instead a test is made and if there is an issue an error is forced. % \begin{macrocode} \cs_new_eq:NN \tl_use:N \prg_do_nothing: \cs_new_nopar:Npn \tl_use:c #1 { \if_cs_exist:w #1 \cs_end: \cs:w #1 \exp_after:wN \cs_end: \else: \msg_expandable_error:n { Undefined~variable~name~'#1'! } \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Working with the contents of token lists} % % \begin{macro}{\tl_length:n, \tl_length:V, \tl_length:o} % \begin{macro}{\tl_length:N, \tl_length:c} % \begin{macro}[aux]{\tl_length_aux:n} % Count number of elements within a token list or token list % variable. Brace groups within the list are read as a single % element. Spaces are ignored. % \cs{tl_length_aux:n} grabs the element and replaces it by |+1|. % The |0| to ensure it works on an empty list. % \begin{macrocode} \cs_new:Npn \tl_length:n #1 { \int_eval:n { 0 \tl_map_function:nN {#1} \tl_length_aux:n } } \cs_new_nopar:Npn \tl_length:N #1 { \int_eval:n { 0 \tl_map_function:NN #1 \tl_length_aux:n } } \cs_new:Npn \tl_length_aux:n #1 { + 1 } \cs_generate_variant:Nn \tl_length:n { V , o } \cs_generate_variant:Nn \tl_length:N { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_reverse_items:n} % \begin{macro}[aux]{\tl_reverse_items_aux:nN} % Reversal of a token list is done by taking one item at a time % and putting it after \cs{q_recursion_stop}. % \begin{macrocode} \cs_new:Npn \tl_reverse_items:n #1 { \tl_reverse_items_aux:nw #1 \q_recursion_tail \q_recursion_stop } \cs_new:Npn \tl_reverse_items_aux:nw #1 #2 \q_recursion_stop { \quark_if_recursion_tail_stop_do:nn {#1} { \use_none:n } \tl_reverse_items_aux:nw #2 \q_recursion_stop {#1} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\tl_trim_spaces:n} % \begin{macro} % { % \tl_trim_spaces:N, \tl_trim_spaces:c, % \tl_gtrim_spaces:N, \tl_gtrim_spaces:c % } % \begin{macro}[aux] % { % \tl_trim_spaces_aux_i:w, \tl_trim_spaces_aux_ii:w % \tl_trim_spaces_aux_iii:w, \tl_trim_spaces_aux_iv:w % } % Trimming spaces from around the input is done using delimited % arguments and quarks, and to get spaces at odd places in the % definitions, we nest those in \cs{tl_tmp:w}, which then receives % a single space as its argument: |#1| is \verb*+ +. % Removing leading spaces is done with \cs{tl_trim_spaces_aux_i:w}, % which loops until \cs{q_mark}\verb*+ + matches the end of the token % list: then |##1| is the token list and |##3| is % \cs{tl_trim_spaces_aux_ii:w}. This hands the relevant tokens to the % loop \cs{tl_trim_spaces_aux_iii:w}, responsible for trimming % trailing spaces. The end is reached when \verb*+ + \cs{q_nil} % matches the one present in the definition of \cs{tl_trim_spacs:n}. % Then \cs{tl_trim_spaces_aux_iv:w} puts the token list into a group, % as the argument of the initial \cs{etex_unexpanded:D}. % The \cs{etex_unexpanded:D} here is used so that space trimming will % behave correctly within an \texttt{x}-type expansion. % \begin{macrocode} \cs_set:Npn \tl_tmp:w #1 { \cs_new:Npn \tl_trim_spaces:n ##1 { \etex_unexpanded:D \tl_trim_spaces_aux_i:w \q_mark ##1 \q_nil \q_mark #1 { } \q_mark \tl_trim_spaces_aux_ii:w \tl_trim_spaces_aux_iii:w #1 \q_nil \tl_trim_spaces_aux_iv:w \q_stop } \cs_new:Npn \tl_trim_spaces_aux_i:w ##1 \q_mark #1 ##2 \q_mark ##3 { ##3 \tl_trim_spaces_aux_i:w \q_mark ##2 \q_mark #1 {##1} } \cs_new:Npn \tl_trim_spaces_aux_ii:w ##1 \q_mark \q_mark ##2 { \tl_trim_spaces_aux_iii:w ##2 } \cs_new:Npn \tl_trim_spaces_aux_iii:w ##1 #1 \q_nil ##2 { ##2 ##1 \q_nil \tl_trim_spaces_aux_iii:w } \cs_new:Npn \tl_trim_spaces_aux_iv:w ##1 \q_nil ##2 \q_stop { \exp_after:wN { \use_none:n ##1 } } } \tl_tmp:w { ~ } \cs_new_protected:Npn \tl_trim_spaces:N #1 { \tl_set:Nx #1 { \exp_after:wN \tl_trim_spaces:n \exp_after:wN {#1} } } \cs_new_protected:Npn \tl_gtrim_spaces:N #1 { \tl_gset:Nx #1 { \exp_after:wN \tl_trim_spaces:n \exp_after:wN {#1} } } \cs_generate_variant:Nn \tl_trim_spaces:N { c } \cs_generate_variant:Nn \tl_gtrim_spaces:N { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{The first token from a token list} % % \begin{macro}{\tl_head:n, \tl_head:V, \tl_head:v, \tl_head:f} % \begin{macro}{\tl_head:w} % \begin{macro}{\tl_tail:n, \tl_tail:V, \tl_tail:v, \tl_tail:f} % \begin{macro}{\tl_tail:w} % These functions pick up either the head or the tail of a list. The % empty brace groups in \cs{tl_head:n} and \cs{tl_tail:n} ensure that % a blank argument gives an empty result. % \begin{macrocode} \cs_new:Npn \tl_head:w #1#2 \q_stop {#1} \cs_new:Npn \tl_tail:w #1#2 \q_stop {#2} \cs_new:Npn \tl_head:n #1 { \tl_head:w #1 { } \q_stop } \cs_new:Npn \tl_tail:n #1 { \tl_tail_aux:w #1 \q_mark { } \q_mark \q_stop } \cs_new:Npn \tl_tail_aux:w #1 #2 \q_mark #3 \q_stop { #2 } \cs_generate_variant:Nn \tl_head:n { V , v , f } \cs_generate_variant:Nn \tl_tail:n { V , v , f } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\str_head:n, \str_tail:n} % \begin{macro}[aux]{\str_head_aux:w} % After \cs{tl_to_str:n}, we have a list of character tokens, % all with category code 12, except the space, which has category % code 10. Directly using \cs{tl_head:w} would thus lose leading spaces. % Instead, we take an argument delimited by an explicit space, and % then only use \cs{tl_head:w}. If the string started with a % space, then the argument of \cs{str_head_aux:w} is empty, and % the function correctly returns a space character. Otherwise, % it returns the first token of |#1|, which is the first token % of the string. If the string is empty, we return an empty result. % % To remove the first character of \cs{tl_to_str:n} |{#1}|, % we test it using \cs{if_charcode:w} \cs{scan_stop:}, % always false for characters. If the argument was non-empty, % then \cs{str_tail_aux:w} returns everything until the first % \texttt{X} (with category code letter, no risk of confusing % with the user input). If the argument was empty, the first % \texttt{X} is taken by \cs{if_charcode:w}, and nothing % is returned. We use \texttt{X} as a \meta{marker}, rather than % a quark because the test \cs{if_charcode:w} \cs{scan_stop:} % \meta{marker} has to be false. % \begin{macrocode} \cs_new:Npn \str_head:n #1 { \exp_after:wN \str_head_aux:w \tl_to_str:n {#1} { { } } ~ \q_stop } \cs_new_nopar:Npn \str_head_aux:w #1 ~ % { \tl_head:w #1 { ~ } } \cs_new:Npn \str_tail:n #1 { \exp_after:wN \str_tail_aux:w \reverse_if:N \if_charcode:w \scan_stop: \tl_to_str:n {#1} X X \q_stop } \cs_new_nopar:Npn \str_tail_aux:w #1 X #2 \q_stop { \fi: #1 } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\tl_if_head_eq_meaning:nN} % \begin{macro}[pTF]{\tl_if_head_eq_charcode:nN} % \begin{macro}[pTF]{\tl_if_head_eq_charcode:fN} % \begin{macro}[pTF]{\tl_if_head_eq_catcode:nN} % Accessing the first token of a token list is tricky in two cases: % when it has category code $1$ (begin-group token), or when it is % an explicit space, with category code $10$ and character code $32$. % % Forgetting temporarily about this issue we would use the % following test in \cs{tl_if_head_eq_charcode:nN}. Here, % an empty |#1| argument yields \cs{q_nil}, otherwise the % first token of the token list. % \begin{verbatim} % \if_charcode:w % \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop % \exp_not:N #2 % \end{verbatim} % The special cases are detected using \cs{tl_if_head_N_type:n} % (the extra |?| takes care of empty arguments). % In those cases, the first token is a character, and % since we only care about its character code, we can % use \cs{str_head:n} to access it (this works even if % it is a space character). % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_eq_charcode:nN #1#2 { p , T , F , TF } { \if_charcode:w \exp_not:N #2 \tl_if_head_N_type:nTF { #1 ? } { \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop } { \str_head:n {#1} } \prg_return_true: \else: \prg_return_false: \fi: } \cs_generate_variant:Nn \tl_if_head_eq_charcode_p:nN { f } \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNTF { f } \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNT { f } \cs_generate_variant:Nn \tl_if_head_eq_charcode:nNF { f } % \end{macrocode} % For \cs{tl_if_head_eq_catcode:nN}, again we detect special % cases with a \cs{tl_if_head_N_type}. Then we need to test % if the first token is a begin-group token or an explicit % space token, and produce the relevant token, either % \cs{c_group_begin_token} or \cs{c_space_token}. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_eq_catcode:nN #1 #2 { p , T , F , TF } { \if_catcode:w \exp_not:N #2 \tl_if_head_N_type:nTF { #1 ? } { \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop } { \tl_if_head_group:nTF {#1} { \c_group_begin_token } { \c_space_token } } \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % For \cs{tl_if_head_eq_meaning:nN}, again, detect special cases. % In the normal case, use \cs{tl_head:w}, with no \cs{exp_not:N} % this time, since \cs{if_meaning:w} causes no expansion. % In the special cases, we know that the first token is a character, % hence \cs{if_charcode:w} and \cs{if_catcode:w} together are enough. % We combine them in some order, hopefully faster than the reverse. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_eq_meaning:nN #1#2 { p , T , F , TF } { \tl_if_head_N_type:nTF { #1 ? } { \tl_if_head_eq_meaning_aux_normal:nN } { \tl_if_head_eq_meaning_aux_special:nN } {#1} #2 } \cs_new:Npn \tl_if_head_eq_meaning_aux_normal:nN #1 #2 { \exp_after:wN \if_meaning:w \tl_head:w #1 \q_nil \q_stop #2 \prg_return_true: \else: \prg_return_false: \fi: } \cs_new:Npn \tl_if_head_eq_meaning_aux_special:nN #1 #2 { \if_charcode:w \str_head:n {#1} \exp_not:N #2 \exp_after:wN \use:n \else: \prg_return_false: \exp_after:wN \use_none:n \fi: { \if_catcode:w \exp_not:N #2 \tl_if_head_group:nTF {#1} { \c_group_begin_token } { \c_space_token } \prg_return_true: \else: \prg_return_false: \fi: } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[pTF]{\tl_if_head_N_type:n} % The first token of a token list can be either an N-type argument, % a begin-group token (catcode 1), or an explicit space token % (catcode 10 and charcode 32). These two cases are characterized % by the fact that \cs{use:n} removes some tokens from |#1|, hence % changing its string representation (no token can have an empty % string representation). The extra brace group covers the case of % an empty argument, whose head is not \enquote{normal}. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_N_type:n #1 { p , T , F , TF } { \str_if_eq_return:on { \use:n #1 { } } { #1 { } } } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP,pTF]{\tl_if_head_group:n} % Pass the first token of |#1| through \cs{token_to_str:N}, % then check for the brace balance. The extra \texttt{?} % caters for an empty argument.\footnote{Bruno: this could % be made faster, but we don't: if we hope to ever have % an e-type argument, we need all brace \enquote{tricks} % to happen in one step of expansion, keeping the token % list brace balanced at all times.} % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_group:n #1 { p , T , F , TF } { \if_predicate:w \exp_after:wN \use_none:n \exp_after:wN { \exp_after:wN { \token_to_str:N #1 ? } \c_false_bool } \c_true_bool \prg_return_false: \else: \prg_return_true: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP,pTF]{\tl_if_head_space:n} % \begin{macro}[EXP,aux]{\tl_if_head_space_aux:w} % If the first token of the token list is an explicit space, i.e., % a character token with character code $32$ and category code $10$, % then this test will be \meta{true}. It is \meta{false} if the token % list is empty, if the first token is an implicit space token, % such as \cs{c_space_token}, or any token other than an explicit space. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_head_space:n #1 { p , T , F , TF } { \if_int_compare:w \pdftex_strcmp:D { } { \tl_if_head_space_aux:w \prg_do_nothing: #1 ? ~ } = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } \cs_new:Npn \tl_if_head_space_aux:w #1 ~ % { \exp_not:o {#1} \if_false: { \fi: } \exp_after:wN \use_none:n \exp_after:wN { \if_false: } \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Viewing token lists} % % \begin{macro}{\tl_show:N, \tl_show:c} % Showing token list variables is done directly: at the moment do not % worry if they are defined. % \begin{macrocode} \cs_new_protected:Npn \tl_show:N #1 { \cs_show:N #1 } \cs_generate_variant:Nn \tl_show:N { c } % \end{macrocode} %\end{macro} % % \begin{macro}{\tl_show:n} % For literal token lists, life is easy. % \begin{macrocode} \cs_new_eq:NN \tl_show:n \etex_showtokens:D % \end{macrocode} %\end{macro} % % \subsection{Constant token lists} % % \begin{variable}{\c_job_name_tl} % Inherited from the \LaTeX3 name for the primitive: this needs to % actually contain the text of the job name rather than the name of % the primitive, of course. \LuaTeX{} does not quote file names containing % spaces, whereas \pdfTeX{} and \XeTeX{} do. So there may be a correction to % make in the \LuaTeX{} case. % \begin{macrocode} %<*package> \tl_const:Nx \c_job_name_tl { \tex_jobname:D } % %<*initex> \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D \luatex_if_engine:TF { \tl_if_in:onTF { \tex_jobname:D } { ~ } { \tl_const:Nx \c_job_name_tl { " \tex_jobname:D " } } { \tl_const:Nx \c_job_name_tl { \tex_jobname:D } } } { \tl_const:Nx \c_job_name_tl { \tex_jobname:D } } } % % \end{macrocode} % \end{variable} % % \begin{variable}{\c_empty_tl} % Never full. % \begin{macrocode} \tl_const:Nn \c_empty_tl { } % \end{macrocode} % \end{variable} % % \begin{variable}{\c_space_tl} % A space as a token list (as opposed to as a character). % \begin{macrocode} \tl_const:Nn \c_space_tl { ~ } % \end{macrocode} % \end{variable} % % \subsection{Scratch token lists} % % \begin{variable}{\g_tmpa_tl, \g_tmpb_tl} % Global temporary token list variables. % They are supposed to be set and used immediately, % with no delay between the definition and the use because you % can't count on other macros not to redefine them from under you. % \begin{macrocode} \tl_new:N \g_tmpa_tl \tl_new:N \g_tmpb_tl % \end{macrocode} % \end{variable} % % \begin{variable}{\l_tmpa_tl, \l_tmpb_tl} % These are local temporary token list variables. Be sure not to assume % that the value you put into them will survive for % long---see discussion above. % \begin{macrocode} \tl_new:N \l_tmpa_tl \tl_new:N \l_tmpb_tl % \end{macrocode} % \end{variable} % % \subsection{Experimental functions} % % \begin{macro}[EXP,pTF]{\str_if_eq_return:on} % It turns out that we often need to compare a token list % with the result of applying some function to it, and % return with \cs{prg_return_true/false:}. This test is % similar to \cs{str_if_eq:nnTF}, but hard-coded for speed. % \begin{macrocode} \cs_new:Npn \str_if_eq_return:on #1 #2 { \if_int_compare:w \pdftex_strcmp:D { \exp_not:o {#1} } { \exp_not:n {#2} } = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP,pTF]{\tl_if_single:N} % Expand the token list and feed it to \cs{tl_if_single:n}. % \begin{macrocode} \cs_new:Npn \tl_if_single_p:N { \exp_args:No \tl_if_single_p:n } \cs_new:Npn \tl_if_single:NT { \exp_args:No \tl_if_single:nT } \cs_new:Npn \tl_if_single:NF { \exp_args:No \tl_if_single:nF } \cs_new:Npn \tl_if_single:NTF { \exp_args:No \tl_if_single:nTF } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP,pTF]{\tl_if_single:n} % A token list has exactly one item if it is either a single % token surrounded by optional explicit spaces, or a single brace % group surrounded by optional explicit spaces. The naive % version of this test would do \cs{use_none:n} |#1|, and % test if the result is empty. However, this will fail when % the token list is empty. Furthermore, it does not allow optional % trailing spaces. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_single:n #1 { p , T , F , TF } { \str_if_eq_return:on { \use_none:nn #1 ?? } {?} } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP,pTF]{\tl_if_single_token:n} % There are four cases: empty token list, token list starting with % a normal token, with a brace group, or with a space token. % If the token list starts with a normal token, remove it % and check for emptyness. Otherwise, compare with a single % space, only case where we have a single token. % \begin{macrocode} \prg_new_conditional:Npnn \tl_if_single_token:n #1 { p , T , F , TF } { \tl_if_head_N_type:nTF {#1} { \str_if_eq_return:on { \use_none:n #1 } { } } { \str_if_eq_return:on { ~ } { #1 } } } % \end{macrocode} % \end{macro} % % \begin{variable}{\q_tl_act_mark,\q_tl_act_stop} % The \cs{tl_act} functions may be applied to any token list. % Hence, we use two private quarks, to allow any token, even quarks, % in the token list.^^A in particular critical for future \::e. % Only \cs{q_tl_act_mark} and \cs{q_tl_act_stop} may not appear % in the token lists manipulated by \cs{tl_act} functions. The quarks % are effectively defined in \pkg{l3quark}. % \end{variable} % % \begin{macro}[EXP]{\tl_act:NNNnn,\tl_act_aux:NNNnn} % \begin{macro}[EXP]{\tl_act_output:n,\tl_act_reverse_output:n, % \tl_act_group_recurse:Nnn} % \begin{macro}[EXP,aux]{\tl_act_loop:w,\tl_act_normal:NwnNNN, % \tl_act_group:nwnNNN,\tl_act_space:wwnNNN,\tl_act_end:w} % To help control the expansion, \cs{tl_act:NNNnn} starts with % \cs{tex_romannumeral:D} and ends by producing \cs{c_zero} % once the result has been obtained. Then loop over tokens, % groups, and spaces in |#5|. The marker \cs{q_tl_act_mark} % is used both to avoid losing outer braces and to detect the % end of the token list more easily. The result is stored % as an argument for the dummy function \cs{tl_act_result:n}. % \begin{macrocode} \cs_new:Npn \tl_act:NNNnn { \tex_romannumeral:D \tl_act_aux:NNNnn } \cs_new:Npn \tl_act_aux:NNNnn #1 #2 #3 #4 #5 { \tl_act_loop:w #5 \q_tl_act_mark \q_tl_act_stop {#4} #1 #2 #3 \tl_act_result:n { } } % \end{macrocode} % In the loop, we check how the token list begins and act % accordingly. In the \enquote{normal} case, we may have % reached \cs{q_tl_act_mark}, the end of the list. Then % leave \cs{c_zero} and the result in the input stream, % to terminate the expansion of \cs{tex_romannumeral:D}. % Otherwise, apply the relevant function to the % \enquote{arguments}, |#3| % and to the head of the token list. Then repeat the loop. % The scheme is the same if the token list starts with a % group or with a space. Some extra work is needed to % make \cs{tl_act_space:wwnNNN} gobble the space. % \begin{macrocode} \cs_new:Npn \tl_act_loop:w #1 \q_tl_act_stop { \tl_if_head_N_type:nTF {#1} { \tl_act_normal:NwnNNN } { \tl_if_head_group:nTF {#1} { \tl_act_group:nwnNNN } { \tl_act_space:wwnNNN } } #1 \q_tl_act_stop } \cs_new:Npn \tl_act_normal:NwnNNN #1 #2 \q_tl_act_stop #3#4 { \if_meaning:w \q_tl_act_mark #1 \exp_after:wN \tl_act_end:wn \fi: #4 {#3} #1 \tl_act_loop:w #2 \q_tl_act_stop {#3} #4 } \cs_new:Npn \tl_act_end:wn #1 \tl_act_result:n #2 { \c_zero #2 } \cs_new:Npn \tl_act_group:nwnNNN #1 #2 \q_tl_act_stop #3#4#5 { #5 {#3} {#1} \tl_act_loop:w #2 \q_tl_act_stop {#3} #4 #5 } \exp_last_unbraced:NNo \cs_new:Npn \tl_act_space:wwnNNN \c_space_tl #1 \q_tl_act_stop #2#3#4#5 { #5 {#2} \tl_act_loop:w #1 \q_tl_act_stop {#2} #3 #4 #5 } % \end{macrocode} % Typically, the output is done to the right of what was already output, % using \cs{tl_act_output:n}, but for the \cs{tl_act_reverse} functions, % it should be done to the left. % \begin{macrocode} \cs_new:Npn \tl_act_output:n #1 #2 \tl_act_result:n #3 { #2 \tl_act_result:n { #3 #1 } } \cs_new:Npn \tl_act_reverse_output:n #1 #2 \tl_act_result:n #3 { #2 \tl_act_result:n { #1 #3 } } % \end{macrocode} % In many applications of \cs{tl_act:NNNnn}, we need to recursively % apply some transformation within brace groups, then output. In this % code, |#1| is the output function, |#2| is the transformation, % which should expand in two steps, and |#3| is the group. % \begin{macrocode} \cs_new:Npn \tl_act_group_recurse:Nnn #1#2#3 { \exp_args:Nf #1 { \exp_after:wN \exp_after:wN \exp_after:wN { #2 {#3} } } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\tl_reverse_tokens:n} % \begin{macro}[EXP,aux]{\tl_act_reverse_normal:nN, % \tl_act_reverse_group:nn, \tl_act_reverse_space:n} % The goal is to reverse a token list. This is done by feeding % \cs{tl_act_aux:NNNnn} three functions, an empty fourth argument % (we don't use it for \cs{tl_act_reverse_tokens:n}), and as % a fifth argument the token list to be reversed. % Spaces and normal tokens are output to the left of the current % output. For groups, we must recursively apply % \cs{tl_act_reverse_tokens:n} to the group, and output, still % on the left. Note that in all three cases, we throw one argument % away: this \meta{parameter} is where for instance the % upper/lowercasing action stores the information of whether it % is uppercasing or lowercasing. % \begin{macrocode} \cs_new:Npn \tl_reverse_tokens:n { \tex_romannumeral:D \tl_act_aux:NNNnn \tl_act_reverse_normal:nN \tl_act_reverse_group:nn \tl_act_reverse_space:n { } } \cs_new:Npn \tl_act_reverse_space:n #1 { \tl_act_reverse_output:n {~} } \cs_new:Npn \tl_act_reverse_normal:nN #1 #2 { \tl_act_reverse_output:n {#2} } \cs_new:Npn \tl_act_reverse_group:nn #1 { \tl_act_group_recurse:Nnn \tl_act_reverse_output:n { \tl_reverse_tokens:n } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[EXP]{\tl_reverse:n,\tl_reverse:o,\tl_reverse:V} % \begin{macro}[EXP,aux]{\tl_reverse_group_preserve:nn} % The goal here is to reverse without losing spaces nor braces. % The only difference with \cs{tl_reverse_tokens:n} is that % we now simply output groups without entering them. % \begin{macrocode} \cs_new:Npn \tl_reverse:n { \tex_romannumeral:D \tl_act_aux:NNNnn \tl_act_reverse_normal:nN \tl_act_reverse_group_preserve:nn \tl_act_reverse_space:n { } } \cs_new:Npn \tl_act_reverse_group_preserve:nn #1 #2 { \tl_act_reverse_output:n { {#2} } } \cs_generate_variant:Nn \tl_reverse:n { o , V } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\tl_reverse:N, \tl_reverse:c} % This reverses the list, leaving |{}| in front, which in turn % is removed by the \cs{etex_unexpanded:D} primitive. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_reverse:N #1 { \tl_set:No #1 { \etex_unexpanded:D \tl_reverse:o { #1 { } } } } \cs_generate_variant:Nn \tl_reverse:N { c } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\tl_length_tokens:n} % \begin{macro}[EXP,aux]{\tl_act_length_normal:nN, % \tl_act_length_group:nn,\tl_act_length_space:n} % The length is computed through an \cs{int_eval:n} construction. % Each \texttt{1+} is output to the \emph{left}, into the integer % expression, and the sum is ended by the \cs{c_zero} inserted by % \cs{tl_act_end:wn}. Somewhat a hack. % \begin{macrocode} \cs_new:Npn \tl_length_tokens:n #1 { \int_eval:n { \tl_act_aux:NNNnn \tl_act_length_normal:nN \tl_act_length_group:nn \tl_act_length_space:n { } {#1} } } \cs_new:Npn \tl_act_length_normal:nN #1 #2 { 1 + } \cs_new:Npn \tl_act_length_space:n #1 { 1 + } \cs_new:Npn \tl_act_length_group:nn #1 #2 { 2 + \tl_length_tokens:n {#2} + } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{variable}{\c_tl_act_uppercase_tl, \c_tl_act_lowercase_tl} % These constants contain the correspondance between lowercase % and uppercase letters, in the form |aAbBcC...| and |AaBbCc...| % respectively. % \begin{macrocode} \tl_const:Nn \c_tl_act_uppercase_tl { aA bB cC dD eE fF gG hH iI jJ kK lL mM nN oO pP qQ rR sS tT uU vV wW xX yY zZ } \tl_const:Nn \c_tl_act_lowercase_tl { Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz } % \end{macrocode} % \end{variable} % % \begin{macro}[EXP]{\tl_expandable_uppercase:n,\tl_expandable_lowercase:n} % \begin{macro}[EXP,aux]{\tl_act_case_normal:nN, % \tl_act_case_group:nn,\tl_act_case_space:n} % The only difference between uppercasing and lowercasing is % the table of correspondance that is used. As for other % token list actions, we feed \cs{tl_act_aux:NNNnn} three % functions, and this time, we use the \meta{parameters} % argument to carry which case-changing we are applying. % A space is simply output. A normal token is compared % to each letter in the alphabet using \cs{str_if_eq:nn} % tests, and converted if necessary to upper/lowercase, % before being output. For a group, we must perform the % conversion within the group (the \cs{exp_after:wN} trigger % \cs{tex_romannumeral:D}, which expands fully to give the % converted group), then output. % \begin{macrocode} \cs_new:Npn \tl_expandable_uppercase:n { \tex_romannumeral:D \tl_act_case_aux:nn { \c_tl_act_uppercase_tl } } \cs_new:Npn \tl_expandable_lowercase:n { \tex_romannumeral:D \tl_act_case_aux:nn { \c_tl_act_lowercase_tl } } \cs_new:Npn \tl_act_case_aux:nn { \tl_act_aux:NNNnn \tl_act_case_normal:nN \tl_act_case_group:nn \tl_act_case_space:n } \cs_new:Npn \tl_act_case_space:n #1 { \tl_act_output:n {~} } \cs_new:Npn \tl_act_case_normal:nN #1 #2 { \exp_args:Nf \tl_act_output:n { \exp_args:NNo \prg_case_str:nnn #2 {#1} { \exp_stop_f: #2 } } } \cs_new:Npn \tl_act_case_group:nn #1 #2 { \exp_after:wN \tl_act_output:n \exp_after:wN { \exp_after:wN { \tex_romannumeral:D \tl_act_case_aux:nn {#1} {#2} } } } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Deprecated functions} % % \begin{macro}{\tl_new:Nn, \tl_new:cn, \tl_new:Nx} % Use either \cs{tl_const:Nn} or \cs{tl_new:N}. % \begin{macrocode} \cs_new_protected:Npn \tl_new:Nn #1#2 { \tl_new:N #1 \tl_gset:Nn #1 {#2} } \cs_generate_variant:Nn \tl_new:Nn { c } \cs_generate_variant:Nn \tl_new:Nn { Nx } % \end{macrocode} % \end{macro} % % \begin{macro}{\tl_gset:Nc} % \begin{macro}{\tl_set:Nc} % This was useful once, but nowadays does not make much sense. % \begin{macrocode} \cs_new_protected_nopar:Npn \tl_gset:Nc { \pref_global:D \tl_set:Nc } \cs_new_protected_nopar:Npn \tl_set:Nc #1#2 { \tl_set:No #1 { \cs:w #2 \cs_end: } } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\tl_replace_in:Nnn, \tl_replace_in:cnn} % \begin{macro}{\tl_greplace_in:Nnn, \tl_greplace_in:cnn} % \begin{macro}{\tl_replace_all_in:Nnn, \tl_replace_all_in:cnn} % \begin{macro}{\tl_greplace_all_in:Nnn, \tl_greplace_all_in:cnn} % These are renamed. % \begin{macrocode} \cs_new_eq:NN \tl_replace_in:Nnn \tl_replace_once:Nnn \cs_new_eq:NN \tl_replace_in:cnn \tl_replace_once:cnn \cs_new_eq:NN \tl_greplace_in:Nnn \tl_greplace_once:Nnn \cs_new_eq:NN \tl_greplace_in:cnn \tl_greplace_once:cnn \cs_new_eq:NN \tl_replace_all_in:Nnn \tl_replace_all:Nnn \cs_new_eq:NN \tl_replace_all_in:cnn \tl_replace_all:cnn \cs_new_eq:NN \tl_greplace_all_in:Nnn \tl_greplace_all:Nnn \cs_new_eq:NN \tl_greplace_all_in:cnn \tl_greplace_all:cnn % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_remove_in:Nn, \tl_remove_in:cn} % \begin{macro}{\tl_gremove_in:Nn, \tl_gremove_in:cn} % \begin{macro}{\tl_remove_all_in:Nn, \tl_remove_all_in:cn} % \begin{macro}{\tl_gremove_all_in:Nn, \tl_gremove_all_in:cn} % Also renamed. % \begin{macrocode} \cs_new_eq:NN \tl_remove_in:Nn \tl_remove_once:Nn \cs_new_eq:NN \tl_remove_in:cn \tl_remove_once:cn \cs_new_eq:NN \tl_gremove_in:Nn \tl_gremove_once:Nn \cs_new_eq:NN \tl_gremove_in:cn \tl_gremove_once:cn \cs_new_eq:NN \tl_remove_all_in:Nn \tl_remove_all:Nn \cs_new_eq:NN \tl_remove_all_in:cn \tl_remove_all:cn \cs_new_eq:NN \tl_gremove_all_in:Nn \tl_gremove_all:Nn \cs_new_eq:NN \tl_gremove_all_in:cn \tl_gremove_all:cn % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\tl_elt_count:n, \tl_elt_count:V, \tl_elt_count:o} % \begin{macro}{\tl_elt_count:N, \tl_elt_count:c} % Another renaming job. % \begin{macrocode} \cs_new_eq:NN \tl_elt_count:n \tl_length:n \cs_new_eq:NN \tl_elt_count:V \tl_length:V \cs_new_eq:NN \tl_elt_count:o \tl_length:o \cs_new_eq:NN \tl_elt_count:N \tl_length:N \cs_new_eq:NN \tl_elt_count:c \tl_length:c % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\tl_head_i:n} % \begin{macro}{\tl_head_i:w} % \begin{macro}{\tl_head_iii:n} % \begin{macro}{\tl_head_iii:f} % \begin{macro}{\tl_head_iii:w} % Two renames, and a few that are rather too specialised. % \begin{macrocode} \cs_new_eq:NN \tl_head_i:n \tl_head:n \cs_new_eq:NN \tl_head_i:w \tl_head:w \cs_new:Npn \tl_head_iii:n #1 { \tl_head_iii:w #1 \q_stop } \cs_generate_variant:Nn \tl_head_iii:n { f } \cs_new:Npn \tl_head_iii:w #1#2#3#4 \q_stop {#1#2#3} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex