From c9172879c19139ba8d262e615a535073caea2e54 Mon Sep 17 00:00:00 2001
From: Karl Berry <karl@freefriends.org>
Date: Fri, 12 Aug 2011 23:14:34 +0000
Subject: l3kernel (11aug11)

git-svn-id: svn://tug.org/texlive/trunk@23524 c570f23f-e606-0410-a88d-b1316a301751
---
 Master/texmf-dist/source/latex/l3kernel/l3tl.dtx | 234 ++++++++++++++++++-----
 1 file changed, 181 insertions(+), 53 deletions(-)

(limited to 'Master/texmf-dist/source/latex/l3kernel/l3tl.dtx')

diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
index a7f292d14c7..149f4a487ba 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
@@ -35,7 +35,7 @@
 %
 %<*driver|package>
 \RequirePackage{l3names}
-\GetIdInfo$Id: l3tl.dtx 2498 2011-07-09 17:51:47Z joseph $
+\GetIdInfo$Id: l3tl.dtx 2534 2011-08-10 18:21:44Z joseph $
   {L3 Experimental token lists}
 %</driver|package>
 %<*driver>
@@ -768,44 +768,87 @@
 %   \begin{syntax}
 %     \cs{tl_head:n} \Arg{tokens}
 %   \end{syntax}
-%   Leaves only the first \meta{token} in \meta{tokens} in the input
-%   stream, discarding the remainder.
+%   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} \Arg{tokens} \cs{q_stop}
+%     \cs{tl_head:w} \meta{tokens} \cs{q_stop}
 %   \end{syntax}
-%   Leaves only the first \meta{token} in \meta{tokens} in the input
-%   stream, discarding the remainder. This function requires only a
-%   single expansion, and so is suitable for use inside an
-%   \texttt{o}-type expansion. In general \cs{tl_head:n} should be
-%   preferred.
+%   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]{\str_head:n}
+%   \begin{syntax}
+%     \cs{str_head:n} \Arg{tokens}
+%   \end{syntax}
+%   Converts the \meta{tokens} into a string, as described for
+%   \cs{tl_to_str:n}, and then leaves the first character of this string
+%   in the input stream; the first character may be a space. If the
+%   \meta{tokens} argument is entirely empty, \cs{scan_stop:} will be left in
+%   the input stream. 
 % \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 first \meta{token} of the \meta{tokens} and leaves the
-%   remainder in the input stream.
+%   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 first \meta{token} of the \meta{tokens} and leaves the
-%   remainder in the input stream. This function requires only a
-%   single expansion, and so is suitable for use inside an
-%   \texttt{o}-type expansion. In general \cs{tl_tail:n} should be
-%   preferred.
+%   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,pTF]{\tl_if_head_eq_catcode:nN}
 %   \begin{syntax}
-%     \cs{tl_if_head_eq_catcode_p:n} \Arg{token list} \meta{test token}
-%     \cs{tl_if_head_eq_catcode:nTF} \Arg{token list} \meta{test token}
+%     \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
@@ -820,8 +863,8 @@
 % \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:n} \Arg{token list} \meta{test token}
-%     \cs{tl_if_head_eq_charcode:nTF} \Arg{token list} \meta{test token}
+%     \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
@@ -835,8 +878,8 @@
 %
 % \begin{function}[EXP,pTF]{\tl_if_head_eq_meaning:nN}
 %   \begin{syntax}
-%     \cs{tl_if_head_eq_meaning_p:n} \Arg{token list} \meta{test token}
-%     \cs{tl_if_head_eq_meaning:nTF} \Arg{token list} \meta{test token}
+%     \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
@@ -976,7 +1019,7 @@
 %   ~~\Arg{true code} \Arg{false code}
 %   \end{syntax}
 %   Tests if the token list consists of exactly one token, i.e.,
-%   is either a single space character or a single ``normal'' token.
+%   is either a single space character or a single \enquote{normal} token.
 %   Token groups are not single tokens. The branching
 %   versions leaves either \meta{true code} or \meta{false code}
 %   in the input stream, as appropriate to the truth of the test and
@@ -1922,12 +1965,16 @@
 % \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.
+%  These functions pick up either the head or the tail of a list. The
+%  \texttt{n}-type implementation needs a test in order to avoid run-away
+%  arguments occurring with blank input.
 %    \begin{macrocode}
-\cs_new:Npn \tl_head:n #1 { \tl_head:w #1 \q_stop }
-\cs_new:Npn \tl_tail:n #1 { \tl_tail:w #1 \q_stop }
 \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_if_blank:nF {#1} { \tl_head:w #1 \q_stop } }
+\cs_new:Npn \tl_tail:n #1
+  { \tl_if_blank:nF {#1} { \tl_tail:w #1 \q_stop } }
 \cs_generate_variant:Nn \tl_head:n { V , v , f }
 \cs_generate_variant:Nn \tl_tail:n { V , v , f }
 %    \end{macrocode}
@@ -1936,54 +1983,135 @@
 % \end{macro}
 % \end{macro}
 %
+% \begin{macro}{\str_head: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
+%   \cs{scan_stop:}.
+%    \begin{macrocode}
+\cs_new:Npn \str_head:n #1
+  {
+    \exp_after:wN \str_head_aux:w
+    \tl_to_str:n {#1}
+    { \scan_stop: } ~ \q_stop
+  }
+\cs_new_nopar:Npn \str_head_aux:w #1 ~ %
+  { \tl_head:w #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}
-%   When we want to check if the first token of a list equals something
-%   specific it is usually either to see if it is a control sequence or
-%   a character. Hence we make two different functions as the internal
-%   test is different.
-%   \cs{tl_if_head_meaning_eq:nNTF} uses \cs{if_meaning:w} and will
-%   consider the tokens |b|$\sb{11}$ and |b|$\sb{12}$ different.
-%   \cs{tl_if_head_char_eq:nNTF} on the other hand only compares
-%   character codes so would regard |b|$\sb{11}$ and |b|$\sb{12}$ as
-%   equal but would also regard two primitives as equal.
+%   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 by comparing |#1| with
+%   \cs{use:n}~|#1| (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_meaning:nN #1#2 { p , T , F , TF }
+\prg_new_conditional:Npnn \tl_if_head_eq_charcode:nN #1#2 { p , T , F , TF }
   {
-    \exp_after:wN \if_meaning:w \tl_head:w #1 \q_stop #2
+    \if_charcode:w
+        \exp_not:N #2
+        \str_if_eq:onTF { \use:n #1 ? } { #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 the charcode and catcode versions we insert |\exp_not:N| in
-%   front of both tokens. If you need them to expand fully as \TeX{}
-%   does itself with these you can use an |f| type expansion.
+%   For \cs{tl_if_head_eq_catcode:nN}, again we detect special
+%   cases with a \cs{str_if_eq:onTF} test. 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_charcode:nN #1#2 { p , T , F , TF }
+\prg_new_conditional:Npnn \tl_if_head_eq_catcode:nN #1 #2 { p , T , F , TF }
   {
-    \exp_after:wN \if:w
-      \exp_after:wN \exp_not:N \tl_head:w #1 \q_stop \exp_not:N #2
+    \if_catcode:w
+        \exp_not:N #2
+        \str_if_eq:onTF { \use:n #1 ? } { #1 ? }
+          { \exp_after:wN \exp_not:N \tl_head:w #1 \q_nil \q_stop }
+          {
+            \tl_if_head_begin_group:nTF {#1}
+              { \c_group_begin_token }
+              { \c_space_token }
+          }
       \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}
-% And now catcodes:
+%   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_catcode:nN #1#2 { p , T , F , TF }
+\prg_new_conditional:Npnn \tl_if_head_eq_meaning:nN #1#2 { p , T , F , TF }
   {
-    \exp_after:wN \if_catcode:w \exp_after:wN \exp_not:N
-        \tl_head:w #1 \q_stop \exp_not:N #2
-      \prg_return_true: \else: \prg_return_false: \fi:
+    \str_if_eq:onTF { \use:n #1 ? } { #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_begin_group:nTF {#1}
+                      { \c_group_begin_token }
+                      { \c_space_token }
+        \prg_return_true:
+      \else:
+        \prg_return_false:
+      \fi:
+    }
   }
 %    \end{macrocode}
 % \end{macro}
-- 
cgit v1.2.3

