summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex')
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3dt/l3dt.dtx8
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3flag.dtx2
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx59
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx3623
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx389
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx4140
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins47
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx12
-rw-r--r--Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx4
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/expl3.dtx6
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3.ins93
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3basics.dtx39
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx6
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3box.dtx12
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx20
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3clist.dtx22
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3doc.dtx3
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3expan.dtx23
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3file.dtx420
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3format.ins92
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx10
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx12
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3fp.dtx14
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3int.dtx219
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3keys.dtx9
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3msg.dtx10
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3prg.dtx37
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3prop.dtx339
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3seq.dtx33
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3skip.dtx186
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3tl.dtx35
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3token.dtx34
-rw-r--r--Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx26
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx110
-rw-r--r--Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx8
35 files changed, 5279 insertions, 4823 deletions
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3dt/l3dt.dtx b/Master/texmf-dist/source/latex/l3experimental/l3dt/l3dt.dtx
index 984739d1efd..63a3218f06a 100644
--- a/Master/texmf-dist/source/latex/l3experimental/l3dt/l3dt.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/l3dt/l3dt.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File l3dt.dtx Copyright (C) 2011,2012 The LaTeX3 Project
+%% File l3dt.dtx Copyright (C) 2011-2013 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
@@ -36,7 +36,7 @@
%
%<*driver|package>
\RequirePackage{expl3}
-\GetIdInfo$Id: l3dt.dtx 4190 2012-09-03 00:23:31Z bruno $
+\GetIdInfo$Id: l3dt.dtx 4420 2013-01-08 20:00:04Z joseph $
{L3 Experimental data tables}
%</driver|package>
%<*driver>
@@ -1195,7 +1195,7 @@
}
% \end{macrocode}
% The second iteration is along the row. This is basically the same as
-% \cs{prop_if_in:NnTF} with the \cs{q_@@} in place of \cs{q_prop}.
+% \cs{prop_if_in:NnTF} with the \cs{q_@@} in place of \cs{q__prop}.
% \begin{macrocode}
\cs_new:Npn \@@_if_in_row:nn #1#2
{
@@ -1204,7 +1204,7 @@
}
\cs_new:Npn \@@_if_in_row:nwn #1 \q_@@ #2 \q_@@ #3
{
- \str_if_eq:xxTF {#1} {#2}
+ \str_if_eq_x:nnTF {#1} {#2}
{ \@@_if_in_row:N }
{ \@@_if_in_row:nwn {#1} }
}
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3flag.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3flag.dtx
index d3b17183671..64d23d43896 100644
--- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3flag.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3flag.dtx
@@ -210,7 +210,7 @@
\else:
\exp_after:wN \use_none_delimit_by_q_stop:w
\fi:
- \cs_set_eq:cN { @@_#2_#1: } \c_undefined:D
+ \cs_set_eq:cN { @@_#2_#1: } \tex_undefined:D
\exp_after:wN \@@_clear:ww
\int_use:N \__int_eval:w \c_one + #1 ;
#2 \q_stop
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx
index 3d25a841a80..7260ca7667f 100644
--- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3regex.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3regex.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3regex.dtx Copyright (C) 2011-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{expl3}
-\GetIdInfo$Id: l3regex.dtx 4341 2012-11-27 08:39:42Z bruno $
+\GetIdInfo$Id: l3regex.dtx 4455 2013-01-22 20:38:19Z bruno $
{L3 Experimental regular expressions}
%</driver|package>
%<*driver>
@@ -320,7 +320,11 @@
% still be escaped without harm. Any escape sequence which matches a
% single character (|\d|, |\D|, \emph{etc.}) is supported in character
% classes. If the first character is |^|, then
-% the meaning of the character class is inverted. Ranges of characters
+% the meaning of the character class is inverted; |^| appearing anywhere
+% else in the range is not special. If the first character (possibly
+% following a leading |^|) is |]| then it does not need to be escaped
+% since ending the range there would make it empty.
+% Ranges of characters
% can be expressed using |-|, for instance, |[\D 0-5]| and |[^6-9]| are
% equivalent.
%
@@ -712,7 +716,7 @@
%<*package>
\ProvidesExplPackage
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
-\RequirePackage{l3tl-build, l3tl-analysis, l3flag, l3str}
+\RequirePackage{l3tl-build, l3tl-analysis, l3flag, l3str, l3str-convert}
%</package>
% \end{macrocode}
%
@@ -911,7 +915,7 @@
% This function makes showing regular expressions easier, and lets us
% define |\D| in terms of |\d| for instance. There is a subtelty: the
% end of the query is marked by $-2$, and will thus match |\D| and
-% other negated properties; this case is catched by another part of
+% other negated properties; this case is caught by another part of
% the code.
% \begin{macrocode}
\cs_new_protected:Npn \@@_item_reverse:n #1
@@ -1375,7 +1379,7 @@
{
\__msg_kernel_error:nnx { regex } { x-overflow } {#1}
\tl_set:Nx \l_@@_internal_b_tl
- { \if_false: } \fi: \@@_escape_loop:N
+ { \if_false: } \fi:
}
{
\char_set_lccode:nn { \c_zero } {#1}
@@ -1384,7 +1388,6 @@
\tl_set:Nx \l_@@_internal_b_tl
{ \if_false: } \fi:
\@@_escape_raw:N ^^@
- \@@_escape_loop:N
}
}
}
@@ -1414,7 +1417,7 @@
}
\cs_new:Npn \@@_escape_x_test_two:N #1
{
- \if_charcode:w \c_lbrace_str #1
+ \if_charcode:w \c_left_brace_str #1
\exp_after:wN \@@_escape_x_loop:N
\else:
\__str_hexadecimal_use:NTF #1
@@ -1454,7 +1457,7 @@
{ \@@_escape_x_loop:N }
{
;
- \exp_after:wN \token_if_eq_charcode:NNTF \c_rbrace_str #1
+ \exp_after:wN \token_if_eq_charcode:NNTF \c_right_brace_str #1
{ \@@_escape_loop:N }
{
\if_false: { \fi: }
@@ -1487,9 +1490,7 @@
% \end{itemize}
% The code is ugly, and highly based on magic numbers and the ascii
% codes of characters. This is mostly unavoidable for performance
-% reasons: testing for instance with \cs{__str_if_contains_char:nN}
-% would be much slower. Maybe the tests can be optimized a little
-% bit more.
+% reasons. Maybe the tests can be optimized a little bit more.
% Here, \enquote{alphanumeric} means \texttt{0}--\texttt{9},
% \texttt{A}--\texttt{Z}, \texttt{a}--\texttt{z};
% \enquote{special} character means non-alphanumeric
@@ -2111,17 +2112,17 @@
% brace, leading to the range $[a,\infty]$ or $[a,b]$, encoded as
% $\{a\}\{-1\}$ and $\{a\}\{b-a\}$.
% \begin{macrocode}
-\cs_new_protected:cpn { @@_compile_quantifier_ \c_lbrace_str :w }
+\cs_new_protected:cpn { @@_compile_quantifier_ \c_left_brace_str :w }
{
\@@_get_digits:NTFw \l_@@_internal_a_int
{ \@@_compile_quantifier_braced_auxi:w }
- { \@@_compile_quantifier_abort:xNN { \c_lbrace_str } }
+ { \@@_compile_quantifier_abort:xNN { \c_left_brace_str } }
}
\cs_new_protected:Npn \@@_compile_quantifier_braced_auxi:w #1#2
{
\str_case_x:nnn { #1 #2 }
{
- { \@@_compile_special:N \c_rbrace_str }
+ { \@@_compile_special:N \c_right_brace_str }
{
\exp_args:No \@@_compile_quantifier_lazyness:nnNN
{ \int_use:N \l_@@_internal_a_int } { 0 }
@@ -2135,28 +2136,28 @@
}
{
\@@_compile_quantifier_abort:xNN
- { \c_lbrace_str \int_use:N \l_@@_internal_a_int }
+ { \c_left_brace_str \int_use:N \l_@@_internal_a_int }
#1 #2
}
}
\cs_new_protected:Npn \@@_compile_quantifier_braced_auxii:w #1#2
{
\str_if_eq_x:nnTF
- { #1 #2 } { \@@_compile_special:N \c_rbrace_str }
+ { #1 #2 } { \@@_compile_special:N \c_right_brace_str }
{
\exp_args:No \@@_compile_quantifier_lazyness:nnNN
{ \int_use:N \l_@@_internal_a_int } { -1 }
}
{
\@@_compile_quantifier_abort:xNN
- { \c_lbrace_str \int_use:N \l_@@_internal_a_int , }
+ { \c_left_brace_str \int_use:N \l_@@_internal_a_int , }
#1 #2
}
}
\cs_new_protected:Npn \@@_compile_quantifier_braced_auxiii:w #1#2
{
\str_if_eq_x:nnTF
- { #1 #2 } { \@@_compile_special:N \c_rbrace_str }
+ { #1 #2 } { \@@_compile_special:N \c_right_brace_str }
{
\if_int_compare:w \l_@@_internal_a_int > \l_@@_internal_b_int
\__msg_kernel_error:nnxx { regex } { backwards-quantifier }
@@ -2173,7 +2174,7 @@
{
\@@_compile_quantifier_abort:xNN
{
- \c_lbrace_str
+ \c_left_brace_str
\int_use:N \l_@@_internal_a_int ,
\int_use:N \l_@@_internal_b_int
}
@@ -2856,7 +2857,7 @@
% to forbid nesting |\c|. Additionally, disable submatch tracking
% since groups don't escape the scope of |\c{...}|.
% \begin{macrocode}
-\cs_new_protected_nopar:cpn { @@_compile_c_ \c_lbrace_str :w }
+\cs_new_protected_nopar:cpn { @@_compile_c_ \c_left_brace_str :w }
{
\@@_compile:w
\@@_disable_submatches:
@@ -2875,7 +2876,7 @@
% dangling class or group). Then insert the corresponding test in the
% outer regex.
% \begin{macrocode}
-\cs_new_protected:cpn { @@_compile_ \c_rbrace_str : }
+\cs_new_protected:cpn { @@_compile_ \c_right_brace_str : }
{
\@@_if_in_cs:TF
{
@@ -2883,7 +2884,7 @@
\@@_compile_one:x
{ \@@_item_cs:n { \exp_not:o \l_@@_internal_regex } }
}
- { \exp_after:wN \@@_compile_raw:N \c_rbrace_str }
+ { \exp_after:wN \@@_compile_raw:N \c_right_brace_str }
}
% \end{macrocode}
% \end{macro}
@@ -2907,7 +2908,7 @@
\@@_if_in_class_or_catcode:TF
{ \@@_compile_raw_error:N u #1 #2 }
{
- \str_if_eq_x:nnTF {#1#2} { \@@_compile_special:N \c_lbrace_str }
+ \str_if_eq_x:nnTF {#1#2} { \@@_compile_special:N \c_left_brace_str }
{
\tl_set:Nx \l_@@_internal_a_tl { \if_false: } \fi:
\@@_compile_u_loop:NN
@@ -2925,7 +2926,7 @@
{
\token_if_eq_meaning:NNTF #1 \@@_compile_special:N
{
- \exp_after:wN \token_if_eq_charcode:NNTF \c_rbrace_str #2
+ \exp_after:wN \token_if_eq_charcode:NNTF \c_right_brace_str #2
{ \if_false: { \fi: } \@@_compile_u_end: }
{ #2 \@@_compile_u_loop:NN }
}
@@ -4733,7 +4734,7 @@
\tl_clear:N \l_@@_balance_tl
\@@_escape_use:nnnn
{
- \if_charcode:w \c_rbrace_str ##1
+ \if_charcode:w \c_right_brace_str ##1
\@@_replacement_rbrace:N \else: \__tl_build_one:n \fi: ##1
}
{ \@@_replacement_escaped:N ##1 }
@@ -4820,7 +4821,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_replacement_g:w #1#2
{
- \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_lbrace_str }
+ \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_left_brace_str }
{
\int_zero:N \l_@@_internal_a_int
\@@_replacement_g_digits:NN
@@ -4877,7 +4878,7 @@
}
{ \@@_replacement_error:NNN c #1#2 }
}
-\cs_new_protected_nopar:cpn { @@_replacement_c_ \c_lbrace_str :w }
+\cs_new_protected_nopar:cpn { @@_replacement_c_ \c_left_brace_str :w }
{
\if_case:w \l_@@_replacement_csnames_int
\__tl_build_one:n
@@ -4898,7 +4899,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_replacement_u:w #1#2
{
- \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_lbrace_str }
+ \str_if_eq_x:nnTF { #1#2 } { \__tl_build_one:n \c_left_brace_str }
{
\if_case:w \l_@@_replacement_csnames_int
\__tl_build_one:n { \exp_not:n { \exp_after:wN \exp_not:V \cs:w } }
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx
new file mode 100644
index 00000000000..1810468ff7d
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-convert.dtx
@@ -0,0 +1,3623 @@
+% \iffalse meta-comment
+%
+%% File: l3str-convert.dtx Copyright (C) 2013 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 "l3experimental 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{expl3}
+\GetIdInfo$Id: l3str-convert.dtx 4339 2013-01-08 10:22:00Z bruno $
+ {L3 Experimental string encoding conversions}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\usepackage{amsmath}
+\begin{document}
+ \tableofcontents
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%
+% \title{^^A
+% The \textsf{l3str-convert} package: string encoding conversions^^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
+%
+% \newcommand{\hexnum}[1]{\text{\texttt{\char`\"}#1}}
+% \begin{documentation}
+%
+% \section{Encoding and escaping schemes}
+%
+% Traditionally, string encodings only specify how strings of characters
+% should be stored as bytes. However, the resulting lists of bytes are
+% often to be used in contexts where only a restricted subset of bytes
+% are permitted (\emph{e.g.}, \textsc{pdf} string objects,
+% \textsc{url}s). Hence, storing a string of characters is done in two
+% steps.
+% \begin{itemize}
+% \item The code points (\enquote{character codes}) are expressed as
+% bytes following a given \enquote{encoding}. This can be
+% \textsc{utf-16}, \textsc{iso 8859-1}, \emph{etc.} See
+% Table~\ref{tab:encodings} for a list of supported
+% encodings.\footnote{Encodings and escapings will be added as they
+% are requested.}
+% \item Bytes are translated to \TeX{} tokens through a given
+% \enquote{escaping}. Those are defined for the most part by the
+% \texttt{pdf} file format. See Table~\ref{tab:escapings} for a
+% list of escaping methods supported.\footnotemark
+% \end{itemize}
+%
+% \begin{table}\centering
+% \caption{\label{tab:encodings}Supported encodings.
+% Non-alphanumeric characters are ignored,
+% and capital letters are lower-cased
+% before searching for the encoding in this list.}
+% \begin{tabular}{cc}
+% \toprule
+% \meta{Encoding} & description \\
+% \midrule
+% \texttt{utf8} & \textsc{utf-8} \\
+% \texttt{utf16} & \textsc{utf-16}, with byte-order mark \\
+% \texttt{utf16be} & \textsc{utf-16}, big-endian \\
+% \texttt{utf16le} & \textsc{utf-16}, little-endian \\
+% \texttt{utf32} & \textsc{utf-32}, with byte-order mark \\
+% \texttt{utf32be} & \textsc{utf-32}, big-endian \\
+% \texttt{utf32le} & \textsc{utf-32}, little-endian \\
+% \midrule
+% \texttt{iso88591}, \texttt{latin1} & \textsc{iso 8859-1} \\
+% \texttt{iso88592}, \texttt{latin2} & \textsc{iso 8859-2} \\
+% \texttt{iso88593}, \texttt{latin3} & \textsc{iso 8859-3} \\
+% \texttt{iso88594}, \texttt{latin4} & \textsc{iso 8859-4} \\
+% \texttt{iso88595} & \textsc{iso 8859-5} \\
+% \texttt{iso88596} & \textsc{iso 8859-6} \\
+% \texttt{iso88597} & \textsc{iso 8859-7} \\
+% \texttt{iso88598} & \textsc{iso 8859-8} \\
+% \texttt{iso88599}, \texttt{latin5} & \textsc{iso 8859-9} \\
+% \texttt{iso885910}, \texttt{latin6} & \textsc{iso 8859-10} \\
+% \texttt{iso885911} & \textsc{iso 8859-11} \\
+% \texttt{iso885913}, \texttt{latin7} & \textsc{iso 8859-13} \\
+% \texttt{iso885914}, \texttt{latin8} & \textsc{iso 8859-14} \\
+% \texttt{iso885915}, \texttt{latin9} & \textsc{iso 8859-15} \\
+% \texttt{iso885916}, \texttt{latin10} & \textsc{iso 8859-16} \\
+% \midrule
+% Empty & Native (Unicode) string. \\
+% \bottomrule
+% \end{tabular}
+% \end{table}
+%
+% \begin{table}\centering
+% \caption{\label{tab:escapings}Supported escapings.
+% Non-alphanumeric characters are ignored,
+% and capital letters are lower-cased
+% before searching for the escaping in this list.}
+% \begin{tabular}{cc}
+% \toprule
+% \meta{Escaping} & description \\
+% \midrule
+% \texttt{bytes}, or empty
+% & arbitrary bytes \\
+% \texttt{hex}, \texttt{hexadecimal}
+% & byte $=$ two hexadecimal digits \\
+% \texttt{name}
+% & see \tn{pdfescapename} \\
+% \texttt{string}
+% & see \tn{pdfescapestring} \\
+% \texttt{url}
+% & encoding used in \textsc{url}s \\
+% \bottomrule
+% \end{tabular}
+% \end{table}
+%
+% \section{Conversion functions}
+%
+% \begin{function}{\str_set_convert:Nnnn, \str_gset_convert:Nnnn}
+% \begin{syntax}
+% \cs{str_set_convert:Nnnn} \meta{str~var} \Arg{string} \Arg{name~1} \Arg{name~2}
+% \end{syntax}
+% This function converts the \meta{string} from the encoding given by
+% \meta{name~1} to the encoding given by \meta{name~2}, and stores the
+% result in the \meta{str~var}. Each \meta{name} can have the form
+% \meta{encoding} or \meta{encoding}\texttt{/}\meta{escaping}, where
+% the possible values of \meta{encoding} and \meta{escaping} are given
+% in Tables~\ref{tab:encodings} and~\ref{tab:escapings}, respectively.
+% The default escaping is to input and output bytes directly. The
+% special case of an empty \meta{name} indicates the use of
+% \enquote{native} strings, 8-bit for pdf\TeX{}, and Unicode strings
+% for the other two engines.
+%
+% For example,
+% \begin{verbatim}
+% \str_set_convert:Nnnn \l_foo_str { Hello! } { } { utf16/hex }
+% \end{verbatim}
+% results in the variable \cs{l_foo_str} holding the string
+% \texttt{FEFF00480065006C006C006F0021}. This is obtained by
+% converting each character in the (native) string \texttt{Hello!} to
+% the \textsc{utf-16} encoding, and expressing each byte as a pair of
+% hexadecimal digits. Note the presence of a (big-endian) byte order
+% mark \hexnum{FEFF}, which can be avoided by specifying the encoding
+% \texttt{utf16be/hex}.
+%
+% An error is raised if the \meta{string} is not valid according to
+% the \meta{escaping~1} and \meta{encoding~1}, or if it cannot be
+% reencoded in the \meta{encoding~2} and \meta{escaping~2} (for
+% instance, if a character does not exist in the \meta{encoding~2}).
+% Erroneous input is replaced by the Unicode replacement character
+% \hexnum{FFFD}, and characters which cannot be reencoded are replaced
+% by either the replacement character \hexnum{FFFD} if it exists in
+% the \meta{encoding~2}, or an encoding-specific replacement
+% character, or the question mark character.
+% \end{function}
+%
+% \begin{function}[TF]{\str_set_convert:Nnnn, \str_gset_convert:Nnnn}
+% \begin{syntax}
+% \cs{str_set_convert:NnnnTF} \meta{str~var} \Arg{string} \Arg{name~1} \Arg{name~2} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% As \cs{str_set_convert:Nnnn}, converts the \meta{string} from the
+% encoding given by \meta{name~1} to the encoding given by
+% \meta{name~2}, and assigns the result to \meta{str~var}. Contrarily
+% to \cs{str_set_convert:Nnnn}, the conditional variant does not raise
+% errors in case the \meta{string} is not valid according to the
+% \meta{name~1} encoding, or cannot be expressed in the \meta{name~2}
+% encoding. Instead, the \meta{false code} is performed.
+% \end{function}
+%
+% \begin{variable}{\c_max_char_int}
+% The maximum valid character code, $255$ for pdf\TeX{}, and $1114111$
+% for \XeTeX{} and \LuaTeX{}.
+% \end{variable}
+%
+% \section{Internal string functions}
+%
+% \begin{function}{\__str_gset_other:Nn}
+% \begin{syntax}
+% \cs{__str_gset_other:Nn} \meta{tl~var} \Arg{token list}
+% \end{syntax}
+% Converts the \meta{token list} to an \meta{other string}, where
+% spaces have category code \enquote{other}, and assigns the result to
+% the \meta{tl~var}, globally.
+% \end{function}
+%
+% \begin{function}{\__str_hexadecimal_use:NTF}
+% \begin{syntax}
+% \cs{__str_hexadecimal_use:NTF} \meta{token} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% If the \meta{token} is a hexadecimal digit (upper case or lower
+% case), its upper-case version is left in the input stream,
+% \emph{followed} by the \meta{true code}. Otherwise, the \meta{false
+% code} is left in the input stream.
+% \begin{texnote}
+% This function fails on some inputs if the escape character is a
+% hexadecimal digit. We are thus careful to set the escape
+% character to a known (safe) value before using it.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}[EXP]{\__str_output_byte:n}
+% \begin{syntax}
+% \cs{__str_output_byte:n} \Arg{intexpr}
+% \end{syntax}
+% Expands to a character token with category other and character code
+% equal to the value of \meta{intexpr}. The value of \meta{intexpr}
+% must be in the range $[-1, 255]$, and any value outside this range
+% results in undefined behaviour. The special value $-1$ is used to
+% produce an empty result.
+% \end{function}
+%
+% \section{Possibilities, and things to do}
+%
+% Encoding/escaping-related tasks.
+% \begin{itemize}
+% \item Describe the internal format in the code comments. Refuse code
+% points in $[\hexnum{D800}, \hexnum{DFFF}]$ in the internal
+% representation?
+% \item Add documentation about each encoding and escaping method, and
+% add examples.
+% \item The \texttt{hex} unescaping should raise an error for
+% odd-token count strings.
+% \item Decide what bytes should be escaped in the \texttt{url}
+% escaping. Perhaps |!'()*-./0123456789_| are safe, and all other
+% characters should be escaped?
+% \item Automate generation of 8-bit mapping files.
+% \item Change the framework for 8-bit encodings: for decoding from
+% 8-bit to Unicode, use $256$ integer registers; for encoding, use a
+% tree-box.
+% \item More encodings (see Heiko's \pkg{stringenc}). CESU?
+% \item More escapings: shell escapes, lua escapes, etc?
+% \end{itemize}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3str} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=str>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\RequirePackage{l3str,l3tl-analysis,l3tl-build,l3flag}
+% \end{macrocode}
+%
+% \subsection{Helpers}
+%
+% \subsubsection{A function unrelated to strings}
+%
+% \begin{macro}[EXP,aux]{\use_ii_i:nn}
+% A function used to swap its arguments.
+% \begin{macrocode}
+\cs_if_exist:NF \use_ii_i:nn
+ { \cs_new:Npn \use_ii_i:nn #1#2 { #2 #1 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Variables and constants}
+%
+% \begin{variable}{\c_max_char_int}
+% The maximum valid character code is $255$ for pdf\TeX{}, and
+% $1114111$ for other engines.
+% \begin{macrocode}
+\int_const:Nn \c_max_char_int
+ { \pdftex_if_engine:TF { "FF } { "10FFFF } }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_tmp:w}
+% \begin{variable}{\l_@@_internal_int}
+% \begin{variable}{\l_@@_internal_tl}
+% Internal scratch space for some functions.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_tmp:w { }
+\tl_new:N \l_@@_internal_tl
+\int_new:N \l_@@_internal_int
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+% \end{macro}
+%
+% \begin{variable}{\g_@@_result_tl}
+% The \cs{g_@@_result_tl} variable is used to hold the result of
+% various internal string operations (mostly conversions) which are
+% typically performed in a group. The variable is global so that it
+% remains defined outside the group, to be assigned to a user-provided
+% variable.
+% \begin{macrocode}
+\tl_new:N \g_@@_result_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\c_@@_replacement_char_int}
+% When converting, invalid bytes are replaced by the Unicode
+% replacement character \hexnum{FFFD}.
+% \begin{macrocode}
+\int_const:Nn \c_@@_replacement_char_int { "FFFD }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \c_forty_eight, \c_fifty_eight, \c_sixty_five, \c_ninety_one,
+% \c_ninety_seven, \c_one_hundred_twenty_three,
+% \c_one_hundred_twenty_seven
+% }
+% We declare here some integer values which delimit ranges of \textsc{ascii}
+% characters of various types. This is mostly used in \pkg{l3regex}.
+% \begin{macrocode}
+\int_const:Nn \c_forty_eight { 48 }
+\int_const:Nn \c_fifty_eight { 58 }
+\int_const:Nn \c_sixty_five { 65 }
+\int_const:Nn \c_ninety_one { 91 }
+\int_const:Nn \c_ninety_seven { 97 }
+\int_const:Nn \c_one_hundred_twenty_three { 123 }
+\int_const:Nn \c_one_hundred_twenty_seven { 127 }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_alias_prop}
+% To avoid needing one file per encoding/escaping alias, we keep track
+% of those in a property list.
+% \begin{macrocode}
+\prop_new:N \g_@@_alias_prop
+\prop_gput:Nnn \g_@@_alias_prop { latin1 } { iso88591 }
+\prop_gput:Nnn \g_@@_alias_prop { latin2 } { iso88592 }
+\prop_gput:Nnn \g_@@_alias_prop { latin3 } { iso88593 }
+\prop_gput:Nnn \g_@@_alias_prop { latin4 } { iso88594 }
+\prop_gput:Nnn \g_@@_alias_prop { latin5 } { iso88599 }
+\prop_gput:Nnn \g_@@_alias_prop { latin6 } { iso885910 }
+\prop_gput:Nnn \g_@@_alias_prop { latin7 } { iso885913 }
+\prop_gput:Nnn \g_@@_alias_prop { latin8 } { iso885914 }
+\prop_gput:Nnn \g_@@_alias_prop { latin9 } { iso885915 }
+\prop_gput:Nnn \g_@@_alias_prop { latin10 } { iso885916 }
+\prop_gput:Nnn \g_@@_alias_prop { utf16le } { utf16 }
+\prop_gput:Nnn \g_@@_alias_prop { utf16be } { utf16 }
+\prop_gput:Nnn \g_@@_alias_prop { utf32le } { utf32 }
+\prop_gput:Nnn \g_@@_alias_prop { utf32be } { utf32 }
+\prop_gput:Nnn \g_@@_alias_prop { hexadecimal } { hex }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_error_bool}
+% In conversion functions with a built-in conditional, errors are not
+% reported directly to the user, but the information is collected in
+% this boolean, used at the end to decide on which branch of the
+% conditional to take.
+% \begin{macrocode}
+\bool_new:N \g_@@_error_bool
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{str_byte, str_error}
+% Conversions from one \meta{encoding}/\meta{escaping} pair to another
+% are done within \texttt{x}-expanding assignments. Errors are
+% signalled by raising the relevant flag.
+% \begin{macrocode}
+\flag_new:n { str_byte }
+\flag_new:n { str_error }
+% \end{macrocode}
+% \end{variable}
+%
+% \subsubsection{Escaping spaces}
+%
+% \begin{macro}[int]{\@@_gset_other:Nn}
+% \begin{macro}[aux,EXP]{\@@_gset_other_loop:w}
+% \begin{macro}[aux,EXP]{\@@_gset_other_end:w}
+% This function could be done by using \cs{@@_to_other:n} within
+% an \texttt{x}-expansion, but that would take a time quadratic in the
+% size of the string. Instead, we can \enquote{leave the result behind
+% us} in the input stream, to be captured into the expanding
+% assignment. This gives us a linear time.
+% \begin{macrocode}
+\group_begin:
+\char_set_lccode:nn { `\* } { `\ }
+\char_set_lccode:nn { `\A } { `\A }
+\tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_protected:Npn \@@_gset_other:Nn #1#2
+ {
+ \tl_gset:Nx #1
+ {
+ \exp_after:wN \@@_gset_other_loop:w \tl_to_str:n {#2} ~ %
+ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_stop
+ }
+ }
+ \cs_new:Npn \@@_gset_other_loop:w
+ #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 ~
+ {
+ \if_meaning:w A #9
+ \@@_gset_other_end:w
+ \fi:
+ #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * #9
+ \@@_gset_other_loop:w *
+ }
+ \cs_new:Npn \@@_gset_other_end:w \fi: #1 * A #2 \q_stop
+ { \fi: #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{String conditionals}
+%
+% \begin{macro}[EXP]{\@@_if_contains_char:NNT, \@@_if_contains_char:NNTF}
+% \begin{macro}[EXP]{\@@_if_contains_char:nNTF}
+% \begin{macro}[EXP,aux]{\@@_if_contains_char_aux:NN}
+% \begin{macro}[EXP,aux]{\@@_if_contains_char_true:}
+% \begin{syntax}
+% \cs{@@_if_contains_char:nNTF} \Arg{token list} \meta{char}
+% \end{syntax}
+% Expects the \meta{token list} to be an \meta{other string}: the
+% caller is responsible for ensuring that no (too-)special catcodes
+% remain. Spaces with catcode $10$ are ignored.
+% Loop over the characters of the string, comparing character codes.
+% The loop is broken if character codes match. Otherwise we return
+% \enquote{false}.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_contains_char:NN #1#2 { T , TF }
+ {
+ \exp_after:wN \@@_if_contains_char_aux:NN \exp_after:wN #2
+ #1 { \__prg_break:n { ? \fi: } }
+ \__prg_break_point:
+ \prg_return_false:
+ }
+\prg_new_conditional:Npnn \@@_if_contains_char:nN #1#2 { TF }
+ {
+ \@@_if_contains_char_aux:NN #2 #1 { \__prg_break:n { ? \fi: } }
+ \__prg_break_point:
+ \prg_return_false:
+ }
+\cs_new:Npn \@@_if_contains_char_aux:NN #1#2
+ {
+ \if_charcode:w #1 #2
+ \exp_after:wN \@@_if_contains_char_true:
+ \fi:
+ \@@_if_contains_char_aux:NN #1
+ }
+\cs_new_nopar:Npn \@@_if_contains_char_true:
+ { \__prg_break:n { \prg_return_true: \use_none:n } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux, rEXP]{\@@_octal_use:NTF}
+% \begin{syntax}
+% \cs{@@_octal_use:NTF} \meta{token} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% If the \meta{token} is an octal digit, it is left in the input
+% stream, \emph{followed} by the \meta{true code}. Otherwise, the
+% \meta{false code} is left in the input stream.
+% \begin{texnote}
+% This function will fail if the escape character is an octal
+% digit. We are thus careful to set the escape character to a known
+% value before using it.
+% \end{texnote}
+% \TeX{} dutifully detects octal digits for us: if |#1| is an octal
+% digit, then the right-hand side of the comparison is |'1#1|, greater
+% than $1$. Otherwise, the right-hand side stops as |'1|, and the
+% conditional takes the \texttt{false} branch.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_octal_use:N #1 { TF }
+ {
+ \if_int_compare:w \c_one < '1 \token_to_str:N #1 \exp_stop_f:
+ #1 \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux, rEXP]{\@@_hexadecimal_use:NTF}
+% \TeX{} detects uppercase hexadecimal digits for us (see
+% \cs{@@_octal_use:NTF}), but not the lowercase letters, which we
+% need to detect and replace by their uppercase counterpart.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_hexadecimal_use:N #1 { TF }
+ {
+ \if_int_compare:w \c_two < "1 \token_to_str:N #1 \exp_stop_f:
+ #1 \prg_return_true:
+ \else:
+ \if_case:w \__int_eval:w
+ \exp_after:wN ` \token_to_str:N #1 - `a
+ \__int_eval_end:
+ A
+ \or: B
+ \or: C
+ \or: D
+ \or: E
+ \or: F
+ \else:
+ \prg_return_false:
+ \exp_after:wN \use_none:n
+ \fi:
+ \prg_return_true:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Conversions}
+%
+% \subsubsection{Producing one byte or character}
+%
+% \begin{variable}{\c_@@_byte_0_tl, \c_@@_byte_1_tl, \c_@@_byte_255_tl}
+% \begin{variable}{\c_@@_byte_-1_tl}
+% For each integer $N$ in the range $[0,255]$, we create a constant
+% token list which holds three character tokens with category code
+% other: the character with character code $N$, followed by the
+% representation of $N$ as two hexadecimal digits. The value $-1$ is
+% given a default token list which ensures that later functions give
+% an empty result for the input $-1$.
+% \begin{macrocode}
+\group_begin:
+ \char_set_catcode_other:n { \c_zero }
+ \tl_set:Nx \l_@@_internal_tl { \tl_to_str:n { 0123456789ABCDEF } }
+ \exp_args:No \tl_map_inline:nn { \l_@@_internal_tl " }
+ { \char_set_lccode:nn {`#1} { \c_zero } }
+ \tl_map_inline:Nn \l_@@_internal_tl
+ {
+ \tl_map_inline:Nn \l_@@_internal_tl
+ {
+ \char_set_lccode:nn { \c_zero } {"#1##1}
+ \tl_to_lowercase:n
+ {
+ \tl_const:cx
+ { c_@@_byte_ \int_eval:n {"#1##1} _tl }
+ { ^^@ #1 ##1 }
+ }
+ }
+ }
+\group_end:
+\tl_const:cn { c_@@_byte_-1_tl } { { } \use_none:n { } }
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+%
+% \begin{macro}[int, EXP]{\@@_output_byte:n}
+% \begin{macro}[int, EXP]{\@@_output_byte:w}
+% \begin{macro}[int, EXP]{\@@_output_hexadecimal:n}
+% \begin{macro}[int, EXP]{\@@_output_hexadecimal:w}
+% \begin{macro}[int, EXP]{\@@_output_end:}
+% Those functions must be used carefully: feeding them a value outside
+% the range $[-1,255]$ will attempt to use the undefined token list
+% variable \cs{c_@@_byte_\meta{number}_tl}. Assuming that the
+% argument is in the right range, we expand the corresponding token
+% list, and pick either the byte (first token) or the hexadecimal
+% representations (second and third tokens). The value $-1$ produces
+% an empty result in both cases.
+% \begin{macrocode}
+\cs_new:Npn \@@_output_byte:n #1
+ { \@@_output_byte:w #1 \@@_output_end: }
+\cs_new_nopar:Npn \@@_output_byte:w
+ {
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \use_i:nnn
+ \cs:w c_@@_byte_ \int_use:N \__int_eval:w
+ }
+\cs_new:Npn \@@_output_hexadecimal:n #1
+ { \@@_output_hexadecimal:w #1 \@@_output_end: }
+\cs_new_nopar:Npn \@@_output_hexadecimal:w
+ {
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \use_none:n
+ \cs:w c_@@_byte_ \int_use:N \__int_eval:w
+ }
+\cs_new_nopar:Npn \@@_output_end:
+ { \__int_eval_end: _tl \cs_end: }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int, rEXP]{\@@_output_byte_pair_be:n}
+% \begin{macro}[int, rEXP]{\@@_output_byte_pair_le:n}
+% \begin{macro}[aux, rEXP]{\@@_output_byte_pair:nnN}
+% Convert a number in the range $[0,65535]$ to a pair of bytes, either
+% big-endian or little-endian.
+% \begin{macrocode}
+\cs_new:Npn \@@_output_byte_pair_be:n #1
+ {
+ \exp_args:Nf \@@_output_byte_pair:nnN
+ { \int_div_truncate:nn { #1 } { "100 } } {#1} \use:nn
+ }
+\cs_new:Npn \@@_output_byte_pair_le:n #1
+ {
+ \exp_args:Nf \@@_output_byte_pair:nnN
+ { \int_div_truncate:nn { #1 } { "100 } } {#1} \use_ii_i:nn
+ }
+\cs_new:Npn \@@_output_byte_pair:nnN #1#2#3
+ {
+ #3
+ { \@@_output_byte:n { #1 } }
+ { \@@_output_byte:n { #2 - #1 * "100 } }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Mapping functions for conversions}
+%
+% \begin{macro}{\@@_convert_gmap:N}
+% \begin{macro}[aux, rEXP]{\@@_convert_gmap_loop:NN}
+% This maps the function |#1| over all characters in
+% \cs{g_@@_result_tl}, which should be a byte string in most cases,
+% sometimes a native string.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_convert_gmap:N #1
+ {
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \exp_after:wN \@@_convert_gmap_loop:NN
+ \exp_after:wN #1
+ \g_@@_result_tl { ? \__prg_break: }
+ \__prg_break_point:
+ }
+ }
+\cs_new:Npn \@@_convert_gmap_loop:NN #1#2
+ {
+ \use_none:n #2
+ #1#2
+ \@@_convert_gmap_loop:NN #1
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_convert_gmap_internal:N}
+% \begin{macro}[aux, rEXP]{\@@_convert_gmap_internal_loop:Nw}
+% This maps the function |#1| over all character codes in
+% \cs{g_@@_result_tl}, which must be in the internal representation.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_convert_gmap_internal:N #1
+ {
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \exp_after:wN \@@_convert_gmap_internal_loop:Nww
+ \exp_after:wN #1
+ \g_@@_result_tl \s__tl \q_stop \__prg_break: \s__tl
+ \__prg_break_point:
+ }
+ }
+\cs_new:Npn \@@_convert_gmap_internal_loop:Nww #1 #2 \s__tl #3 \s__tl
+ {
+ \use_none_delimit_by_q_stop:w #3 \q_stop
+ #1 {#3}
+ \@@_convert_gmap_internal_loop:Nww #1
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Error-reporting during conversion}
+%
+% \begin{macro}[int]{\@@_if_flag_error:nnx}
+% \begin{macro}[aux]{\@@_if_flag_no_error:nnx}
+% When converting using the function \cs{str_set_convert:Nnnn}, errors
+% should be reported to the user after each step in the
+% conversion. Errors are signalled by raising some flag (typically
+% \texttt{@@_error}), so here we test that flag: if it is raised,
+% give the user an error, otherwise remove the arguments. On the other
+% hand, in the conditional functions \cs{str_set_convert:NnnnTF},
+% errors should be suppressed. This is done by changing
+% \cs{@@_if_flag_error:nnx} into \cs{@@_if_flag_no_error:nnx}
+% locally.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_if_flag_error:nnx #1
+ {
+ \flag_if_raised:nTF {#1}
+ { \__msg_kernel_error:nnx { str } }
+ { \use_none:nn }
+ }
+\cs_new_protected:Npn \@@_if_flag_no_error:nnx #1#2#3
+ { \flag_if_raised:nT {#1} { \bool_gset_true:N \g_@@_error_bool } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_if_flag_times:nT}
+% At the end of each conversion step, we raise all relevant errors as
+% one error message, built on the fly. The height of each flag
+% indicates how many times a given error was encountered. This
+% function prints |#2| followed by the number of occurrences of an
+% error if it occurred, nothing otherwise.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_if_flag_times:nT #1#2
+ { \flag_if_raised:nT {#1} { #2~(x \flag_height:n {#1} ) } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Framework for conversions}
+%
+% Most functions in this module expect to be working with
+% \enquote{native} strings. Strings can also be stored as bytes, in one
+% of many encodings, for instance \textsc{utf8}. The bytes themselves
+% can be expressed in various ways in terms of \TeX{} tokens, for
+% instance as pairs of hexadecimal digits. The questions of going from
+% arbitrary Unicode code points to bytes, and from bytes to tokens are
+% mostly independent.
+%
+% Conversions are done in four steps:
+% \begin{itemize}
+% \item \enquote{unescape} produces a string of bytes;
+% \item \enquote{decode} takes in a string of bytes, and converts it
+% to a list of Unicode characters in an internal representation,
+% with items of the form
+% \begin{quote}
+% \meta{bytes} \cs{s__tl} \meta{Unicode code point} \cs{s__tl}
+% \end{quote}
+% where we have collected the \meta{bytes} which combined to form
+% this particular Unicode character, and the \meta{Unicode code
+% point} is in the range $[0,\hexnum{10FFFF}]$.
+% \item \enquote{encode} encodes the internal list of code points as a
+% byte string in the new encoding;
+% \item \enquote{escape} escapes bytes as requested.
+% \end{itemize}
+% The process is modified in case one of the encoding is empty (or the
+% conversion function has been set equal to the empty encoding because
+% it was not found): then the unescape or escape step is ignored, and
+% the decode or encode steps work on tokens instead of bytes. Otherwise,
+% each step must ensure that it passes a correct byte string or internal
+% string to the next step.
+%
+% \begin{macro}{\str_set_convert:Nnnn, \str_gset_convert:Nnnn}
+% \begin{macro}[TF]{\str_set_convert:Nnnn, \str_gset_convert:Nnnn}
+% \begin{macro}[aux]{\@@_convert:nNNnnn}
+% The input string is stored in \cs{g_@@_result_tl}, then we:
+% unescape and decode; encode and escape; exit the group and store the
+% result in the user's variable. The various conversion functions all
+% act on \cs{g_@@_result_tl}. Errors are silenced for the conditional
+% functions by redefining \cs{@@_if_flag_error:nnx} locally.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \str_set_convert:Nnnn
+ { \@@_convert:nNNnnn { } \tl_set_eq:NN }
+\cs_new_protected_nopar:Npn \str_gset_convert:Nnnn
+ { \@@_convert:nNNnnn { } \tl_gset_eq:NN }
+\prg_new_protected_conditional:Npnn
+ \str_set_convert:Nnnn #1#2#3#4 { T , F , TF }
+ {
+ \bool_gset_false:N \g_@@_error_bool
+ \@@_convert:nNNnnn
+ { \cs_set_eq:NN \@@_if_flag_error:nnx \@@_if_flag_no_error:nnx }
+ \tl_set_eq:NN #1 {#2} {#3} {#4}
+ \bool_if:NTF \g_@@_error_bool \prg_return_false: \prg_return_true:
+ }
+\prg_new_protected_conditional:Npnn
+ \str_gset_convert:Nnnn #1#2#3#4 { T , F , TF }
+ {
+ \bool_gset_false:N \g_@@_error_bool
+ \@@_convert:nNNnnn
+ { \cs_set_eq:NN \@@_if_flag_error:nnx \@@_if_flag_no_error:nnx }
+ \tl_gset_eq:NN #1 {#2} {#3} {#4}
+ \bool_if:NTF \g_@@_error_bool \prg_return_false: \prg_return_true:
+ }
+\cs_new_protected:Npn \@@_convert:nNNnnn #1#2#3#4#5#6
+ {
+ \group_begin:
+ #1
+ \@@_gset_other:Nn \g_@@_result_tl {#4}
+ \exp_after:wN \@@_convert:wwwnn
+ \tl_to_str:n {#5} /// \q_stop
+ { decode } { unescape }
+ \prg_do_nothing:
+ \@@_convert_decode_:
+ \exp_after:wN \@@_convert:wwwnn
+ \tl_to_str:n {#6} /// \q_stop
+ { encode } { escape }
+ \use_ii_i:nn
+ \@@_convert_encode_:
+ \group_end:
+ #2 #3 \g_@@_result_tl
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_convert:wwwnn}
+% \begin{macro}[aux]{\@@_convert:NNnNN}
+% The task of \cs{@@_convert:wwwnn} is to split
+% \meta{encoding}/\meta{escaping} pairs into their components, |#1|
+% and |#2|. Calls to \cs{@@_convert:nnn} ensure that the
+% corresponding conversion functions are defined. The third auxiliary
+% does the main work.
+% \begin{itemize}
+% \item |#1| is the encoding conversion function;
+% \item |#2| is the escaping function;
+% \item |#3| is the escaping name for use in an error message;
+% \item |#4| is \cs{prg_do_nothing:} for unescaping/decoding, and
+% \cs{use_ii_i:nn} for encoding/escaping;
+% \item |#5| is the default encoding function (either
+% \enquote{decode} or \enquote{encode}), for which there should be
+% no escaping.
+% \end{itemize}
+% Let us ignore the native encoding for a second. In the
+% unescaping/decoding phase, we want to do |#2#1| in this order, and
+% in the encoding/escaping phase, the order should be reversed:
+% |#4#2#1| does exactly that. If one of the encodings is the default
+% (native), then the escaping should be ignored, with an error if any
+% was given, and only the encoding, |#1|, should be performed.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_convert:wwwnn
+ #1 / #2 // #3 \q_stop #4#5
+ {
+ \@@_convert:nnn {enc} {#4} {#1}
+ \@@_convert:nnn {esc} {#5} {#2}
+ \exp_args:Ncc \@@_convert:NNnNN
+ { @@_convert_#4_#1: } { @@_convert_#5_#2: } {#2}
+ }
+\cs_new_protected:Npn \@@_convert:NNnNN #1#2#3#4#5
+ {
+ \if_meaning:w #1 #5
+ \tl_if_empty:nF {#3}
+ { \__msg_kernel_error:nnx { str } { native-escaping } {#3} }
+ #1
+ \else:
+ #4 #2 #1
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_convert:nnn}
+% \begin{macro}[aux]{\@@_convert:nnnn}
+% The arguments of \cs{@@_convert:nnn} are: \texttt{enc} or
+% \texttt{esc}, used to build filenames, the type of the conversion
+% (unescape, decode, encode, escape), and the encoding or escaping
+% name. If the function is already defined, no need to do anything.
+% Otherwise, filter out all non-alphanumerics in the name, and
+% lowercase it. Feed that, and the same three arguments, to
+% \cs{@@_convert:nnnn}. The task is then to make sure that the
+% conversion function |#3_#1| corresponding to the type |#3| and
+% filtered name |#1| is defined, then set our initial conversion
+% function |#3_#4| equal to that.
+%
+% How do we get the |#3_#1| conversion to be defined if it isn't?
+% Two main cases.
+%
+% First, if |#1| is a key in \cs{g_@@_alias_prop}, then the value
+% \cs{l_@@_internal_tl} tells us what file to load. Loading is
+% skipped if the file was already read, \emph{i.e.}, if the conversion
+% command based on \cs{l_@@_internal_tl} already exists. Otherwise,
+% try to load the file; if that fails, there is an error, use the
+% default empty name instead.
+%
+% Second, |#1| may be absent from the property list. The
+% \cs{cs_if_exist:cF} test is automatically false, and we search for a
+% file defining the encoding or escaping |#1| (this should allow
+% third-party \texttt{.def} files). If the file is not found, there is
+% an error, use the default empty name instead.
+%
+% In all cases, the conversion based on \cs{l_@@_internal_tl} is
+% defined, so we can set the |#3_#1| function equal to that. In some
+% cases (\emph{e.g.}, \texttt{utf16be}), the |#3_#1| function is
+% actually defined within the file we just loaded, and it is different
+% from the \cs{l_@@_internal_tl}-based function: we mustn't clobber
+% that different definition.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_convert:nnn #1#2#3
+ {
+ \cs_if_exist:cF { @@_convert_#2_#3: }
+ {
+ \exp_args:Nx \@@_convert:nnnn
+ { \@@_convert_lowercase_alphanum:n {#3} }
+ {#1} {#2} {#3}
+ }
+ }
+\cs_new_protected:Npn \@@_convert:nnnn #1#2#3#4
+ {
+ \cs_if_exist:cF { @@_convert_#3_#1: }
+ {
+ \prop_get:NnNF \g_@@_alias_prop {#1} \l_@@_internal_tl
+ { \tl_set:Nn \l_@@_internal_tl {#1} }
+ \cs_if_exist:cF { @@_convert_#3_ \l_@@_internal_tl : }
+ {
+ \file_if_exist:nTF { l3str-#2- \l_@@_internal_tl .def }
+ {
+ \group_begin:
+ \@@_load_catcodes:
+ \file_input:n { l3str-#2- \l_@@_internal_tl .def }
+ \group_end:
+ }
+ {
+ \tl_clear:N \l_@@_internal_tl
+ \__msg_kernel_error:nnxx { str } { unknown-#2 } {#4} {#1}
+ }
+ }
+ \cs_if_exist:cF { @@_convert_#3_#1: }
+ {
+ \cs_gset_eq:cc { @@_convert_#3_#1: }
+ { @@_convert_#3_ \l_@@_internal_tl : }
+ }
+ }
+ \cs_gset_eq:cc { @@_convert_#3_#4: } { @@_convert_#3_#1: }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int, rEXP]{\@@_convert_lowercase_alphanum:n}
+% \begin{macro}[aux, rEXP]{\@@_convert_lowercase_alphanum_loop:N}
+% This function keeps only letters and digits, with upper case letters
+% converted to lower case.
+% \begin{macrocode}
+\cs_new:Npn \@@_convert_lowercase_alphanum:n #1
+ {
+ \exp_after:wN \@@_convert_lowercase_alphanum_loop:N
+ \tl_to_str:n {#1} { ? \__prg_break: }
+ \__prg_break_point:
+ }
+\cs_new:Npn \@@_convert_lowercase_alphanum_loop:N #1
+ {
+ \use_none:n #1
+ \if_int_compare:w `#1 < \c_ninety_one
+ \if_int_compare:w `#1 < \c_sixty_five
+ \if_int_compare:w \c_one < 1#1 \exp_stop_f:
+ #1
+ \fi:
+ \else:
+ \@@_output_byte:n { `#1 + \c_thirty_two }
+ \fi:
+ \else:
+ \if_int_compare:w `#1 < \c_one_hundred_twenty_three
+ \if_int_compare:w `#1 < \c_ninety_seven
+ \else:
+ #1
+ \fi:
+ \fi:
+ \fi:
+ \@@_convert_lowercase_alphanum_loop:N
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_load_catcodes:}
+% Since encoding files may be loaded at arbitrary places in a \TeX{}
+% document, including within verbatim mode, we set the catcodes of all
+% characters appearing in any encoding definition file.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_load_catcodes:
+ {
+ \char_set_catcode_escape:N \\
+ \char_set_catcode_group_begin:N \{
+ \char_set_catcode_group_end:N \}
+ \char_set_catcode_math_toggle:N \$
+ \char_set_catcode_alignment:N \&
+ \char_set_catcode_parameter:N \#
+ \char_set_catcode_math_superscript:N \^
+ \char_set_catcode_ignore:N \ %
+ \char_set_catcode_space:N \~
+ \tl_map_function:nN { abcdefghijklmnopqrstuvwxyz_:ABCDEFILNPSTUX }
+ \char_set_catcode_letter:N
+ \tl_map_function:nN { 0123456789"'?*+-.(),`!/<>[];= }
+ \char_set_catcode_other:N
+ \char_set_catcode_comment:N \%
+ \int_set:Nn \tex_endlinechar:D {32}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Byte unescape and escape}
+%
+% Strings of bytes may need to be stored in auxiliary files in safe
+% \enquote{escaping} formats. Each such escaping is only loaded as
+% needed. By default, on input any non-byte is filtered out, while the
+% output simply consists in letting bytes through.
+%
+% \begin{macro}[int, rEXP]{\@@_filter_bytes:n}
+% \begin{macro}[aux, rEXP]{\@@_filter_bytes_aux:N}
+% In the case of pdf\TeX{}, every character is a byte. For
+% Unicode-aware engines, test the character code; non-bytes cause us
+% to raise the flag \texttt{str_byte}. Spaces have already been given
+% the correct category code when this function is called.
+% \begin{macrocode}
+\pdftex_if_engine:TF
+ { \cs_new_eq:NN \@@_filter_bytes:n \use:n }
+ {
+ \cs_new:Npn \@@_filter_bytes:n #1
+ {
+ \@@_filter_bytes_aux:N #1
+ { ? \__prg_break: }
+ \__prg_break_point:
+ }
+ \cs_new:Npn \@@_filter_bytes_aux:N #1
+ {
+ \use_none:n #1
+ \if_int_compare:w `#1 < 256 \exp_stop_f:
+ #1
+ \else:
+ \flag_raise:n { str_byte }
+ \fi:
+ \@@_filter_bytes_aux:N
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_unescape_:}
+% \begin{macro}[int]{\@@_convert_unescape_bytes:}
+% The simplest unescaping method removes non-bytes from
+% \cs{g_@@_result_tl}.
+% \begin{macrocode}
+\pdftex_if_engine:TF
+ { \cs_new_protected_nopar:Npn \@@_convert_unescape_: { } }
+ {
+ \cs_new_protected_nopar:Npn \@@_convert_unescape_:
+ {
+ \flag_clear:n { str_byte }
+ \tl_gset:Nx \g_@@_result_tl
+ { \exp_args:No \@@_filter_bytes:n \g_@@_result_tl }
+ \@@_if_flag_error:nnx { str_byte } { non-byte } { bytes }
+ }
+ }
+\cs_new_eq:NN \@@_convert_unescape_bytes: \@@_convert_unescape_:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_escape_:}
+% \begin{macro}[int]{\@@_convert_escape_bytes:}
+% The simplest form of escape leaves the bytes from the previous step
+% of the conversion unchanged.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_convert_escape_: { }
+\cs_new_eq:NN \@@_convert_escape_bytes: \@@_convert_escape_:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Native strings}
+%
+% \begin{macro}[int]{\@@_convert_decode_:}
+% \begin{macro}[aux, rEXP]{\@@_decode_native_char:N}
+% Convert each character to its character code, one at a time.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \@@_convert_decode_:
+ { \@@_convert_gmap:N \@@_decode_native_char:N }
+\cs_new:Npn \@@_decode_native_char:N #1
+ { #1 \s__tl \__int_value:w `#1 \s__tl }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_encode_:}
+% The conversion from an internal string to native character tokens is
+% very different in pdf\TeX{} and in other engines. For Unicode-aware
+% engines, we need the definitions to be read when the null byte has
+% category code $12$, so we set that inside a group.
+% \begin{macrocode}
+\group_begin:
+ \char_set_catcode_other:n { 0 }
+ \pdftex_if_engine:TF
+% \end{macrocode}
+% \begin{macro}[aux, EXP]{\@@_encode_native_char:n}
+% Since pdf\TeX{} only supports 8-bit characters, and we have a table
+% of all bytes, the conversion can be done in linear time within an
+% \texttt{x}-expanding assignment. Look out for character codes larger
+% than $255$, those characters are replaced by |?|, and raise a flag,
+% which then triggers a pdf\TeX{}-specific error.
+% \begin{macrocode}
+ {
+ \cs_new_protected_nopar:Npn \@@_convert_encode_:
+ {
+ \flag_clear:n { str_error }
+ \@@_convert_gmap_internal:N \@@_encode_native_char:n
+ \@@_if_flag_error:nnx { str_error }
+ { pdfTeX-native-overflow } { }
+ }
+ \cs_new:Npn \@@_encode_native_char:n #1
+ {
+ \if_int_compare:w #1 < \c_two_hundred_fifty_six
+ \@@_output_byte:n {#1}
+ \else:
+ \flag_raise:n { str_error }
+ ?
+ \fi:
+ }
+ \__msg_kernel_new:nnnn { str } { pdfTeX-native-overflow }
+ { Character~code~too~large~for~pdfTeX. }
+ {
+ The~pdfTeX~engine~only~supports~8-bit~characters:~
+ valid~character~codes~are~in~the~range~[0,255].~
+ To~manipulate~arbitrary~Unicode,~use~LuaTeX~or~XeTeX.
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[aux]{\@@_encode_native_loop:w}
+% \begin{macro}[aux]{\@@_encode_native_flush:}
+% \begin{macro}[aux, rEXP]{\@@_encode_native_filter:N}
+% In Unicode-aware engines, since building particular characters
+% cannot be done expandably in \TeX{}, we cannot hope to get a
+% linear-time function. However, we get quite close using the
+% \pkg{l3tl-build} module, which abuses \tn{toks} to reach an almost
+% linear time. Use the standard lowercase trick to produce an
+% arbitrary character from the null character, and add that character
+% to the end of the token list being built. At the end of the loop,
+% put the token list together with \cs{__tl_build_end:}. Note that we
+% use an \texttt{x}-expanding assignment because it is slightly
+% faster. Unicode-aware engines will never incur an overflow because
+% the internal string is guaranteed to only contain code points in
+% $[0,\hexnum{10FFFF}]$.
+% \begin{macrocode}
+ {
+ \cs_new_protected_nopar:Npn \@@_convert_encode_:
+ {
+ \int_zero:N \l__tl_build_offset_int
+ \__tl_gbuild_x:Nw \g_@@_result_tl
+ \exp_after:wN \@@_encode_native_loop:w
+ \g_@@_result_tl \s__tl { \q_stop \__prg_break: } \s__tl
+ \__prg_break_point:
+ \__tl_build_end:
+ }
+ \cs_new_protected:Npn \@@_encode_native_loop:w #1 \s__tl #2 \s__tl
+ {
+ \use_none_delimit_by_q_stop:w #2 \q_stop
+ \tex_lccode:D \l_@@_internal_int \__int_eval:w #2 \__int_eval_end:
+ \tl_to_lowercase:n { \__tl_build_one:n { ^^@ } }
+ \@@_encode_native_loop:w
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% End the group to restore the catcode of the null byte.
+% \begin{macrocode}
+\group_end:
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{8-bit encodings}
+%
+% This section will be entirely rewritten: it is not yet clear in what
+% situations 8-bit encodings are used, hence I don't know what exactly
+% should be optimized. The current approach is reasonably efficient to
+% convert long strings, and it scales well when using many different
+% encodings. An approach based on csnames would have a smaller constant
+% load time for each individual conversion, but has a large hash table
+% cost. Using a range of \tn{count} registers works for decoding, but
+% not for encoding: one possibility there would be to use a binary tree
+% for the mapping of Unicode characters to bytes, stored as a box, one
+% per encoding.
+%
+% Since the section is going to be rewritten, documentation lacks.
+%
+% All the 8-bit encodings which \pkg{l3str} supports rely on the same
+% internal functions.
+%
+% \begin{macro}[int]{\@@_declare_eight_bit_encoding:nnn}
+% \begin{syntax}
+% \cs{@@_declare_eight_bit_encoding:nnn} \Arg{name} \Arg{mapping} \Arg{missing}
+% \end{syntax}
+% This declares the encoding \meta{name} to map bytes to Unicode
+% characters according to the \meta{mapping}, and map those bytes
+% which are not mentionned in the \meta{mapping} either to the
+% replacement character (if they appear in \meta{missing}), or to
+% themselves.
+%
+% All the 8-bit encoding definition file start with
+% \cs{@@_declare_eight_bit_encoding:nnn} \Arg{encoding name}
+% \Arg{mapping} \Arg{missing bytes}. The \meta{mapping} argument is a
+% token list of pairs \Arg{byte} \Arg{Unicode} expressed in uppercase
+% hexadecimal notation. The \meta{missing} argument is a token list
+% of \Arg{byte}. Every \meta{byte} which does not appear in the
+% \meta{mapping} nor the \meta{missing} lists maps to the same code
+% point in Unicode.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare_eight_bit_encoding:nnn #1#2#3
+ {
+ \tl_set:Nn \l_@@_internal_tl {#1}
+ \cs_new_protected_nopar:cpn { @@_convert_decode_#1: }
+ { \@@_convert_decode_eight_bit:n {#1} }
+ \cs_new_protected_nopar:cpn { @@_convert_encode_#1: }
+ { \@@_convert_encode_eight_bit:n {#1} }
+ \tl_const:cn { c_@@_encoding_#1_tl } {#2}
+ \tl_const:cn { c_@@_encoding_#1_missing_tl } {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_decode_eight_bit:n}
+% \begin{macro}[aux]{\@@_decode_eight_bit_load:nn}
+% \begin{macro}[aux]{\@@_decode_eight_bit_load_missing:n}
+% \begin{macro}[aux, EXP]{\@@_decode_eight_bit_char:N}
+%^^A todo: document
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_convert_decode_eight_bit:n #1
+ {
+ \group_begin:
+ \int_zero:N \l_@@_internal_int
+ \exp_last_unbraced:Nx \@@_decode_eight_bit_load:nn
+ { \tl_use:c { c_@@_encoding_#1_tl } }
+ { \q_stop \__prg_break: } { }
+ \__prg_break_point:
+ \exp_last_unbraced:Nx \@@_decode_eight_bit_load_missing:n
+ { \tl_use:c { c_@@_encoding_#1_missing_tl } }
+ { \q_stop \__prg_break: }
+ \__prg_break_point:
+ \flag_clear:n { str_error }
+ \@@_convert_gmap:N \@@_decode_eight_bit_char:N
+ \@@_if_flag_error:nnx { str_error } { decode-8-bit } {#1}
+ \group_end:
+ }
+\cs_new_protected:Npn \@@_decode_eight_bit_load:nn #1#2
+ {
+ \use_none_delimit_by_q_stop:w #1 \q_stop
+ \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop:
+ \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop:
+ \tex_toks:D \l_@@_internal_int \exp_after:wN { \__int_value:w "#2 }
+ \tex_advance:D \l_@@_internal_int \c_one
+ \@@_decode_eight_bit_load:nn
+ }
+\cs_new_protected:Npn \@@_decode_eight_bit_load_missing:n #1
+ {
+ \use_none_delimit_by_q_stop:w #1 \q_stop
+ \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop:
+ \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop:
+ \tex_toks:D \l_@@_internal_int \exp_after:wN
+ { \int_use:N \c_@@_replacement_char_int }
+ \tex_advance:D \l_@@_internal_int \c_one
+ \@@_decode_eight_bit_load_missing:n
+ }
+\cs_new:Npn \@@_decode_eight_bit_char:N #1
+ {
+ #1 \s__tl
+ \if_int_compare:w \tex_dimen:D `#1 < \l_@@_internal_int
+ \if_int_compare:w \tex_skip:D \tex_dimen:D `#1 = `#1 \exp_stop_f:
+ \tex_the:D \tex_toks:D \tex_dimen:D
+ \fi:
+ \fi:
+ \__int_value:w `#1 \s__tl
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_encode_eight_bit:n}
+% \begin{macro}[aux]{\@@_encode_eight_bit_load:nn}
+% \begin{macro}[aux, rEXP]{\@@_encode_eight_bit_char:n}
+% \begin{macro}[aux, rEXP]{\@@_encode_eight_bit_char_aux:n}
+%^^A todo: document
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_convert_encode_eight_bit:n #1
+ {
+ \group_begin:
+ \int_zero:N \l_@@_internal_int
+ \exp_last_unbraced:Nx \@@_encode_eight_bit_load:nn
+ { \tl_use:c { c_@@_encoding_#1_tl } }
+ { \q_stop \__prg_break: } { }
+ \__prg_break_point:
+ \flag_clear:n { str_error }
+ \@@_convert_gmap_internal:N \@@_encode_eight_bit_char:n
+ \@@_if_flag_error:nnx { str_error } { encode-8-bit } {#1}
+ \group_end:
+ }
+\cs_new_protected:Npn \@@_encode_eight_bit_load:nn #1#2
+ {
+ \use_none_delimit_by_q_stop:w #1 \q_stop
+ \tex_dimen:D "#2 = \l_@@_internal_int sp \scan_stop:
+ \tex_skip:D \l_@@_internal_int = "#2 sp \scan_stop:
+ \exp_args:NNf \tex_toks:D \l_@@_internal_int
+ { \@@_output_byte:n { "#1 } }
+ \tex_advance:D \l_@@_internal_int \c_one
+ \@@_encode_eight_bit_load:nn
+ }
+\cs_new:Npn \@@_encode_eight_bit_char:n #1
+ {
+ \if_int_compare:w #1 > \c_max_register_int
+ \flag_raise:n { str_error }
+ \else:
+ \if_int_compare:w \tex_dimen:D #1 < \l_@@_internal_int
+ \if_int_compare:w \tex_skip:D \tex_dimen:D #1 = #1 \exp_stop_f:
+ \tex_the:D \tex_toks:D \tex_dimen:D #1 \exp_stop_f:
+ \exp_after:wN \exp_after:wN \exp_after:wN \use_none:nn
+ \fi:
+ \fi:
+ \@@_encode_eight_bit_char_aux:n {#1}
+ \fi:
+ }
+\cs_new:Npn \@@_encode_eight_bit_char_aux:n #1
+ {
+ \if_int_compare:w #1 < \c_two_hundred_fifty_six
+ \@@_output_byte:n {#1}
+ \else:
+ \flag_raise:n { str_error }
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Messages}
+%
+% General messages, and messages for the encodings and escapings loaded
+% by default (\enquote{native}, and \enquote{bytes}).
+% \begin{macrocode}
+\__msg_kernel_new:nnn { str } { unknown-esc }
+ { Escaping~scheme~'#1'~(filtered:~'#2')~unknown. }
+\__msg_kernel_new:nnn { str } { unknown-enc }
+ { Encoding~scheme~'#1'~(filtered:~'#2')~unknown. }
+\__msg_kernel_new:nnnn { str } { native-escaping }
+ { The~'native'~encoding~scheme~does~not~support~any~escaping. }
+ {
+ Since~native~strings~do~not~consist~in~bytes,~
+ none~of~the~escaping~methods~make~sense.~
+ The~specified~escaping,~'#1',~will be ignored.
+ }
+\__msg_kernel_new:nnn { str } { file-not-found }
+ { File~'l3str-#1.def'~not~found. }
+% \end{macrocode}
+%
+% Message used when the \enquote{bytes} unescaping fails because the
+% string given to \cs{str_set_convert:Nnnn} contains a non-byte. This
+% cannot happen for the pdf\TeX{} engine, since that engine only
+% supports 8-bit characters. Messages used for other escapings and
+% encodings are defined in each definition file.
+% \begin{macrocode}
+\pdftex_if_engine:F
+ {
+ \__msg_kernel_new:nnnn { str } { non-byte }
+ { String~invalid~in~escaping~'#1':~it~may~only~contain~bytes. }
+ {
+ Some~characters~in~the~string~you~asked~to~convert~are~not~
+ 8-bit~characters.~Perhaps~the~string~is~a~'native'~Unicode~string?~
+ If~it~is,~try~using\\
+ \\
+ \iow_indent:n
+ {
+ \iow_char:N\\str_set_convert:Nnnn \\
+ \ \ <str~var>~\{~<string>~\}~\{~native~\}~\{~<target~encoding>~\}
+ }
+ }
+ }
+% \end{macrocode}
+%
+% Those messages are used when converting to and from 8-bit encodings.
+% \begin{macrocode}
+\__msg_kernel_new:nnnn { str } { decode-8-bit }
+ { Invalid~string~in~encoding~'#1'. }
+ {
+ LaTeX~came~across~a~byte~which~is~not~defined~to~represent~
+ any~character~in~the~encoding~'#1'.
+ }
+\__msg_kernel_new:nnnn { str } { encode-8-bit }
+ { Unicode~string~cannot~be~converted~to~encoding~'#1'. }
+ {
+ The~encoding~'#1'~only~contains~a~subset~of~all~Unicode~characters.~
+ LaTeX~was~asked~to~convert~a~string~to~that~encoding,~but~that~
+ string~contains~a~character~that~'#1'~does~not~support.
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \subsection{Escaping definition files}
+%
+% Several of those encodings are defined by the pdf file format. The
+% following byte storage methods are defined:
+% \begin{itemize}
+% \item \texttt{bytes} (default), non-bytes are filtered out, and
+% bytes are left untouched (this is defined by default);
+% \item \texttt{hex} or \texttt{hexadecimal}, as per the pdf\TeX{}
+% primitive \tn{pdfescapehex}
+% \item \texttt{name}, as per the pdf\TeX{} primitive
+% \tn{pdfescapename}
+% \item \texttt{string}, as per the pdf\TeX{} primitive
+% \tn{pdfescapestring}
+% \item \texttt{url}, as per the percent encoding of urls.
+% \end{itemize}
+%
+% \subsubsection{Unescape methods}
+%
+% \begin{macro}[int]{\@@_convert_unescape_hex:}
+% \begin{macro}[aux, rEXP]{\@@_unescape_hex_auxi:N}
+% \begin{macro}[aux, rEXP]{\@@_unescape_hex_auxii:N}
+% Take chars two by two, and interpret each pair as the hexadecimal
+% code for a byte. Anything else than hexadecimal digits is ignored,
+% raising the flag. A string which contains an odd number of
+% hexadecimal digits gets |0| appended to it: this is equivalent to
+% appending a |0| in all cases, and dropping it if it is alone.
+% \begin{macrocode}
+%<*hex>
+\cs_new_protected_nopar:Npn \@@_convert_unescape_hex:
+ {
+ \group_begin:
+ \flag_clear:n { str_error }
+ \int_set:Nn \tex_escapechar:D { 92 }
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \@@_output_byte:w "
+ \exp_last_unbraced:Nf \@@_unescape_hex_auxi:N
+ { \tl_to_str:N \g_@@_result_tl }
+ 0 { ? 0 - \c_one \__prg_break: }
+ \__prg_break_point:
+ \@@_output_end:
+ }
+ \@@_if_flag_error:nnx { str_error } { unescape-hex } { }
+ \group_end:
+ }
+\cs_new:Npn \@@_unescape_hex_auxi:N #1
+ {
+ \use_none:n #1
+ \@@_hexadecimal_use:NTF #1
+ { \@@_unescape_hex_auxii:N }
+ {
+ \flag_raise:n { str_error }
+ \@@_unescape_hex_auxi:N
+ }
+ }
+\cs_new:Npn \@@_unescape_hex_auxii:N #1
+ {
+ \use_none:n #1
+ \@@_hexadecimal_use:NTF #1
+ {
+ \@@_output_end:
+ \@@_output_byte:w " \@@_unescape_hex_auxi:N
+ }
+ {
+ \flag_raise:n { str_error }
+ \@@_unescape_hex_auxii:N
+ }
+ }
+\__msg_kernel_new:nnnn { str } { unescape-hex }
+ { String~invalid~in~escaping~'hex':~only~hexadecimal~digits~allowed. }
+ {
+ Some~characters~in~the~string~you~asked~to~convert~are~not~
+ hexadecimal~digits~(0-9,~A-F,~a-f)~nor~spaces.
+ }
+%</hex>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_unescape_name:}
+% \begin{macro}[aux, rEXP]{\@@_unescape_name_loop:wNN}
+% \begin{macro}[int]{\@@_convert_unescape_url:}
+% \begin{macro}[aux, rEXP]{\@@_unescape_url_loop:wNN}
+% The \cs{@@_convert_unescape_name:} function replaces each
+% occurrence of |#| followed by two hexadecimal digits in
+% \cs{g_@@_result_tl} by the corresponding byte. The \texttt{url}
+% function is identical, with escape character |%| instead of |#|.
+% Thus we define the two together. The arguments of \cs{@@_tmp:w} are
+% the character code of |#| or |%| in hexadecimal, the name of the
+% main function to define, and the name of the auxiliary which
+% performs the loop.
+%
+% The looping auxiliary |#3| finds the next escape character, reads
+% the following two characters, and tests them. The test
+% \cs{@@_hexadecimal_use:NTF} leaves the upper-case digit in the
+% input stream, hence we surround the test with
+% \cs{@@_output_byte:w}~|"| and \cs{@@_output_end:}. If both
+% characters are hexadecimal digits, they should be removed before
+% looping: this is done by \cs{use_i:nnn}. If one of the characters
+% is not a hexadecimal digit, then feed |"#1| to
+% \cs{@@_output_byte:w} to produce the escape character, raise the
+% flag, and call the looping function followed by the two characters
+% (remove \cs{use_i:nnn}).
+% \begin{macrocode}
+%<*name|url>
+\cs_set_protected:Npn \@@_tmp:w #1#2#3
+ {
+ \cs_new_protected:cpn { @@_convert_unescape_#2: }
+ {
+ \group_begin:
+ \flag_clear:n { str_byte }
+ \flag_clear:n { str_error }
+ \int_set:Nn \tex_escapechar:D { 92 }
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \exp_after:wN #3 \g_@@_result_tl
+ #1 ? { ? \__prg_break: }
+ \__prg_break_point:
+ }
+ \@@_if_flag_error:nnx { str_byte } { non-byte } { #2 }
+ \@@_if_flag_error:nnx { str_error } { unescape-#2 } { }
+ \group_end:
+ }
+ \cs_new:Npn #3 ##1#1##2##3
+ {
+ \@@_filter_bytes:n {##1}
+ \use_none:n ##3
+ \@@_output_byte:w "
+ \@@_hexadecimal_use:NTF ##2
+ {
+ \@@_hexadecimal_use:NTF ##3
+ { }
+ {
+ \flag_raise:n { str_error }
+ * \c_zero + `#1 \use_i:nn
+ }
+ }
+ {
+ \flag_raise:n { str_error }
+ 0 + `#1 \use_i:nn
+ }
+ \@@_output_end:
+ \use_i:nnn #3 ##2##3
+ }
+ \__msg_kernel_new:nnnn { str } { unescape-#2 }
+ { String~invalid~in~escaping~'#2'. }
+ {
+ LaTeX~came~across~the~escape~character~'#1'~not~followed~by~
+ two~hexadecimal~digits.~This~is~invalid~in~the~escaping~'#2'.
+ }
+ }
+%</name|url>
+%<*name>
+\exp_after:wN \@@_tmp:w \c_hash_str { name }
+ \@@_unescape_name_loop:wNN
+%</name>
+%<*url>
+\exp_after:wN \@@_tmp:w \c_percent_str { url }
+ \@@_unescape_url_loop:wNN
+%</url>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_unescape_string:}
+% \begin{macro}[aux, rEXP]{\@@_unescape_string_newlines:wN}
+% \begin{macro}[aux, rEXP]{\@@_unescape_string_loop:wNNN}
+% \begin{macro}[aux, rEXP]{\@@_unescape_string_repeat:NNNNNN}
+% The \texttt{string} escaping is somewhat similar to the
+% \texttt{name} and \texttt{url} escapings, with escape character |\|.
+% The first step is to convert all three line endings, |^^J|, |^^M|,
+% and |^^M^^J| to the common |^^J|, as per the \textsc{pdf}
+% specification. This step cannot raise the flag.
+%
+% Then the following escape sequences are decoded.
+% \begin{itemize}\def\makelabel#1{\hss\llap{\ttfamily\string#1}}
+% \item[\n] Line feed ($10$)
+% \item[\r] Carriage return ($13$)
+% \item[\t] Horizontal tab ($9$)
+% \item[\b] Backspace ($8$)
+% \item[\f] Form feed ($12$)
+% \item[\(] Left parenthesis
+% \item[\)] Right parenthesis
+% \item[\\] Backslash
+% \item[\ddd] (backslash followed by $1$ to $3$ octal digits) Byte
+% \texttt{ddd} (octal), subtracting $256$ in case of overflow.
+% \end{itemize}
+% If followed by an end-of-line character, the backslash and the
+% end-of-line are ignored. If followed by anything else, the backslash
+% is ignored, raising the error flag.
+%^^A Be paranoid: \tl_to_lowercase:n is unsafe.
+% \begin{macrocode}
+%<*string>
+\group_begin:
+ \char_set_lccode:nn {`\*} {`\\}
+ \char_set_catcode_other:N \^^J
+ \char_set_catcode_other:N \^^M
+ \tl_to_lowercase:n
+ {
+ \cs_new_protected_nopar:Npn \@@_convert_unescape_string:
+ {
+ \group_begin:
+ \flag_clear:n { str_byte }
+ \flag_clear:n { str_error }
+ \int_set:Nn \tex_escapechar:D { 92 }
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \exp_after:wN \@@_unescape_string_newlines:wN
+ \g_@@_result_tl \__prg_break: ^^M ?
+ \__prg_break_point:
+ }
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \exp_after:wN \@@_unescape_string_loop:wNNN
+ \g_@@_result_tl * ?? { ? \__prg_break: }
+ \__prg_break_point:
+ }
+ \@@_if_flag_error:nnx { str_byte } { non-byte } { string }
+ \@@_if_flag_error:nnx { str_error } { unescape-string } { }
+ \group_end:
+ }
+ \cs_new:Npn \@@_unescape_string_loop:wNNN #1 *#2#3#4
+ }
+ {
+ \@@_filter_bytes:n {#1}
+ \use_none:n #4
+ \@@_output_byte:w '
+ \@@_octal_use:NTF #2
+ {
+ \@@_octal_use:NTF #3
+ {
+ \@@_octal_use:NTF #4
+ {
+ \if_int_compare:w #2 > \c_three
+ - 256
+ \fi:
+ \@@_unescape_string_repeat:NNNNNN
+ }
+ { \@@_unescape_string_repeat:NNNNNN ? }
+ }
+ { \@@_unescape_string_repeat:NNNNNN ?? }
+ }
+ {
+ \str_case_x:nnn {#2}
+ {
+ { \c_backslash_str } { 134 }
+ { ( } { 50 }
+ { ) } { 51 }
+ { r } { 15 }
+ { f } { 14 }
+ { n } { 12 }
+ { t } { 11 }
+ { b } { 10 }
+ { ^^J } { 0 - \c_one }
+ }
+ {
+ \flag_raise:n { str_error }
+ 0 - \c_one \use_i:nn
+ }
+ }
+ \@@_output_end:
+ \use_i:nn \@@_unescape_string_loop:wNNN #2#3#4
+ }
+ \cs_new:Npn \@@_unescape_string_repeat:NNNNNN #1#2#3#4#5#6
+ { \@@_output_end: \@@_unescape_string_loop:wNNN }
+ \cs_new:Npn \@@_unescape_string_newlines:wN #1 ^^M #2
+ {
+ #1
+ \if_charcode:w ^^J #2 \else: ^^J \fi:
+ \@@_unescape_string_newlines:wN #2
+ }
+ \__msg_kernel_new:nnnn { str } { unescape-string }
+ { String~invalid~in~escaping~'string'. }
+ {
+ LaTeX~came~across~an~escape~character~'\c_backslash_str'~
+ not~followed~by~any~of:~'n',~'r',~'t',~'b',~'f',~'(',~')',~
+ '\c_backslash_str',~one~to~three~octal~digits,~or~the~end~
+ of~a~line.
+ }
+\group_end:
+%</string>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Escape methods}
+%
+% Currently, none of the escape methods can lead to errors, assuming
+% that their input is made out of bytes.
+%
+% \begin{macro}[int]{\@@_convert_escape_hex:}
+% \begin{macro}[aux, rEXP]{\@@_escape_hex_char:N}
+% Loop and convert each byte to hexadecimal.
+% \begin{macrocode}
+%<*hex>
+\cs_new_protected_nopar:Npn \@@_convert_escape_hex:
+ { \@@_convert_gmap:N \@@_escape_hex_char:N }
+\cs_new:Npn \@@_escape_hex_char:N #1
+ { \@@_output_hexadecimal:n { `#1 } }
+%</hex>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_escape_name:}
+% \begin{macro}[aux, rEXP]{\@@_escape_name_char:N}
+% \begin{macro}[aux, rEXP]{\@@_if_escape_name:NTF}
+% \begin{variable}{\c_@@_escape_name_str}
+% \begin{variable}{\c_@@_escape_name_not_str}
+% For each byte, test whether it should be output as is, or be
+% \enquote{hash-encoded}. Roughly, bytes outside the range
+% $[\hexnum{2A},\hexnum{7E}]$ are hash-encoded. We keep two lists of
+% exceptions: characters in \cs{c_@@_escape_name_not_str} are not
+% hash-encoded, and characters in the \cs{c_@@_escape_name_str} are
+% encoded.
+% \begin{macrocode}
+%<*name>
+\str_const:Nn \c_@@_escape_name_not_str { ! " $ & ' } %$
+\str_const:Nn \c_@@_escape_name_str { {}/<>[] }
+\cs_new_protected_nopar:Npn \@@_convert_escape_name:
+ { \@@_convert_gmap:N \@@_escape_name_char:N }
+\cs_new:Npn \@@_escape_name_char:N #1
+ {
+ \@@_if_escape_name:NTF #1 {#1}
+ { \c_hash_str \@@_output_hexadecimal:n {`#1} }
+ }
+\prg_new_conditional:Npnn \@@_if_escape_name:N #1 { TF }
+ {
+ \if_int_compare:w `#1 < "2A \exp_stop_f:
+ \@@_if_contains_char:NNTF \c_@@_escape_name_not_str #1
+ \prg_return_true: \prg_return_false:
+ \else:
+ \if_int_compare:w `#1 > "7E \exp_stop_f:
+ \prg_return_false:
+ \else:
+ \@@_if_contains_char:NNTF \c_@@_escape_name_str #1
+ \prg_return_false: \prg_return_true:
+ \fi:
+ \fi:
+ }
+%</name>
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_escape_string:}
+% \begin{macro}[aux, rEXP]{\@@_escape_string_char:N}
+% \begin{macro}[aux, rEXP]{\@@_if_escape_string:NTF}
+% \begin{variable}{\c_@@_escape_string_str}
+% Any character below (and including) space, and any character above
+% (and including) \texttt{del}, are converted to octal. One backslash
+% is added before each parenthesis and backslash.
+% \begin{macrocode}
+%<*string>
+\str_const:Nx \c_@@_escape_string_str
+ { \c_backslash_str ( ) }
+\cs_new_protected_nopar:Npn \@@_convert_escape_string:
+ { \@@_convert_gmap:N \@@_escape_string_char:N }
+\cs_new:Npn \@@_escape_string_char:N #1
+ {
+ \@@_if_escape_string:NTF #1
+ {
+ \@@_if_contains_char:NNT
+ \c_@@_escape_string_str #1
+ { \c_backslash_str }
+ #1
+ }
+ {
+ \c_backslash_str
+ \int_div_truncate:nn {`#1} {64}
+ \int_mod:nn { \int_div_truncate:nn {`#1} \c_eight } \c_eight
+ \int_mod:nn {`#1} \c_eight
+ }
+ }
+\prg_new_conditional:Npnn \@@_if_escape_string:N #1 { TF }
+ {
+ \if_int_compare:w `#1 < "21 \exp_stop_f:
+ \prg_return_false:
+ \else:
+ \if_int_compare:w `#1 > "7E \exp_stop_f:
+ \prg_return_false:
+ \else:
+ \prg_return_true:
+ \fi:
+ \fi:
+ }
+%</string>
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_convert_escape_url:}
+% \begin{macro}[aux, rEXP]{\@@_escape_url_char:N}
+% \begin{macro}[aux, rEXP]{\@@_if_escape_url:NTF}
+% This function is similar to \cs{@@_convert_escape_name:}, escaping
+% different characters.
+% \begin{macrocode}
+%<*url>
+\cs_new_protected_nopar:Npn \@@_convert_escape_url:
+ { \@@_convert_gmap:N \@@_escape_url_char:N }
+\cs_new:Npn \@@_escape_url_char:N #1
+ {
+ \@@_if_escape_url:NTF #1 {#1}
+ { \c_percent_str \@@_output_hexadecimal:n { `#1 } }
+ }
+\prg_new_conditional:Npnn \@@_if_escape_url:N #1 { TF }
+ {
+ \if_int_compare:w `#1 < "41 \exp_stop_f:
+ \@@_if_contains_char:nNTF { "-.<> } #1
+ \prg_return_true: \prg_return_false:
+ \else:
+ \if_int_compare:w `#1 > "7E \exp_stop_f:
+ \prg_return_false:
+ \else:
+ \@@_if_contains_char:nNTF { [ ] } #1
+ \prg_return_false: \prg_return_true:
+ \fi:
+ \fi:
+ }
+%</url>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Encoding definition files}
+%
+% The \texttt{native} encoding is automatically defined. Other encodings
+% are loaded as needed. The following encodings are supported:
+% \begin{itemize}
+% \item \textsc{utf-8};
+% \item \textsc{utf-16}, big-, little-endian, or with byte order mark;
+% \item \textsc{utf-32}, big-, little-endian, or with byte order mark;
+% \item the \textsc{iso 8859} code pages, numbered from $1$ to $16$,
+% skipping the inexistent \textsc{iso 8859-12}.
+% \end{itemize}
+%
+% \subsubsection{\textsc{utf-8} support}
+%
+% \begin{macrocode}
+%<*utf8>
+% \end{macrocode}
+%
+% \begin{macro}[int]{\@@_convert_encode_utf8:}
+% \begin{macro}[aux, rEXP]{\@@_encode_utf_viii_char:n}
+% \begin{macro}[aux, rEXP]{\@@_encode_utf_viii_loop:wwnnw}
+% Loop through the internal string, and convert each character to its
+% \textsc{utf-8} representation. The representation is built from the
+% right-most (least significant) byte to the left-most (most
+% significant) byte. Continuation bytes are in the range $[128,191]$,
+% taking $64$ different values, hence we roughly want to express the
+% character code in base $64$, shifting the first digit in the
+% representation by some number depending on how many continuation
+% bytes there are. In the range $[0,127]$, output the corresponding
+% byte directly. In the range $[128,2047]$, output the remainder
+% modulo $64$, plus $128$ as a continuation byte, then output the
+% quotient (which is in the range $[0,31]$), shifted by $192$. In the
+% next range, $[2048,65535]$, split the character code into residue
+% and quotient modulo $64$, output the residue as a first continuation
+% byte, then repeat; this leaves us with a quotient in the range
+% $[0,15]$, which we output shifted by $224$. The last range,
+% $[65536,1114111]$, follows the same pattern: once we realize that
+% dividing twice by $64$ leaves us with a number larger than $15$, we
+% repeat, producing a last continuation byte, and offset the quotient
+% by $240$ for the leading byte.
+%
+% How is that implemented? \cs{@@_encode_utf_vii_loop:wwnnw} takes
+% successive quotients as its first argument, the quotient from the
+% previous step as its second argument (except in step~$1$), the bound
+% for quotients that trigger one more step or not, and finally the
+% offset used if this step should produce the leading byte. Leading
+% bytes can be in the ranges $[0,127]$, $[192,223]$, $[224,239]$, and
+% $[240,247]$ (really, that last limit should be $244$ because Unicode
+% stops at the code point $1114111$). At each step, if the quotient
+% |#1| is less than the limit |#3| for that range, output the leading
+% byte (|#1| shifted by |#4|) and stop. Otherwise, we need one more
+% step: use the quotient of |#1| by $64$, and |#1| as arguments for
+% the looping auxiliary, and output the continuation byte
+% corresponding to the remainder $|#2|-64|#1|+128$. The bizarre
+% construction |\c_minus_one + \c_zero *| removes the spurious initial
+% continuation byte (better methods welcome).
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { @@_convert_encode_utf8: }
+ { \@@_convert_gmap_internal:N \@@_encode_utf_viii_char:n }
+\cs_new:Npn \@@_encode_utf_viii_char:n #1
+ {
+ \@@_encode_utf_viii_loop:wwnnw #1 ; \c_minus_one + \c_zero * ;
+ { 128 } { \c_zero }
+ { 32 } { 192 }
+ { 16 } { 224 }
+ { 8 } { 240 }
+ \q_stop
+ }
+\cs_new:Npn \@@_encode_utf_viii_loop:wwnnw #1; #2; #3#4 #5 \q_stop
+ {
+ \if_int_compare:w #1 < #3 \exp_stop_f:
+ \@@_output_byte:n { #1 + #4 }
+ \exp_after:wN \use_none_delimit_by_q_stop:w
+ \fi:
+ \exp_after:wN \@@_encode_utf_viii_loop:wwnnw
+ \__int_value:w \int_div_truncate:nn {#1} {64} ; #1 ;
+ #5 \q_stop
+ \@@_output_byte:n { #2 - 64 * ( #1 - \c_two ) }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{variable}
+% {
+% \l_@@_missing_flag ,
+% \l_@@_extra_flag ,
+% \l_@@_overlong_flag ,
+% \l_@@_overflow_flag ,
+% }
+% When decoding a string that is purportedly in the \textsc{utf-8}
+% encoding, four different errors can occur, signalled by a specific
+% flag for each (we define those flags using \cs{flag_clear_new:n}
+% rather than \cs{flag_new:n}, because they are shared with other
+% encoding definition files).
+% \begin{itemize}
+% \item \enquote{Missing continuation byte}: a leading byte is not
+% followed by the right number of continuation bytes.
+% \item \enquote{Extra continuation byte}: a continuation byte
+% appears where it was not expected, \emph{i.e.}, not after an
+% appropriate leading byte.
+% \item \enquote{Overlong}: a Unicode character is expressed using
+% more bytes than necessary, for instance, \hexnum{C0}\hexnum{80}
+% for the code point $0$, instead of a single null byte.
+% \item \enquote{Overflow}: this occurs when decoding produces
+% Unicode code points greater than $1114111$.
+% \end{itemize}
+% We only raise one \LaTeX3 error message, combining all the errors
+% which occurred. In the short message, the leading comma must be
+% removed to get a grammatically correct sentence. In the long text,
+% first remind the user what a correct \textsc{utf-8} string should
+% look like, then add error-specific information.
+% \begin{macrocode}
+\flag_clear_new:n { str_missing }
+\flag_clear_new:n { str_extra }
+\flag_clear_new:n { str_overlong }
+\flag_clear_new:n { str_overflow }
+\__msg_kernel_new:nnnn { str } { utf8-decode }
+ {
+ Invalid~UTF-8~string: \exp_last_unbraced:Nf \use_none:n
+ \@@_if_flag_times:nT { str_missing } { ,~missing~continuation~byte }
+ \@@_if_flag_times:nT { str_extra } { ,~extra~continuation~byte }
+ \@@_if_flag_times:nT { str_overlong } { ,~overlong~form }
+ \@@_if_flag_times:nT { str_overflow } { ,~code~point~too~large }
+ .
+ }
+ {
+ In~the~UTF-8~encoding,~each~Unicode~character~consists~in~
+ 1~to~4~bytes,~with~the~following~bit~pattern: \\
+ \iow_indent:n
+ {
+ Code~point~\ \ \ \ <~128:~0xxxxxxx \\
+ Code~point~\ \ \ <~2048:~110xxxxx~10xxxxxx \\
+ Code~point~\ \ <~65536:~1110xxxx~10xxxxxx~10xxxxxx \\
+ Code~point~ <~1114112:~11110xxx~10xxxxxx~10xxxxxx~10xxxxxx \\
+ }
+ Bytes~of~the~form~10xxxxxx~are~called~continuation~bytes.
+ \flag_if_raised:nT { str_missing }
+ {
+ \\\\
+ A~leading~byte~(in~the~range~[192,255])~was~not~followed~by~
+ the~appropriate~number~of~continuation~bytes.
+ }
+ \flag_if_raised:nT { str_extra }
+ {
+ \\\\
+ LaTeX~came~across~a~continuation~byte~when~it~was~not~expected.
+ }
+ \flag_if_raised:nT { str_overlong }
+ {
+ \\\\
+ Every~Unicode~code~point~must~be~expressed~in~the~shortest~
+ possible~form.~For~instance,~'0xC0'~'0x83'~is~not~a~valid~
+ representation~for~the~code~point~3.
+ }
+ \flag_if_raised:nT { str_overflow }
+ {
+ \\\\
+ Unicode~limits~code~points~to~the~range~[0,1114111].
+ }
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\@@_convert_decode_utf8:}
+% \begin{macro}[aux, rEXP]
+% {
+% \@@_decode_utf_viii_start:N,
+% \@@_decode_utf_viii_continuation:wwN,
+% \@@_decode_utf_viii_aux:wNnnwN
+% }
+% \begin{macro}[aux, rEXP]
+% {\@@_decode_utf_viii_overflow:w, \@@_decode_utf_viii_end:}
+% Decoding is significantly harder than encoding. As before, lower
+% some flags, which are tested at the end (in bulk, to trigger at most
+% one \LaTeX3 error, as explained above). We expect successive
+% multi-byte sequences of the form \meta{start byte}
+% \meta{continuation bytes}. The \texttt{_start} auxiliary tests the
+% first byte:
+% \begin{itemize}
+% \item $[0,\hexnum{7F}]$: the byte stands alone, and is converted
+% to its own character code;
+% \item $[\hexnum{80}, \hexnum{BF}]$: unexpected continuation byte,
+% raise the appropriate flag, and convert that byte to the
+% replacement character \hexnum{FFFD};
+% \item $[\hexnum{C0}, \hexnum{FF}]$: this byte should be followed
+% by some continuation byte(s).
+% \end{itemize}
+% In the first two cases, \cs{use_none_delimit_by_q_stop:w} removes
+% data that only the third case requires, namely the limits of ranges
+% of Unicode characters which can be expressed with $1$, $2$, $3$, or
+% $4$ bytes.
+%
+% We can now concentrate on the multi-byte case and the
+% \texttt{_continuation} auxiliary. We expect |#3| to be in the range
+% $[\hexnum{80}, \hexnum{BF}]$. The test for this goes as follows: if
+% the character code is less than \hexnum{80}, we compare it to
+% $-\hexnum{C0}$, yielding \texttt{false}; otherwise to \hexnum{C0},
+% yielding \texttt{true} in the range $[\hexnum{80}, \hexnum{BF}]$ and
+% \texttt{false} otherwise. If we find that the byte is not a
+% continuation range, stop the current slew of bytes, output the
+% replacement character, and continue parsing with the \texttt{_start}
+% auxiliary, starting at the byte we just tested. Once we know that
+% the byte is a continuation byte, leave it behind us in the input
+% stream, compute what code point the bytes read so far would produce,
+% and feed that number to the \texttt{_aux} function.
+%
+% The \texttt{_aux} function tests whether we should look for more
+% continuation bytes or not. If the number it receives as |#1| is less
+% than the maximum |#4| for the current range, then we are done: check
+% for an overlong representation by comparing |#1| with the maximum
+% |#3| for the previous range. Otherwise, we call the
+% \texttt{_continuation} auxiliary again, after shifting the
+% \enquote{current code point} by |#4| (maximum from the range we just
+% checkedd).
+%
+% Two additional tests are needed: if we reach the end of the list of
+% range maxima and we are still not done, then we are faced with an
+% overflow. Clean up, and again insert the code point \hexnum{FFFD}
+% for the replacement character. Also, every time we read a byte, we
+% need to check whether we reached the end of the string. In a correct
+% \textsc{utf-8} string, this happens automatically when the
+% \texttt{_start} auxiliary leaves its first argument in the input
+% stream: the end-marker begins with \cs{__prg_break:}, which ends
+% the loop. On the other hand, if the end is reached when looking for
+% a continuation byte, the \cs{use_none:n} |#3| construction removes
+% the first token from the end-marker, and leaves the \texttt{_end}
+% auxiliary, which raises the appropriate error flag before ending the
+% mapping.
+% \begin{macrocode}
+\cs_new_protected_nopar:cpn { @@_convert_decode_utf8: }
+ {
+ \flag_clear:n { str_error }
+ \flag_clear:n { str_missing }
+ \flag_clear:n { str_extra }
+ \flag_clear:n { str_overlong }
+ \flag_clear:n { str_overflow }
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \exp_after:wN \@@_decode_utf_viii_start:N \g_@@_result_tl
+ { \__prg_break: \@@_decode_utf_viii_end: }
+ \__prg_break_point:
+ }
+ \@@_if_flag_error:nnx { str_error } { utf8-decode } { }
+ }
+\cs_new:Npn \@@_decode_utf_viii_start:N #1
+ {
+ #1
+ \if_int_compare:w `#1 < "C0 \exp_stop_f:
+ \s__tl
+ \if_int_compare:w `#1 < "80 \exp_stop_f:
+ \__int_value:w `#1
+ \else:
+ \flag_raise:n { str_extra }
+ \flag_raise:n { str_error }
+ \int_use:N \c_@@_replacement_char_int
+ \fi:
+ \else:
+ \exp_after:wN \@@_decode_utf_viii_continuation:wwN
+ \int_use:N \__int_eval:w `#1 - "C0 \exp_after:wN \__int_eval_end:
+ \fi:
+ \s__tl
+ \use_none_delimit_by_q_stop:w {"80} {"800} {"10000} {"110000} \q_stop
+ \@@_decode_utf_viii_start:N
+ }
+\cs_new:Npn \@@_decode_utf_viii_continuation:wwN
+ #1 \s__tl #2 \@@_decode_utf_viii_start:N #3
+ {
+ \use_none:n #3
+ \if_int_compare:w `#3 <
+ \if_int_compare:w `#3 < "80 \exp_stop_f: - \fi:
+ "C0 \exp_stop_f:
+ #3
+ \exp_after:wN \@@_decode_utf_viii_aux:wNnnwN
+ \int_use:N \__int_eval:w
+ #1 * "40 + `#3 - "80
+ \exp_after:wN \__int_eval_end:
+ \else:
+ \s__tl
+ \flag_raise:n { str_missing }
+ \flag_raise:n { str_error }
+ \int_use:N \c_@@_replacement_char_int
+ \fi:
+ \s__tl
+ #2
+ \@@_decode_utf_viii_start:N #3
+ }
+\cs_new:Npn \@@_decode_utf_viii_aux:wNnnwN
+ #1 \s__tl #2#3#4 #5 \@@_decode_utf_viii_start:N #6
+ {
+ \if_int_compare:w #1 < #4 \exp_stop_f:
+ \s__tl
+ \if_int_compare:w #1 < #3 \exp_stop_f:
+ \flag_raise:n { str_overlong }
+ \flag_raise:n { str_error }
+ \int_use:N \c_@@_replacement_char_int
+ \else:
+ #1
+ \fi:
+ \else:
+ \if_meaning:w \q_stop #5
+ \@@_decode_utf_viii_overflow:w #1
+ \fi:
+ \exp_after:wN \@@_decode_utf_viii_continuation:wwN
+ \int_use:N \__int_eval:w #1 - #4 \exp_after:wN \__int_eval_end:
+ \fi:
+ \s__tl
+ #2 {#4} #5
+ \@@_decode_utf_viii_start:N
+ }
+\cs_new:Npn \@@_decode_utf_viii_overflow:w #1 \fi: #2 \fi:
+ {
+ \fi: \fi:
+ \flag_raise:n { str_overflow }
+ \flag_raise:n { str_error }
+ \int_use:N \c_@@_replacement_char_int
+ }
+\cs_new_nopar:Npn \@@_decode_utf_viii_end:
+ {
+ \s__tl
+ \flag_raise:n { str_missing }
+ \flag_raise:n { str_error }
+ \int_use:N \c_@@_replacement_char_int \s__tl
+ \__prg_break:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</utf8>
+% \end{macrocode}
+%
+% \subsubsection{\textsc{utf-16} support}
+%
+% The definitions are done in a category code regime where the bytes
+% $254$ and $255$ used by the byte order mark have catcode~$12$.
+% \begin{macrocode}
+%<*utf16>
+\group_begin:
+ \char_set_catcode_other:N \^^fe
+ \char_set_catcode_other:N \^^ff
+% \end{macrocode}
+%
+% \begin{macro}[int]
+% {
+% \@@_convert_encode_utf16: ,
+% \@@_convert_encode_utf16be: ,
+% \@@_convert_encode_utf16le: ,
+% }
+% \begin{macro}[aux, rEXP]
+% {
+% \@@_encode_utf_xvi_aux:N ,
+% \@@_encode_utf_xvi_char:n ,
+% }
+% When the endianness is not specified, it is big-endian by default,
+% and we add a byte-order mark. Convert characters one by one in a
+% loop, with different behaviours depending on the character code.
+% \begin{itemize}
+% \item $[0, \hexnum{D7FF}]$: converted to two bytes;
+% \item $[\hexnum{D800}, \hexnum{DFFF}]$ are used as surrogates:
+% they cannot be converted and are replaced by the replacement
+% character;
+% \item $[\hexnum{E000}, \hexnum{FFFF}]$: converted to two bytes;
+% \item $[\hexnum{10000}, \hexnum{10FFFF}]$: converted to a pair of
+% surrogates, each two bytes. The magic \hexnum{D7C0} is
+% $\hexnum{D800}-\hexnum{10000}/\hexnum{400}$.
+% \end{itemize}
+% For the duration of this operation, \cs{@@_tmp:w} is defined as a
+% function to convert a number in the range $[0, \hexnum{FFFF}]$ to a
+% pair of bytes (either big endian or little endian), by feeding the
+% quotient of the division of |#1| by \hexnum{100}, followed by |#1|
+% to \cs{@@_encode_utf_xvi_be:nn} or its \texttt{le} analog: those
+% compute the remainder, and output two bytes for the quotient and
+% remainder.
+% \begin{macrocode}
+ \cs_new_protected_nopar:cpn { @@_convert_encode_utf16: }
+ {
+ \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_be:n
+ \tl_gput_left:Nx \g_@@_result_tl { ^^fe ^^ff }
+ }
+ \cs_new_protected_nopar:cpn { @@_convert_encode_utf16be: }
+ { \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_be:n }
+ \cs_new_protected_nopar:cpn { @@_convert_encode_utf16le: }
+ { \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_le:n }
+ \cs_new_protected:Npn \@@_encode_utf_xvi_aux:N #1
+ {
+ \flag_clear:n { str_error }
+ \cs_set_eq:NN \@@_tmp:w #1
+ \@@_convert_gmap_internal:N \@@_encode_utf_xvi_char:n
+ \@@_if_flag_error:nnx { str_error } { utf16-encode } { }
+ }
+ \cs_new:Npn \@@_encode_utf_xvi_char:n #1
+ {
+ \if_int_compare:w #1 < "D800 \exp_stop_f:
+ \@@_tmp:w {#1}
+ \else:
+ \if_int_compare:w #1 < "10000 \exp_stop_f:
+ \if_int_compare:w #1 < "E000 \exp_stop_f:
+ \flag_raise:n { str_error }
+ \@@_tmp:w { \c_@@_replacement_char_int }
+ \else:
+ \@@_tmp:w {#1}
+ \fi:
+ \else:
+ \exp_args:Nf \@@_tmp:w { \int_div_truncate:nn {#1} {"400} + "D7C0 }
+ \exp_args:Nf \@@_tmp:w { \int_mod:nn {#1} {"400} + "DC00 }
+ \fi:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{variable}
+% {
+% \l_@@_missing_flag ,
+% \l_@@_extra_flag ,
+% \l_@@_end_flag ,
+% }
+% When encoding a Unicode string to \textsc{utf-16}, only one error
+% can occur: code points in the range $[\hexnum{D800},
+% \hexnum{DFFF}]$, corresponding to surrogates, cannot be encoded. We
+% use the all-purpose flag \texttt{@@_error} to signal that error.
+%
+% When decoding a Unicode string which is purportedly in
+% \textsc{utf-16}, three errors can occur: a missing trail surrogate,
+% an unexpected trail surrogate, and a string containing an odd number
+% of bytes.
+% \begin{macrocode}
+ \flag_clear_new:n { str_missing }
+ \flag_clear_new:n { str_extra }
+ \flag_clear_new:n { str_end }
+ \__msg_kernel_new:nnnn { str } { utf16-encode }
+ { Unicode~string~cannot~be~expressed~in~UTF-16:~surrogate. }
+ {
+ Surrogate~code~points~(in~the~range~[U+D800,~U+DFFF])~
+ can~be~expressed~in~the~UTF-8~and~UTF-32~encodings,~
+ but~not~in~the~UTF-16~encoding.
+ }
+ \__msg_kernel_new:nnnn { str } { utf16-decode }
+ {
+ Invalid~UTF-16~string: \exp_last_unbraced:Nf \use_none:n
+ \@@_if_flag_times:nT { str_missing } { ,~missing~trail~surrogate }
+ \@@_if_flag_times:nT { str_extra } { ,~extra~trail~surrogate }
+ \@@_if_flag_times:nT { str_end } { ,~odd~number~of~bytes }
+ .
+ }
+ {
+ In~the~UTF-16~encoding,~each~Unicode~character~is~encoded~as~
+ 2~or~4~bytes: \\
+ \iow_indent:n
+ {
+ Code~point~in~[U+0000,~U+D7FF]:~two~bytes \\
+ Code~point~in~[U+D800,~U+DFFF]:~illegal \\
+ Code~point~in~[U+E000,~U+FFFF]:~two~bytes \\
+ Code~point~in~[U+10000,~U+10FFFF]:~
+ a~lead~surrogate~and~a~trail~surrogate \\
+ }
+ Lead~surrogates~are~pairs~of~bytes~in~the~range~[0xD800,~0xDBFF],~
+ and~trail~surrogates~are~in~the~range~[0xDC00,~0xDFFF].
+ \flag_if_raised:nT { str_missing }
+ {
+ \\\\
+ A~lead~surrogate~was~not~followed~by~a~trail~surrogate.
+ }
+ \flag_if_raised:nT { str_extra }
+ {
+ \\\\
+ LaTeX~came~across~a~trail~surrogate~when~it~was~not~expected.
+ }
+ \flag_if_raised:nT { str_end }
+ {
+ \\\\
+ The~string~contained~an~odd~number~of~bytes.~This~is~invalid:~
+ the~basic~code~unit~for~UTF-16~is~16~bits~(2~bytes).
+ }
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]
+% {
+% \@@_convert_decode_utf16: ,
+% \@@_convert_decode_utf16be: ,
+% \@@_convert_decode_utf16le: ,
+% }
+% \begin{macro}[aux]{\@@_decode_utf_xvi_bom:NN, \@@_decode_utf_xvi:Nw}
+% As for \textsc{utf-8}, decoding \textsc{utf-16} is harder than
+% encoding it. If the endianness is unknown, check the first two
+% bytes: if those are \hexnum{FE} and \hexnum{FF} in either order,
+% remove them and use the corresponding endianness, otherwise assume
+% big-endianness. The three endianness cases are based on a common
+% auxiliary whose first argument is $1$ for big-endian and $2$ for
+% little-endian, and whose second argument, delimited by the scan mark
+% \cs{s__stop}, is expanded once (the string may be long; passing
+% \cs{g_@@_result_tl} as an argument before expansion is cheaper).
+%
+% The \cs{@@_decode_utf_xvi:Nw} function defines \cs{@@_tmp:w} to
+% take two arguments and return the character code of the first one if
+% the string is big-endian, and the second one if the string is
+% little-endian, then loops over the string using
+% \cs{@@_decode_utf_xvi_pair:NN} described below.
+% \begin{macrocode}
+ \cs_new_protected_nopar:cpn { @@_convert_decode_utf16be: }
+ { \@@_decode_utf_xvi:Nw 1 \g_@@_result_tl \s__stop }
+ \cs_new_protected_nopar:cpn { @@_convert_decode_utf16le: }
+ { \@@_decode_utf_xvi:Nw 2 \g_@@_result_tl \s__stop }
+ \cs_new_protected_nopar:cpn { @@_convert_decode_utf16: }
+ {
+ \exp_after:wN \@@_decode_utf_xvi_bom:NN
+ \g_@@_result_tl \s__stop \s__stop \s__stop
+ }
+ \cs_new_protected:Npn \@@_decode_utf_xvi_bom:NN #1#2
+ {
+ \str_if_eq_x:nnTF { #1#2 } { ^^ff ^^fe }
+ { \@@_decode_utf_xvi:Nw 2 }
+ {
+ \str_if_eq_x:nnTF { #1#2 } { ^^fe ^^ff }
+ { \@@_decode_utf_xvi:Nw 1 }
+ { \@@_decode_utf_xvi:Nw 1 #1#2 }
+ }
+ }
+ \cs_new_protected:Npn \@@_decode_utf_xvi:Nw #1#2 \s__stop
+ {
+ \flag_clear:n { str_error }
+ \flag_clear:n { str_missing }
+ \flag_clear:n { str_extra }
+ \flag_clear:n { str_end }
+ \cs_set:Npn \@@_tmp:w ##1 ##2 { ` ## #1 }
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \exp_after:wN \@@_decode_utf_xvi_pair:NN
+ #2 \q_nil \q_nil
+ \__prg_break_point:
+ }
+ \@@_if_flag_error:nnx { str_error } { utf16-decode } { }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux, rEXP]
+% {
+% \@@_decode_utf_xvi_pair:NN ,
+% \@@_decode_utf_xvi_quad:NNwNN ,
+% \@@_decode_utf_xvi_pair_end:Nw ,
+% }
+% \begin{macro}[aux, rEXP]
+% {
+% \@@_decode_utf_xvi_error:nNN ,
+% \@@_decode_utf_xvi_extra:NNw ,
+% }
+% Bytes are read two at a time. At this stage, |\@@_tmp:w #1#2|
+% expands to the character code of the most significant byte, and we
+% distinguish cases depending on which range it lies in:
+% \begin{itemize}
+% \item $[\hexnum{D8}, \hexnum{DB}]$ signals a lead surrogate, and
+% the integer expression yields $1$ (\eTeX{} rounds ties away from
+% zero);
+% \item $[\hexnum{DC}, \hexnum{DF}]$ signals a trail surrogate,
+% unexpected here, and the integer expression yields $2$;
+% \item any other value signals a code point in the Basic
+% Multilingual Plane, which stands for itself, and the
+% \cs{if_case:w} construction expands to nothing (cases other than
+% $1$ or $2$), leaving the relevant material in the input stream,
+% followed by another call to the \texttt{_pair} auxiliary.
+% \end{itemize}
+% The case of a lead surrogate is treated by the \texttt{_quad}
+% auxiliary, whose arguments |#1|, |#2|, |#4| and |#5| are the four
+% bytes. We expect the most significant byte of |#4#5| to be in the
+% range $[\hexnum{DC}, \hexnum{DF}]$ (trail surrogate). The test is
+% similar to the test used for continuation bytes in the
+% \textsc{utf-8} decoding functions. In the case where |#4#5| is
+% indeed a trail surrogate, leave |#1#2#4#5| \cs{s__tl}
+% \meta{code~point} \cs{s__tl}, and remove the pair |#4#5| before
+% looping with \cs{@@_decode_utf_xvi_pair:NN}. Otherwise, of course,
+% complain about the missing surrogate.
+%
+% The magic number \hexnum{D7F7} is such that
+% $\hexnum{D7F7}*\hexnum{400} = \hexnum{D800}*\hexnum{400} +
+% \hexnum{DC00} - \hexnum{10000}$.
+%
+% Every time we read a pair of bytes, we test for the end-marker
+% \cs{q_nil}. When reaching the end, we additionally check that the
+% string had an even length. Also, if the end is reached when
+% expecting a trail surrogate, we treat that as a missing surrogate.
+% \begin{macrocode}
+ \cs_new:Npn \@@_decode_utf_xvi_pair:NN #1#2
+ {
+ \if_meaning:w \q_nil #2
+ \@@_decode_utf_xvi_pair_end:Nw #1
+ \fi:
+ \if_case:w
+ \__int_eval:w ( \@@_tmp:w #1#2 - "D6 ) / \c_four \__int_eval_end:
+ \or: \exp_after:wN \@@_decode_utf_xvi_quad:NNwNN
+ \or: \exp_after:wN \@@_decode_utf_xvi_extra:NNw
+ \fi:
+ #1#2 \s__tl
+ \int_eval:n { "100 * \@@_tmp:w #1#2 + \@@_tmp:w #2#1 } \s__tl
+ \@@_decode_utf_xvi_pair:NN
+ }
+ \cs_new:Npn \@@_decode_utf_xvi_quad:NNwNN
+ #1#2 #3 \@@_decode_utf_xvi_pair:NN #4#5
+ {
+ \if_meaning:w \q_nil #5
+ \@@_decode_utf_xvi_error:nNN { missing } #1#2
+ \@@_decode_utf_xvi_pair_end:Nw #4
+ \fi:
+ \if_int_compare:w
+ \if_int_compare:w \@@_tmp:w #4#5 < "DC \exp_stop_f:
+ \c_zero = \c_one
+ \else:
+ \@@_tmp:w #4#5 < "E0 \exp_stop_f:
+ \fi:
+ #1 #2 #4 #5 \s__tl
+ \int_eval:n
+ {
+ ( "100 * \@@_tmp:w #1#2 + \@@_tmp:w #2#1 - "D7F7 ) * "400
+ + "100 * \@@_tmp:w #4#5 + \@@_tmp:w #5#4
+ }
+ \s__tl
+ \exp_after:wN \use_i:nnn
+ \else:
+ \@@_decode_utf_xvi_error:nNN { missing } #1#2
+ \fi:
+ \@@_decode_utf_xvi_pair:NN #4#5
+ }
+ \cs_new:Npn \@@_decode_utf_xvi_pair_end:Nw #1 \fi:
+ {
+ \fi:
+ \if_meaning:w \q_nil #1
+ \else:
+ \@@_decode_utf_xvi_error:nNN { end } #1 \prg_do_nothing:
+ \fi:
+ \__prg_break:
+ }
+ \cs_new:Npn \@@_decode_utf_xvi_extra:NNw #1#2 \s__tl #3 \s__tl
+ { \@@_decode_utf_xvi_error:nNN { extra } #1#2 }
+ \cs_new:Npn \@@_decode_utf_xvi_error:nNN #1#2#3
+ {
+ \flag_raise:n { str_error }
+ \flag_raise:n { str_#1 }
+ #2 #3 \s__tl
+ \int_use:N \c_@@_replacement_char_int \s__tl
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% Restore the original catcodes of bytes $254$ and $255$.
+% \begin{macrocode}
+\group_end:
+%</utf16>
+% \end{macrocode}
+%
+% \subsubsection{\textsc{utf-32} support}
+%
+% The definitions are done in a category code regime where the bytes
+% $0$, $254$ and $255$ used by the byte order mark have catcode
+% \enquote{other}.
+% \begin{macrocode}
+%<*utf32>
+\group_begin:
+ \char_set_catcode_other:N \^^00
+ \char_set_catcode_other:N \^^fe
+ \char_set_catcode_other:N \^^ff
+% \end{macrocode}
+%
+% \begin{macro}[int]
+% {
+% \@@_convert_encode_utf32: ,
+% \@@_convert_encode_utf32be: ,
+% \@@_convert_encode_utf32le: ,
+% }
+% \begin{macro}[aux, rEXP]
+% {
+% \@@_encode_utf_xxxii_be:n ,
+% \@@_encode_utf_xxxii_be_aux:nn ,
+% \@@_encode_utf_xxxii_le:n ,
+% \@@_encode_utf_xxxii_le_aux:nn ,
+% }
+% Convert each integer in the comma-list \cs{g_@@_result_tl} to a
+% sequence of four bytes. The functions for big-endian and
+% little-endian encodings are very similar, but the
+% \cs{@@_output_byte:n} instructions are reversed.
+% \begin{macrocode}
+ \cs_new_protected_nopar:cpn { @@_convert_encode_utf32: }
+ {
+ \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_be:n
+ \tl_gput_left:Nx \g_@@_result_tl { ^^00 ^^00 ^^fe ^^ff }
+ }
+ \cs_new_protected_nopar:cpn { @@_convert_encode_utf32be: }
+ { \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_be:n }
+ \cs_new_protected_nopar:cpn { @@_convert_encode_utf32le: }
+ { \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_le:n }
+ \cs_new:Npn \@@_encode_utf_xxxii_be:n #1
+ {
+ \exp_args:Nf \@@_encode_utf_xxxii_be_aux:nn
+ { \int_div_truncate:nn {#1} { "100 } } {#1}
+ }
+ \cs_new:Npn \@@_encode_utf_xxxii_be_aux:nn #1#2
+ {
+ ^^00
+ \@@_output_byte_pair_be:n {#1}
+ \@@_output_byte:n { #2 - #1 * "100 }
+ }
+ \cs_new:Npn \@@_encode_utf_xxxii_le:n #1
+ {
+ \exp_args:Nf \@@_encode_utf_xxxii_le_aux:nn
+ { \int_div_truncate:nn {#1} { "100 } } {#1}
+ }
+ \cs_new:Npn \@@_encode_utf_xxxii_le_aux:nn #1#2
+ {
+ \@@_output_byte:n { #2 - #1 * "100 }
+ \@@_output_byte_pair_le:n {#1}
+ ^^00
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{variable}{str_overflow, str_end}
+% There can be no error when encoding in \textsc{utf-32}. When
+% decoding, the string may not have length $4n$, or it may contain
+% code points larger than \hexnum{10FFFF}. The latter case often
+% happens if the encoding was in fact not \textsc{utf-32}, because
+% most arbitrary strings are not valid in \textsc{utf-32}.
+% \begin{macrocode}
+ \flag_clear_new:n { str_overflow }
+ \flag_clear_new:n { str_end }
+ \__msg_kernel_new:nnnn { str } { utf32-decode }
+ {
+ Invalid~UTF-32~string: \exp_last_unbraced:Nf \use_none:n
+ \@@_if_flag_times:nT { str_overflow } { ,~code~point~too~large }
+ \@@_if_flag_times:nT { str_end } { ,~truncated~string }
+ .
+ }
+ {
+ In~the~UTF-32~encoding,~every~Unicode~character~
+ (in~the~range~[U+0000,~U+10FFFF])~is~encoded~as~4~bytes.
+ \flag_if_raised:nT { str_overflow }
+ {
+ \\\\
+ LaTeX~came~across~a~code~point~larger~than~1114111,~
+ the~maximum~code~point~defined~by~Unicode.~
+ Perhaps~the~string~was~not~encoded~in~the~UTF-32~encoding?
+ }
+ \flag_if_raised:nT { str_end }
+ {
+ \\\\
+ The~length~of~the~string~is~not~a~multiple~of~4.~
+ Perhaps~the~string~was~truncated?
+ }
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]
+% {
+% \@@_convert_decode_utf32: ,
+% \@@_convert_decode_utf32be: ,
+% \@@_convert_decode_utf32le: ,
+% }
+% \begin{macro}[aux]
+% {\@@_decode_utf_xxxii_bom:NNNN, \@@_decode_utf_xxxii:Nw}
+% \begin{macro}[aux, rEXP]
+% {\@@_decode_utf_xxxii_loop:NNNN, \@@_decode_utf_xxxii_end:w}
+%
+% The structure is similar to \textsc{utf-16} decoding functions. If
+% the endianness is not given, test the first $4$ bytes of the string
+% (possibly \cs{s__stop} if the string is too short) for the presence
+% of a byte-order mark. If there is a byte-order mark, use that
+% endianness, and remove the $4$ bytes, otherwise default to
+% big-endian, and leave the $4$ bytes in place. The
+% \cs{@@_decode_utf_xxxii:Nw} auxiliary recieves $1$ or $2$ as its
+% first argument indicating endianness, and the string to convert as
+% its second argument (expanded or not). It sets \cs{@@_tmp:w} to
+% expand to the character code of either of its two arguments
+% depending on endianness, then triggers the \texttt{_loop} auxiliary
+% inside an \texttt{x}-expanding assignment to \cs{g_@@_result_tl}.
+%
+% The \texttt{_loop} auxiliary first checks for the end-of-string
+% marker \cs{s__stop}, calling the \texttt{_end} auxiliary if
+% appropriate. Otherwise, leave the \meta{4~bytes} \cs{s__tl} behind,
+% then check that the code point is not overflowing: the leading byte
+% must be $0$, and the following byte at most $16$.
+%
+% In the ending code, we check that there remains no byte: there
+% should be nothing left until the first \cs{s__stop}. Break the map.
+% \begin{macrocode}
+ \cs_new_protected_nopar:cpn { @@_convert_decode_utf32be: }
+ { \@@_decode_utf_xxxii:Nw 1 \g_@@_result_tl \s__stop }
+ \cs_new_protected_nopar:cpn { @@_convert_decode_utf32le: }
+ { \@@_decode_utf_xxxii:Nw 2 \g_@@_result_tl \s__stop }
+ \cs_new_protected_nopar:cpn { @@_convert_decode_utf32: }
+ {
+ \exp_after:wN \@@_decode_utf_xxxii_bom:NNNN \g_@@_result_tl
+ \s__stop \s__stop \s__stop \s__stop \s__stop
+ }
+ \cs_new_protected:Npn \@@_decode_utf_xxxii_bom:NNNN #1#2#3#4
+ {
+ \str_if_eq_x:nnTF { #1#2#3#4 } { ^^ff ^^fe ^^00 ^^00 }
+ { \@@_decode_utf_xxxii:Nw 2 }
+ {
+ \str_if_eq_x:nnTF { #1#2#3#4 } { ^^00 ^^00 ^^fe ^^ff }
+ { \@@_decode_utf_xxxii:Nw 1 }
+ { \@@_decode_utf_xxxii:Nw 1 #1#2#3#4 }
+ }
+ }
+ \cs_new_protected:Npn \@@_decode_utf_xxxii:Nw #1#2 \s__stop
+ {
+ \flag_clear:n { str_overflow }
+ \flag_clear:n { str_end }
+ \flag_clear:n { str_error }
+ \cs_set:Npn \@@_tmp:w ##1 ##2 { ` ## #1 }
+ \tl_gset:Nx \g_@@_result_tl
+ {
+ \exp_after:wN \@@_decode_utf_xxxii_loop:NNNN
+ #2 \s__stop \s__stop \s__stop \s__stop
+ \__prg_break_point:
+ }
+ \@@_if_flag_error:nnx { str_error } { utf32-decode } { }
+ }
+ \cs_new:Npn \@@_decode_utf_xxxii_loop:NNNN #1#2#3#4
+ {
+ \if_meaning:w \s__stop #4
+ \exp_after:wN \@@_decode_utf_xxxii_end:w
+ \fi:
+ #1#2#3#4 \s__tl
+ \if_int_compare:w \@@_tmp:w #1#4 > \c_zero
+ \flag_raise:n { str_overflow }
+ \flag_raise:n { str_error }
+ \int_use:N \c_@@_replacement_char_int
+ \else:
+ \if_int_compare:w \@@_tmp:w #2#3 > \c_sixteen
+ \flag_raise:n { str_overflow }
+ \flag_raise:n { str_error }
+ \int_use:N \c_@@_replacement_char_int
+ \else:
+ \int_eval:n
+ { \@@_tmp:w #2#3*"10000 + \@@_tmp:w #3#2*"100 + \@@_tmp:w #4#1 }
+ \fi:
+ \fi:
+ \s__tl
+ \@@_decode_utf_xxxii_loop:NNNN
+ }
+ \cs_new:Npn \@@_decode_utf_xxxii_end:w #1 \s__stop
+ {
+ \tl_if_empty:nF {#1}
+ {
+ \flag_raise:n { str_end }
+ \flag_raise:n { str_error }
+ #1 \s__tl
+ \int_use:N \c_@@_replacement_char_int \s__tl
+ }
+ \__prg_break:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% Restore the original catcodes of bytes $0$, $254$ and $255$.
+% \begin{macrocode}
+\group_end:
+%</utf32>
+% \end{macrocode}
+%
+% \subsubsection{\textsc{iso 8859} support}
+%
+% The \textsc{iso-8859-1} encoding exactly matches with the $256$ first
+% Unicode characters. For other 8-bit encodings of the \textsc{iso-8859}
+% family, we keep track only of differences, and of unassigned bytes.
+% \begin{macrocode}
+%<*iso88591>
+\@@_declare_eight_bit_encoding:nnn { iso88591 }
+ {
+ }
+ {
+ }
+%</iso88591>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso88592>
+\@@_declare_eight_bit_encoding:nnn { iso88592 }
+ {
+ { A1 } { 0104 }
+ { A2 } { 02D8 }
+ { A3 } { 0141 }
+ { A5 } { 013D }
+ { A6 } { 015A }
+ { A9 } { 0160 }
+ { AA } { 015E }
+ { AB } { 0164 }
+ { AC } { 0179 }
+ { AE } { 017D }
+ { AF } { 017B }
+ { B1 } { 0105 }
+ { B2 } { 02DB }
+ { B3 } { 0142 }
+ { B5 } { 013E }
+ { B6 } { 015B }
+ { B7 } { 02C7 }
+ { B9 } { 0161 }
+ { BA } { 015F }
+ { BB } { 0165 }
+ { BC } { 017A }
+ { BD } { 02DD }
+ { BE } { 017E }
+ { BF } { 017C }
+ { C0 } { 0154 }
+ { C3 } { 0102 }
+ { C5 } { 0139 }
+ { C6 } { 0106 }
+ { C8 } { 010C }
+ { CA } { 0118 }
+ { CC } { 011A }
+ { CF } { 010E }
+ { D0 } { 0110 }
+ { D1 } { 0143 }
+ { D2 } { 0147 }
+ { D5 } { 0150 }
+ { D8 } { 0158 }
+ { D9 } { 016E }
+ { DB } { 0170 }
+ { DE } { 0162 }
+ { E0 } { 0155 }
+ { E3 } { 0103 }
+ { E5 } { 013A }
+ { E6 } { 0107 }
+ { E8 } { 010D }
+ { EA } { 0119 }
+ { EC } { 011B }
+ { EF } { 010F }
+ { F0 } { 0111 }
+ { F1 } { 0144 }
+ { F2 } { 0148 }
+ { F5 } { 0151 }
+ { F8 } { 0159 }
+ { F9 } { 016F }
+ { FB } { 0171 }
+ { FE } { 0163 }
+ { FF } { 02D9 }
+ }
+ {
+ }
+%</iso88592>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso88593>
+\@@_declare_eight_bit_encoding:nnn { iso88593 }
+ {
+ { A1 } { 0126 }
+ { A2 } { 02D8 }
+ { A6 } { 0124 }
+ { A9 } { 0130 }
+ { AA } { 015E }
+ { AB } { 011E }
+ { AC } { 0134 }
+ { AF } { 017B }
+ { B1 } { 0127 }
+ { B6 } { 0125 }
+ { B9 } { 0131 }
+ { BA } { 015F }
+ { BB } { 011F }
+ { BC } { 0135 }
+ { BF } { 017C }
+ { C5 } { 010A }
+ { C6 } { 0108 }
+ { D5 } { 0120 }
+ { D8 } { 011C }
+ { DD } { 016C }
+ { DE } { 015C }
+ { E5 } { 010B }
+ { E6 } { 0109 }
+ { F5 } { 0121 }
+ { F8 } { 011D }
+ { FD } { 016D }
+ { FE } { 015D }
+ { FF } { 02D9 }
+ }
+ {
+ { A5 }
+ { AE }
+ { BE }
+ { C3 }
+ { D0 }
+ { E3 }
+ { F0 }
+ }
+%</iso88593>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso88594>
+\@@_declare_eight_bit_encoding:nnn { iso88594 }
+ {
+ { A1 } { 0104 }
+ { A2 } { 0138 }
+ { A3 } { 0156 }
+ { A5 } { 0128 }
+ { A6 } { 013B }
+ { A9 } { 0160 }
+ { AA } { 0112 }
+ { AB } { 0122 }
+ { AC } { 0166 }
+ { AE } { 017D }
+ { B1 } { 0105 }
+ { B2 } { 02DB }
+ { B3 } { 0157 }
+ { B5 } { 0129 }
+ { B6 } { 013C }
+ { B7 } { 02C7 }
+ { B9 } { 0161 }
+ { BA } { 0113 }
+ { BB } { 0123 }
+ { BC } { 0167 }
+ { BD } { 014A }
+ { BE } { 017E }
+ { BF } { 014B }
+ { C0 } { 0100 }
+ { C7 } { 012E }
+ { C8 } { 010C }
+ { CA } { 0118 }
+ { CC } { 0116 }
+ { CF } { 012A }
+ { D0 } { 0110 }
+ { D1 } { 0145 }
+ { D2 } { 014C }
+ { D3 } { 0136 }
+ { D9 } { 0172 }
+ { DD } { 0168 }
+ { DE } { 016A }
+ { E0 } { 0101 }
+ { E7 } { 012F }
+ { E8 } { 010D }
+ { EA } { 0119 }
+ { EC } { 0117 }
+ { EF } { 012B }
+ { F0 } { 0111 }
+ { F1 } { 0146 }
+ { F2 } { 014D }
+ { F3 } { 0137 }
+ { F9 } { 0173 }
+ { FD } { 0169 }
+ { FE } { 016B }
+ { FF } { 02D9 }
+ }
+ {
+ }
+%</iso88594>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso88595>
+\@@_declare_eight_bit_encoding:nnn { iso88595 }
+ {
+ { A1 } { 0401 }
+ { A2 } { 0402 }
+ { A3 } { 0403 }
+ { A4 } { 0404 }
+ { A5 } { 0405 }
+ { A6 } { 0406 }
+ { A7 } { 0407 }
+ { A8 } { 0408 }
+ { A9 } { 0409 }
+ { AA } { 040A }
+ { AB } { 040B }
+ { AC } { 040C }
+ { AE } { 040E }
+ { AF } { 040F }
+ { B0 } { 0410 }
+ { B1 } { 0411 }
+ { B2 } { 0412 }
+ { B3 } { 0413 }
+ { B4 } { 0414 }
+ { B5 } { 0415 }
+ { B6 } { 0416 }
+ { B7 } { 0417 }
+ { B8 } { 0418 }
+ { B9 } { 0419 }
+ { BA } { 041A }
+ { BB } { 041B }
+ { BC } { 041C }
+ { BD } { 041D }
+ { BE } { 041E }
+ { BF } { 041F }
+ { C0 } { 0420 }
+ { C1 } { 0421 }
+ { C2 } { 0422 }
+ { C3 } { 0423 }
+ { C4 } { 0424 }
+ { C5 } { 0425 }
+ { C6 } { 0426 }
+ { C7 } { 0427 }
+ { C8 } { 0428 }
+ { C9 } { 0429 }
+ { CA } { 042A }
+ { CB } { 042B }
+ { CC } { 042C }
+ { CD } { 042D }
+ { CE } { 042E }
+ { CF } { 042F }
+ { D0 } { 0430 }
+ { D1 } { 0431 }
+ { D2 } { 0432 }
+ { D3 } { 0433 }
+ { D4 } { 0434 }
+ { D5 } { 0435 }
+ { D6 } { 0436 }
+ { D7 } { 0437 }
+ { D8 } { 0438 }
+ { D9 } { 0439 }
+ { DA } { 043A }
+ { DB } { 043B }
+ { DC } { 043C }
+ { DD } { 043D }
+ { DE } { 043E }
+ { DF } { 043F }
+ { E0 } { 0440 }
+ { E1 } { 0441 }
+ { E2 } { 0442 }
+ { E3 } { 0443 }
+ { E4 } { 0444 }
+ { E5 } { 0445 }
+ { E6 } { 0446 }
+ { E7 } { 0447 }
+ { E8 } { 0448 }
+ { E9 } { 0449 }
+ { EA } { 044A }
+ { EB } { 044B }
+ { EC } { 044C }
+ { ED } { 044D }
+ { EE } { 044E }
+ { EF } { 044F }
+ { F0 } { 2116 }
+ { F1 } { 0451 }
+ { F2 } { 0452 }
+ { F3 } { 0453 }
+ { F4 } { 0454 }
+ { F5 } { 0455 }
+ { F6 } { 0456 }
+ { F7 } { 0457 }
+ { F8 } { 0458 }
+ { F9 } { 0459 }
+ { FA } { 045A }
+ { FB } { 045B }
+ { FC } { 045C }
+ { FD } { 00A7 }
+ { FE } { 045E }
+ { FF } { 045F }
+ }
+ {
+ }
+%</iso88595>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso88596>
+\@@_declare_eight_bit_encoding:nnn { iso88596 }
+ {
+ { AC } { 060C }
+ { BB } { 061B }
+ { BF } { 061F }
+ { C1 } { 0621 }
+ { C2 } { 0622 }
+ { C3 } { 0623 }
+ { C4 } { 0624 }
+ { C5 } { 0625 }
+ { C6 } { 0626 }
+ { C7 } { 0627 }
+ { C8 } { 0628 }
+ { C9 } { 0629 }
+ { CA } { 062A }
+ { CB } { 062B }
+ { CC } { 062C }
+ { CD } { 062D }
+ { CE } { 062E }
+ { CF } { 062F }
+ { D0 } { 0630 }
+ { D1 } { 0631 }
+ { D2 } { 0632 }
+ { D3 } { 0633 }
+ { D4 } { 0634 }
+ { D5 } { 0635 }
+ { D6 } { 0636 }
+ { D7 } { 0637 }
+ { D8 } { 0638 }
+ { D9 } { 0639 }
+ { DA } { 063A }
+ { E0 } { 0640 }
+ { E1 } { 0641 }
+ { E2 } { 0642 }
+ { E3 } { 0643 }
+ { E4 } { 0644 }
+ { E5 } { 0645 }
+ { E6 } { 0646 }
+ { E7 } { 0647 }
+ { E8 } { 0648 }
+ { E9 } { 0649 }
+ { EA } { 064A }
+ { EB } { 064B }
+ { EC } { 064C }
+ { ED } { 064D }
+ { EE } { 064E }
+ { EF } { 064F }
+ { F0 } { 0650 }
+ { F1 } { 0651 }
+ { F2 } { 0652 }
+ }
+ {
+ { A1 }
+ { A2 }
+ { A3 }
+ { A5 }
+ { A6 }
+ { A7 }
+ { A8 }
+ { A9 }
+ { AA }
+ { AB }
+ { AE }
+ { AF }
+ { B0 }
+ { B1 }
+ { B2 }
+ { B3 }
+ { B4 }
+ { B5 }
+ { B6 }
+ { B7 }
+ { B8 }
+ { B9 }
+ { BA }
+ { BC }
+ { BD }
+ { BE }
+ { C0 }
+ { DB }
+ { DC }
+ { DD }
+ { DE }
+ { DF }
+ }
+%</iso88596>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso88597>
+\@@_declare_eight_bit_encoding:nnn { iso88597 }
+ {
+ { A1 } { 2018 }
+ { A2 } { 2019 }
+ { A4 } { 20AC }
+ { A5 } { 20AF }
+ { AA } { 037A }
+ { AF } { 2015 }
+ { B4 } { 0384 }
+ { B5 } { 0385 }
+ { B6 } { 0386 }
+ { B8 } { 0388 }
+ { B9 } { 0389 }
+ { BA } { 038A }
+ { BC } { 038C }
+ { BE } { 038E }
+ { BF } { 038F }
+ { C0 } { 0390 }
+ { C1 } { 0391 }
+ { C2 } { 0392 }
+ { C3 } { 0393 }
+ { C4 } { 0394 }
+ { C5 } { 0395 }
+ { C6 } { 0396 }
+ { C7 } { 0397 }
+ { C8 } { 0398 }
+ { C9 } { 0399 }
+ { CA } { 039A }
+ { CB } { 039B }
+ { CC } { 039C }
+ { CD } { 039D }
+ { CE } { 039E }
+ { CF } { 039F }
+ { D0 } { 03A0 }
+ { D1 } { 03A1 }
+ { D3 } { 03A3 }
+ { D4 } { 03A4 }
+ { D5 } { 03A5 }
+ { D6 } { 03A6 }
+ { D7 } { 03A7 }
+ { D8 } { 03A8 }
+ { D9 } { 03A9 }
+ { DA } { 03AA }
+ { DB } { 03AB }
+ { DC } { 03AC }
+ { DD } { 03AD }
+ { DE } { 03AE }
+ { DF } { 03AF }
+ { E0 } { 03B0 }
+ { E1 } { 03B1 }
+ { E2 } { 03B2 }
+ { E3 } { 03B3 }
+ { E4 } { 03B4 }
+ { E5 } { 03B5 }
+ { E6 } { 03B6 }
+ { E7 } { 03B7 }
+ { E8 } { 03B8 }
+ { E9 } { 03B9 }
+ { EA } { 03BA }
+ { EB } { 03BB }
+ { EC } { 03BC }
+ { ED } { 03BD }
+ { EE } { 03BE }
+ { EF } { 03BF }
+ { F0 } { 03C0 }
+ { F1 } { 03C1 }
+ { F2 } { 03C2 }
+ { F3 } { 03C3 }
+ { F4 } { 03C4 }
+ { F5 } { 03C5 }
+ { F6 } { 03C6 }
+ { F7 } { 03C7 }
+ { F8 } { 03C8 }
+ { F9 } { 03C9 }
+ { FA } { 03CA }
+ { FB } { 03CB }
+ { FC } { 03CC }
+ { FD } { 03CD }
+ { FE } { 03CE }
+ }
+ {
+ { AE }
+ { D2 }
+ }
+%</iso88597>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso88598>
+\@@_declare_eight_bit_encoding:nnn { iso88598 }
+ {
+ { AA } { 00D7 }
+ { BA } { 00F7 }
+ { DF } { 2017 }
+ { E0 } { 05D0 }
+ { E1 } { 05D1 }
+ { E2 } { 05D2 }
+ { E3 } { 05D3 }
+ { E4 } { 05D4 }
+ { E5 } { 05D5 }
+ { E6 } { 05D6 }
+ { E7 } { 05D7 }
+ { E8 } { 05D8 }
+ { E9 } { 05D9 }
+ { EA } { 05DA }
+ { EB } { 05DB }
+ { EC } { 05DC }
+ { ED } { 05DD }
+ { EE } { 05DE }
+ { EF } { 05DF }
+ { F0 } { 05E0 }
+ { F1 } { 05E1 }
+ { F2 } { 05E2 }
+ { F3 } { 05E3 }
+ { F4 } { 05E4 }
+ { F5 } { 05E5 }
+ { F6 } { 05E6 }
+ { F7 } { 05E7 }
+ { F8 } { 05E8 }
+ { F9 } { 05E9 }
+ { FA } { 05EA }
+ { FD } { 200E }
+ { FE } { 200F }
+ }
+ {
+ { A1 }
+ { BF }
+ { C0 }
+ { C1 }
+ { C2 }
+ { C3 }
+ { C4 }
+ { C5 }
+ { C6 }
+ { C7 }
+ { C8 }
+ { C9 }
+ { CA }
+ { CB }
+ { CC }
+ { CD }
+ { CE }
+ { CF }
+ { D0 }
+ { D1 }
+ { D2 }
+ { D3 }
+ { D4 }
+ { D5 }
+ { D6 }
+ { D7 }
+ { D8 }
+ { D9 }
+ { DA }
+ { DB }
+ { DC }
+ { DD }
+ { DE }
+ { FB }
+ { FC }
+ }
+%</iso88598>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso88599>
+\@@_declare_eight_bit_encoding:nnn { iso88599 }
+ {
+ { D0 } { 011E }
+ { DD } { 0130 }
+ { DE } { 015E }
+ { F0 } { 011F }
+ { FD } { 0131 }
+ { FE } { 015F }
+ }
+ {
+ }
+%</iso88599>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso885910>
+\@@_declare_eight_bit_encoding:nnn { iso885910 }
+ {
+ { A1 } { 0104 }
+ { A2 } { 0112 }
+ { A3 } { 0122 }
+ { A4 } { 012A }
+ { A5 } { 0128 }
+ { A6 } { 0136 }
+ { A8 } { 013B }
+ { A9 } { 0110 }
+ { AA } { 0160 }
+ { AB } { 0166 }
+ { AC } { 017D }
+ { AE } { 016A }
+ { AF } { 014A }
+ { B1 } { 0105 }
+ { B2 } { 0113 }
+ { B3 } { 0123 }
+ { B4 } { 012B }
+ { B5 } { 0129 }
+ { B6 } { 0137 }
+ { B8 } { 013C }
+ { B9 } { 0111 }
+ { BA } { 0161 }
+ { BB } { 0167 }
+ { BC } { 017E }
+ { BD } { 2015 }
+ { BE } { 016B }
+ { BF } { 014B }
+ { C0 } { 0100 }
+ { C7 } { 012E }
+ { C8 } { 010C }
+ { CA } { 0118 }
+ { CC } { 0116 }
+ { D1 } { 0145 }
+ { D2 } { 014C }
+ { D7 } { 0168 }
+ { D9 } { 0172 }
+ { E0 } { 0101 }
+ { E7 } { 012F }
+ { E8 } { 010D }
+ { EA } { 0119 }
+ { EC } { 0117 }
+ { F1 } { 0146 }
+ { F2 } { 014D }
+ { F7 } { 0169 }
+ { F9 } { 0173 }
+ { FF } { 0138 }
+ }
+ {
+ }
+%</iso885910>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso885911>
+\@@_declare_eight_bit_encoding:nnn { iso885911 }
+ {
+ { A1 } { 0E01 }
+ { A2 } { 0E02 }
+ { A3 } { 0E03 }
+ { A4 } { 0E04 }
+ { A5 } { 0E05 }
+ { A6 } { 0E06 }
+ { A7 } { 0E07 }
+ { A8 } { 0E08 }
+ { A9 } { 0E09 }
+ { AA } { 0E0A }
+ { AB } { 0E0B }
+ { AC } { 0E0C }
+ { AD } { 0E0D }
+ { AE } { 0E0E }
+ { AF } { 0E0F }
+ { B0 } { 0E10 }
+ { B1 } { 0E11 }
+ { B2 } { 0E12 }
+ { B3 } { 0E13 }
+ { B4 } { 0E14 }
+ { B5 } { 0E15 }
+ { B6 } { 0E16 }
+ { B7 } { 0E17 }
+ { B8 } { 0E18 }
+ { B9 } { 0E19 }
+ { BA } { 0E1A }
+ { BB } { 0E1B }
+ { BC } { 0E1C }
+ { BD } { 0E1D }
+ { BE } { 0E1E }
+ { BF } { 0E1F }
+ { C0 } { 0E20 }
+ { C1 } { 0E21 }
+ { C2 } { 0E22 }
+ { C3 } { 0E23 }
+ { C4 } { 0E24 }
+ { C5 } { 0E25 }
+ { C6 } { 0E26 }
+ { C7 } { 0E27 }
+ { C8 } { 0E28 }
+ { C9 } { 0E29 }
+ { CA } { 0E2A }
+ { CB } { 0E2B }
+ { CC } { 0E2C }
+ { CD } { 0E2D }
+ { CE } { 0E2E }
+ { CF } { 0E2F }
+ { D0 } { 0E30 }
+ { D1 } { 0E31 }
+ { D2 } { 0E32 }
+ { D3 } { 0E33 }
+ { D4 } { 0E34 }
+ { D5 } { 0E35 }
+ { D6 } { 0E36 }
+ { D7 } { 0E37 }
+ { D8 } { 0E38 }
+ { D9 } { 0E39 }
+ { DA } { 0E3A }
+ { DF } { 0E3F }
+ { E0 } { 0E40 }
+ { E1 } { 0E41 }
+ { E2 } { 0E42 }
+ { E3 } { 0E43 }
+ { E4 } { 0E44 }
+ { E5 } { 0E45 }
+ { E6 } { 0E46 }
+ { E7 } { 0E47 }
+ { E8 } { 0E48 }
+ { E9 } { 0E49 }
+ { EA } { 0E4A }
+ { EB } { 0E4B }
+ { EC } { 0E4C }
+ { ED } { 0E4D }
+ { EE } { 0E4E }
+ { EF } { 0E4F }
+ { F0 } { 0E50 }
+ { F1 } { 0E51 }
+ { F2 } { 0E52 }
+ { F3 } { 0E53 }
+ { F4 } { 0E54 }
+ { F5 } { 0E55 }
+ { F6 } { 0E56 }
+ { F7 } { 0E57 }
+ { F8 } { 0E58 }
+ { F9 } { 0E59 }
+ { FA } { 0E5A }
+ { FB } { 0E5B }
+ }
+ {
+ { DB }
+ { DC }
+ { DD }
+ { DE }
+ }
+%</iso885911>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso885913>
+\@@_declare_eight_bit_encoding:nnn { iso885913 }
+ {
+ { A1 } { 201D }
+ { A5 } { 201E }
+ { A8 } { 00D8 }
+ { AA } { 0156 }
+ { AF } { 00C6 }
+ { B4 } { 201C }
+ { B8 } { 00F8 }
+ { BA } { 0157 }
+ { BF } { 00E6 }
+ { C0 } { 0104 }
+ { C1 } { 012E }
+ { C2 } { 0100 }
+ { C3 } { 0106 }
+ { C6 } { 0118 }
+ { C7 } { 0112 }
+ { C8 } { 010C }
+ { CA } { 0179 }
+ { CB } { 0116 }
+ { CC } { 0122 }
+ { CD } { 0136 }
+ { CE } { 012A }
+ { CF } { 013B }
+ { D0 } { 0160 }
+ { D1 } { 0143 }
+ { D2 } { 0145 }
+ { D4 } { 014C }
+ { D8 } { 0172 }
+ { D9 } { 0141 }
+ { DA } { 015A }
+ { DB } { 016A }
+ { DD } { 017B }
+ { DE } { 017D }
+ { E0 } { 0105 }
+ { E1 } { 012F }
+ { E2 } { 0101 }
+ { E3 } { 0107 }
+ { E6 } { 0119 }
+ { E7 } { 0113 }
+ { E8 } { 010D }
+ { EA } { 017A }
+ { EB } { 0117 }
+ { EC } { 0123 }
+ { ED } { 0137 }
+ { EE } { 012B }
+ { EF } { 013C }
+ { F0 } { 0161 }
+ { F1 } { 0144 }
+ { F2 } { 0146 }
+ { F4 } { 014D }
+ { F8 } { 0173 }
+ { F9 } { 0142 }
+ { FA } { 015B }
+ { FB } { 016B }
+ { FD } { 017C }
+ { FE } { 017E }
+ { FF } { 2019 }
+ }
+ {
+ }
+%</iso885913>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso885914>
+\@@_declare_eight_bit_encoding:nnn { iso885914 }
+ {
+ { A1 } { 1E02 }
+ { A2 } { 1E03 }
+ { A4 } { 010A }
+ { A5 } { 010B }
+ { A6 } { 1E0A }
+ { A8 } { 1E80 }
+ { AA } { 1E82 }
+ { AB } { 1E0B }
+ { AC } { 1EF2 }
+ { AF } { 0178 }
+ { B0 } { 1E1E }
+ { B1 } { 1E1F }
+ { B2 } { 0120 }
+ { B3 } { 0121 }
+ { B4 } { 1E40 }
+ { B5 } { 1E41 }
+ { B7 } { 1E56 }
+ { B8 } { 1E81 }
+ { B9 } { 1E57 }
+ { BA } { 1E83 }
+ { BB } { 1E60 }
+ { BC } { 1EF3 }
+ { BD } { 1E84 }
+ { BE } { 1E85 }
+ { BF } { 1E61 }
+ { D0 } { 0174 }
+ { D7 } { 1E6A }
+ { DE } { 0176 }
+ { F0 } { 0175 }
+ { F7 } { 1E6B }
+ { FE } { 0177 }
+ }
+ {
+ }
+%</iso885914>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso885915>
+\@@_declare_eight_bit_encoding:nnn { iso885915 }
+ {
+ { A4 } { 20AC }
+ { A6 } { 0160 }
+ { A8 } { 0161 }
+ { B4 } { 017D }
+ { B8 } { 017E }
+ { BC } { 0152 }
+ { BD } { 0153 }
+ { BE } { 0178 }
+ }
+ {
+ }
+%</iso885915>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*iso885916>
+\@@_declare_eight_bit_encoding:nnn { iso885916 }
+ {
+ { A1 } { 0104 }
+ { A2 } { 0105 }
+ { A3 } { 0141 }
+ { A4 } { 20AC }
+ { A5 } { 201E }
+ { A6 } { 0160 }
+ { A8 } { 0161 }
+ { AA } { 0218 }
+ { AC } { 0179 }
+ { AE } { 017A }
+ { AF } { 017B }
+ { B2 } { 010C }
+ { B3 } { 0142 }
+ { B4 } { 017D }
+ { B5 } { 201D }
+ { B8 } { 017E }
+ { B9 } { 010D }
+ { BA } { 0219 }
+ { BC } { 0152 }
+ { BD } { 0153 }
+ { BE } { 0178 }
+ { BF } { 017C }
+ { C3 } { 0102 }
+ { C5 } { 0106 }
+ { D0 } { 0110 }
+ { D1 } { 0143 }
+ { D5 } { 0150 }
+ { D7 } { 015A }
+ { D8 } { 0170 }
+ { DD } { 0118 }
+ { DE } { 021A }
+ { E3 } { 0103 }
+ { E5 } { 0107 }
+ { F0 } { 0111 }
+ { F1 } { 0144 }
+ { F5 } { 0151 }
+ { F7 } { 015B }
+ { F8 } { 0171 }
+ { FD } { 0119 }
+ { FE } { 021B }
+ }
+ {
+ }
+%</iso885916>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx
index ea6c38e6564..7d42697daab 100644
--- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str-format.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3str-format.dtx Copyright (C) 2012 The LaTeX3 Project
+%% File: l3str-format.dtx Copyright (C) 2012-2013 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
@@ -100,7 +100,9 @@
% data should be formatted. The list of allowed \meta{styles}
% depends on the type.
% \end{itemize}
-% The choice of \meta{alignment} |=| is not implemented yet.
+% The choice of \meta{alignment} |=| is only valid for numeric types: in
+% this case the padding is inserted between the sign and the rest of the
+% number.
%
% \section{Formatting various data-types}
%
@@ -173,7 +175,7 @@
% \end{macrocode}
%
% \begin{macrocode}
-%<@@=str>
+%<@@=str_format>
% \end{macrocode}
%
% \begin{macrocode}
@@ -201,11 +203,11 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_if_digit:NTF}
+% \begin{macro}[aux, EXP]{\@@_if_digit:NTF}
% Here we expect |#1| to be a character with category other, or
% \cs{s__stop}.
% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_format_if_digit:N #1 { TF }
+\prg_new_conditional:Npnn \@@_if_digit:N #1 { TF }
{
\if_int_compare:w \c_nine < 1 #1 \exp_stop_f:
\prg_return_true: \else: \prg_return_false: \fi:
@@ -214,27 +216,50 @@
% \end{macro}
%
% \begin{macro}[aux, EXP]
-% {\@@_format_put:nw, \@@_format_put:ow, \@@_format_put:fw}
+% {\@@_put:nw, \@@_put:ow, \@@_put:fw}
% Put |#1| after an \cs{s__stop} delimiter.
% \begin{macrocode}
-\cs_new:Npn \@@_format_put:nw #1 #2 \s__stop { #2 \s__stop #1 }
-\cs_generate_variant:Nn \@@_format_put:nw { o , f }
+\cs_new:Npn \@@_put:nw #1 #2 \s__stop { #2 \s__stop #1 }
+\cs_generate_variant:Nn \@@_put:nw { o , f }
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}[aux, EXP, TF]{\@@_if_in:nN}
+% \begin{macro}[aux, EXP]{\@@_if_in_aux:NN}
+% A copy of \cs{__str_if_contains_char:nNTF} to avoid relying on
+% this weird internal string function.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_in:nN #1#2 { TF }
+ {
+ \@@_if_in_aux:NN #2 #1
+ { #2 \prg_return_false: \exp_after:wN \__prg_break: \else: }
+ \__prg_break_point:
+ }
+\cs_new:Npn \@@_if_in_aux:NN #1#2
+ {
+ \if_charcode:w #1 #2
+ \prg_return_true:
+ \exp_after:wN \__prg_break:
+ \fi:
+ \@@_if_in_aux:NN #1
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \subsection{Parsing a format specification}
%
-% \begin{macro}[aux, EXP]{\@@_format_parse:n}
+% \begin{macro}[aux, EXP]{\@@_parse:n}
% \begin{macro}[aux, EXP]
% {
-% \@@_format_parse_auxi:NN,
-% \@@_format_parse_auxii:nN,
-% \@@_format_parse_auxiii:nN,
-% \@@_format_parse_auxiv:nwN,
-% \@@_format_parse_auxv:nN,
-% \@@_format_parse_auxvi:nwN,
-% \@@_format_parse_auxvii:nN,
-% \@@_format_parse_end:nwn,
+% \@@_parse_auxi:NN,
+% \@@_parse_auxii:nN,
+% \@@_parse_auxiii:nN,
+% \@@_parse_auxiv:nwN,
+% \@@_parse_auxv:nN,
+% \@@_parse_auxvi:nwN,
+% \@@_parse_auxvii:nN,
+% \@@_parse_end:nwn,
% }
% The goal is to parse
% \begin{equation*}
@@ -242,59 +267,59 @@
% [\meta{sign}] [\meta{width}] [.\meta{precision}] [\meta{style}]
% \end{equation*}
% \begin{macrocode}
-\cs_new:Npn \@@_format_parse:n #1
+\cs_new:Npn \@@_parse:n #1
{
- \exp_last_unbraced:Nf \@@_format_parse_auxi:NN
- \@@_to_other:n {#1} \s__stop \s__stop {#1}
+ \exp_last_unbraced:Nf \@@_parse_auxi:NN
+ \__str_to_other:n {#1} \s__stop \s__stop {#1}
}
-\cs_new:Npx \@@_format_parse_auxi:NN #1#2
+\cs_new:Npx \@@_parse_auxi:NN #1#2
{
- \exp_not:N \@@_if_contains_char:nNTF { < > = ^ } #2
- { \exp_not:N \@@_format_parse_auxiii:nN { #1 #2 } }
+ \exp_not:N \@@_if_in:nNTF { < > = ^ } #2
+ { \exp_not:N \@@_parse_auxiii:nN { #1 #2 } }
{
- \exp_not:N \@@_format_parse_auxii:nN
+ \exp_not:N \@@_parse_auxii:nN
{ \c_catcode_other_space_tl } #1 #2
}
}
-\cs_new:Npn \@@_format_parse_auxii:nN #1#2
+\cs_new:Npn \@@_parse_auxii:nN #1#2
{
- \@@_if_contains_char:nNTF { < > = ^ } #2
- { \@@_format_parse_auxiii:nN { #1 #2 } }
- { \@@_format_parse_auxiii:nN { #1 ? } #2 }
+ \@@_if_in:nNTF { < > = ^ } #2
+ { \@@_parse_auxiii:nN { #1 #2 } }
+ { \@@_parse_auxiii:nN { #1 ? } #2 }
}
-\cs_new:Npx \@@_format_parse_auxiii:nN #1#2
+\cs_new:Npx \@@_parse_auxiii:nN #1#2
{
- \exp_not:N \@@_if_contains_char:nNTF
+ \exp_not:N \@@_if_in:nNTF
{ + - \c_catcode_other_space_tl }
#2
- { \exp_not:N \@@_format_parse_auxiv:nwN { #1 #2 } ; }
- { \exp_not:N \@@_format_parse_auxiv:nwN { #1 ? } ; #2 }
+ { \exp_not:N \@@_parse_auxiv:nwN { #1 #2 } ; }
+ { \exp_not:N \@@_parse_auxiv:nwN { #1 ? } ; #2 }
}
-\cs_new:Npn \@@_format_parse_auxiv:nwN #1#2; #3
+\cs_new:Npn \@@_parse_auxiv:nwN #1#2; #3
{
- \@@_format_if_digit:NTF #3
- { \@@_format_parse_auxiv:nwN {#1} #2 #3 ; }
- { \@@_format_parse_auxv:nN { #1 {#2} } #3 }
+ \@@_if_digit:NTF #3
+ { \@@_parse_auxiv:nwN {#1} #2 #3 ; }
+ { \@@_parse_auxv:nN { #1 {#2} } #3 }
}
-\cs_new:Npn \@@_format_parse_auxv:nN #1#2
+\cs_new:Npn \@@_parse_auxv:nN #1#2
{
\token_if_eq_charcode:NNTF . #2
- { \@@_format_parse_auxvi:nwN {#1} 0 ; }
- { \@@_format_parse_auxvii:nN { #1 { } } #2 }
+ { \@@_parse_auxvi:nwN {#1} 0 ; }
+ { \@@_parse_auxvii:nN { #1 { } } #2 }
}
-\cs_new:Npn \@@_format_parse_auxvi:nwN #1#2; #3
+\cs_new:Npn \@@_parse_auxvi:nwN #1#2; #3
{
- \@@_format_if_digit:NTF #3
- { \@@_format_parse_auxvi:nwN {#1} #2 #3 ; }
- { \@@_format_parse_auxvii:nN { #1 {#2} } #3 }
+ \@@_if_digit:NTF #3
+ { \@@_parse_auxvi:nwN {#1} #2 #3 ; }
+ { \@@_parse_auxvii:nN { #1 {#2} } #3 }
}
-\cs_new:Npn \@@_format_parse_auxvii:nN #1#2
+\cs_new:Npn \@@_parse_auxvii:nN #1#2
{
\token_if_eq_meaning:NNTF \s__stop #2
- { \@@_format_parse_end:nwn { #1 ? } #2 }
- { \@@_format_parse_end:nwn { #1 #2 } }
+ { \@@_parse_end:nwn { #1 ? } #2 }
+ { \@@_parse_end:nwn { #1 #2 } }
}
-\cs_new:Npn \@@_format_parse_end:nwn #1 #2 \s__stop \s__stop #3
+\cs_new:Npn \@@_parse_end:nwn #1 #2 \s__stop \s__stop #3
{
\tl_if_empty:nF {#2}
{ \__msg_kernel_expandable_error:nnn { str } { invalid-format } {#3} }
@@ -316,40 +341,40 @@
% padding between the \meta{sign} and the \meta{body}, hence the need to
% keep those separate.
%
-% \begin{macro}[aux, EXP]{\@@_format_align_<:nnnN}
+% \begin{macro}[aux, EXP]{\@@_align_<:nnnN}
% \begin{quote}
-% \cs{@@_format_align_<:nnnN} \Arg{body} \Arg{sign} \Arg{width}
+% \cs{@@_align_<:nnnN} \Arg{body} \Arg{sign} \Arg{width}
% \meta{fill}
% \end{quote}
% Aligning \enquote{\meta{sign} \meta{body}} to the left
% entails appending |#4| the correct number of times. Then convert
% the result to a string.
% \begin{macrocode}
-\cs_new:cpn { @@_format_align_<:nnnN } #1#2#3#4
+\cs_new:cpn { @@_align_<:nnnN } #1#2#3#4
{
\use:nf { #2 #1 }
{
\prg_replicate:nn
- { \int_max:nn { #3 - \@@_count_unsafe:n { #2 #1 } } { 0 } }
+ { \int_max:nn { #3 - \__str_count_unsafe:n { #2 #1 } } { 0 } }
{#4}
}
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_align_>:nnnN}
+% \begin{macro}[aux, EXP]{\@@_align_>:nnnN}
% \begin{quote}
-% \cs{@@_format_align_>:nnnN} \Arg{body} \Arg{sign} \Arg{width}
+% \cs{@@_align_>:nnnN} \Arg{body} \Arg{sign} \Arg{width}
% \meta{fill}
% \end{quote}
% Aligning an \enquote{\meta{sign} \meta{body}} to the right
% entails prepending |#4| the correct number of times. Then convert
% the result to a string.
% \begin{macrocode}
-\cs_new:cpn { @@_format_align_>:nnnN } #1#2#3#4
+\cs_new:cpn { @@_align_>:nnnN } #1#2#3#4
{
\prg_replicate:nn
- { \int_max:nn { #3 - \@@_count_unsafe:n { #2 #1 } } { 0 } }
+ { \int_max:nn { #3 - \__str_count_unsafe:n { #2 #1 } } { 0 } }
{#4}
#2 #1
}
@@ -357,9 +382,9 @@
% \end{macro}
%
% \begingroup\catcode`\^=12
-% \begin{macro}[aux, EXP]{\@@_format_align_^:nnnN}
+% \begin{macro}[aux, EXP]{\@@_align_^:nnnN}
% \begin{quote}
-% \cs{@@_format_align_^:nnnN} \Arg{body} \Arg{sign} \Arg{width}
+% \cs{@@_align_^:nnnN} \Arg{body} \Arg{sign} \Arg{width}
% \meta{fill}
% \end{quote}
% Centering \enquote{\meta{sign} \meta{body}} entails
@@ -367,14 +392,14 @@
% number of |#4| to be added is odd, we add one more after than
% before.
% \begin{macrocode}
-\cs_new:cpn { @@_format_align_^:nnnN } #1#2#3#4
+\cs_new:cpn { @@_align_^:nnnN } #1#2#3#4
{
\use:fnf
{
\prg_replicate:nn
{
\int_max:nn \c_zero
- { #3 - \@@_count_unsafe:n { #2 #1 } - \c_one }
+ { #3 - \__str_count_unsafe:n { #2 #1 } - \c_one }
/ \c_two
}
{#4}
@@ -384,7 +409,7 @@
\prg_replicate:nn
{
\int_max:nn \c_zero
- { #3 - \@@_count_unsafe:n { #2 #1 } }
+ { #3 - \__str_count_unsafe:n { #2 #1 } }
/ \c_two
}
{#4}
@@ -394,21 +419,21 @@
% \end{macro}
% \endgroup
%
-% \begin{macro}[aux, EXP]{\@@_format_align_=:nnnN}
+% \begin{macro}[aux, EXP]{\@@_align_=:nnnN}
% \begin{quote}
-% \cs{@@_format_align_=:nnnN} \Arg{body} \Arg{sign} \Arg{width}
+% \cs{@@_align_=:nnnN} \Arg{body} \Arg{sign} \Arg{width}
% \meta{fill}
% \end{quote}
% The special numeric alignment |=| means that we insert the
% appropriate number of copies of |#4| between the \meta{sign} and the
% \meta{body}. Then convert the result to a string.
% \begin{macrocode}
-\cs_new:cpn { @@_format_align_=:nnnN } #1#2#3#4
+\cs_new:cpn { @@_align_=:nnnN } #1#2#3#4
{
\use:nf {#2}
{
\prg_replicate:nn
- { \int_max:nn { #3 - \@@_count_unsafe:n { #2 #1 } } { 0 } }
+ { \int_max:nn { #3 - \__str_count_unsafe:n { #2 #1 } } { 0 } }
{#4}
}
#1
@@ -420,7 +445,7 @@
% \subsection{Formatting token lists}
%
% \begin{macro}[EXP]{\tl_format:Nn, \tl_format:cn, \tl_format:nn}
-% Call \cs{@@_format_tl:NNNnnNn} to read the parsed \meta{format
+% Call \cs{@@_tl:NNNnnNn} to read the parsed \meta{format
% specification}. Then convert the result to a string.
% \begin{macrocode}
\cs_new_nopar:Npn \tl_format:Nn { \exp_args:No \tl_format:nn }
@@ -429,52 +454,52 @@
{
\tl_to_str:f
{
- \exp_last_unbraced:Nf \@@_format_tl:NNNnnNn
- { \@@_format_parse:n {#2} }
+ \exp_last_unbraced:Nf \@@_tl:NNNnnNn
+ { \@@_parse:n {#2} }
{#1}
}
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_tl:NNNnnNn}
+% \begin{macro}[aux, EXP]{\@@_tl:NNNnnNn}
% \begin{quote}
-% \cs{@@_format_tl:NNNnnNn} \meta{fill} \meta{alignment} \meta{sign}
+% \cs{@@_tl:NNNnnNn} \meta{fill} \meta{alignment} \meta{sign}
% \Arg{width} \Arg{precision} \meta{style} \Arg{token list}
% \end{quote}
% First check that the \meta{alignment} is not |=|, and set the
% default alignment |?| to |<|. Place the modified information after
% a trailing \cs{s__stop} for later retrieval. Then check that there
% was no \meta{sign}. The width will be useful later, store it after
-% \cs{s__stop}. Afterwards, check the \meta{precision}: if it is
-% empty, we will eventually use the whole string, otherwise we will
-% only use a substring, starting at the index $1$, and ending at |#5|.
+% \cs{s__stop}. Afterwards, store the precision, and the function
+% \cs{__str_range_unsafe:nnn} that will be used to extract the first
+% |#5| characters of the string.
% There is a need to use the \enquote{unsafe} function, as otherwise
% leading spaces would get stripped by |f|-expansion. Finally, check
% that the \meta{style} is |?| or |s|.
% \begin{macrocode}
-\cs_new:Npn \@@_format_tl:NNNnnNn #1#2#3#4#5#6
+\cs_new:Npn \@@_tl:NNNnnNn #1#2#3#4#5#6
{
\token_if_eq_charcode:NNTF #2 =
{
\__msg_kernel_expandable_error:nnnn
{ str } { invalid-align-format } {#2} {tl}
- \@@_format_put:nw { #1 < }
+ \@@_put:nw { #1 < }
}
{
\token_if_eq_charcode:NNTF #2 ?
- { \@@_format_put:nw { #1 < } }
- { \@@_format_put:nw { #1 #2 } }
+ { \@@_put:nw { #1 < } }
+ { \@@_put:nw { #1 #2 } }
}
\token_if_eq_charcode:NNF #3 ?
{
\__msg_kernel_expandable_error:nnnn
{ str } { invalid-sign-format } {#3} {tl}
}
- \@@_format_put:nw { {#4} }
+ \@@_put:nw { {#4} }
\tl_if_empty:nTF {#5}
- { \@@_format_put:nw { \use:n { } } }
- { \@@_format_put:nw { \@@_substr_unsafe:nnn { {1} {#5} } } }
+ { \@@_put:nw { \__str_range_unsafe:nnn { {1} {-1} } } }
+ { \@@_put:nw { \__str_range_unsafe:nnn { {1} {#5} } } }
\token_if_eq_charcode:NNF #6 s
{
\token_if_eq_charcode:NNF #6 ?
@@ -483,15 +508,15 @@
{ str } { invalid-style-format } {#6} {tl}
}
}
- \@@_format_tl_s:NNnnNNn
+ \@@_tl_s:NNnnNNn
\s__stop
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_tl_s:NNnnNNn}
+% \begin{macro}[aux, EXP]{\@@_tl_s:NNnnNNn}
% \begin{quote}
-% \cs{@@_format_tl_s:NNnnNNn} \cs{s__stop} \meta{function}
+% \cs{@@_tl_s:NNnnNNn} \cs{s__stop} \meta{function}
% \Arg{arguments} \Arg{width} \meta{fill} \meta{alignment}
% \Arg{token list}
% \end{quote}
@@ -499,13 +524,13 @@
% that |f|-expanding \meta{function} \Arg{other string}
% \meta{arguments} yields the piece of the \meta{other string} that we
% want to output. The \meta{other string} is built from the
-% \meta{token list} by |f|-expanding \cs{@@_to_other:n}.
+% \meta{token list} by |f|-expanding \cs{__str_to_other:n}.
% \begin{macrocode}
-\cs_new:Npn \@@_format_tl_s:NNnnNNn #1#2#3#4#5#6#7
+\cs_new:Npn \@@_tl_s:NNnnNNn #1#2#3#4#5#6#7
{
\exp_args:Nc \exp_args:Nf
- { @@_format_align_#6:nnnN }
- { \exp_args:Nf #2 { \@@_to_other:n {#7} } #3 }
+ { @@_align_#6:nnnN }
+ { \exp_args:Nf #2 { \__str_to_other:n {#7} } #3 }
{ }
{#4} #5
}
@@ -522,29 +547,29 @@
\cs_new:Npn \seq_format:Nn #1#2
{
\tl_to_str:f
- { \@@_format_seq:of {#1} { \@@_format_parse:n {#2} } }
+ { \@@_seq:of {#1} { \@@_parse:n {#2} } }
}
\cs_generate_variant:Nn \seq_format:Nn { c }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_seq:nn, \@@_format_seq:of}
+% \begin{macro}[aux, EXP]{\@@_seq:nn, \@@_seq:of}
% The first argument is the contents of a \texttt{seq} variable. The
% second is a parsed \meta{format specification}. Set up the loop.
% \begin{macrocode}
-\cs_new:Npn \@@_format_seq:nn #1#2
+\cs_new:Npn \@@_seq:nn #1#2
{
- \@@_format_seq_loop:nnNn { } {#2}
+ \@@_seq_loop:nnNn { } {#2}
#1
- { ? \@@_format_seq_end:w } { }
+ { ? \@@_seq_end:w } { }
}
-\cs_generate_variant:Nn \@@_format_seq:nn { of }
+\cs_generate_variant:Nn \@@_seq:nn { of }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_seq_loop:nnNn}
+% \begin{macro}[aux, EXP]{\@@_seq_loop:nnNn}
% \begin{quote}
-% \cs{@@_format_seq_loop:nnNn} \Arg{done} \Arg{parsed format}
+% \cs{@@_seq_loop:nnNn} \Arg{done} \Arg{parsed format}
% \cs{__seq_item:n} \Arg{item}
% \end{quote}
% The first argument is the result of formatting the items read so
@@ -552,52 +577,52 @@
% until we reach the end of the sequence, where |\use_none:n #3| ends
% the loop.
% \begin{macrocode}
-\cs_new:Npn \@@_format_seq_loop:nnNn #1#2#3#4
+\cs_new:Npn \@@_seq_loop:nnNn #1#2#3#4
{
\use_none:n #3
- \exp_args:Nf \@@_format_seq_loop:nnNn
- { \use:nf {#1} { \@@_format_tl:NNNnnNn #2 {#4} } }
+ \exp_args:Nf \@@_seq_loop:nnNn
+ { \use:nf {#1} { \@@_tl:NNNnnNn #2 {#4} } }
{#2}
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_seq_end:w}
+% \begin{macro}[aux, EXP]{\@@_seq_end:w}
% Pick the right piece in the loop above.
% \begin{macrocode}
-\cs_new:Npn \@@_format_seq_end:w #1#2#3#4 { \use_ii:nnn #3 }
+\cs_new:Npn \@@_seq_end:w #1#2#3#4 { \use_ii:nnn #3 }
% \end{macrocode}
% \end{macro}
%
% \subsection{Formatting integers}
%
% \begin{macro}[EXP]{\int_format:nn}
-% Evalute the first argument and feed it to \cs{@@_format_int:nn}.
+% Evalute the first argument and feed it to \cs{@@_int:nn}.
% \begin{macrocode}
\cs_new:Npn \int_format:nn #1
- { \exp_args:Nf \@@_format_int:nn { \int_eval:n {#1} } }
+ { \exp_args:Nf \@@_int:nn { \int_eval:n {#1} } }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_int:nn}
+% \begin{macro}[aux, EXP]{\@@_int:nn}
% Parse the \meta{format specification} and feed it to
-% \cs{@@_format_int:NNNnnNn}. Then convert the result to a string
+% \cs{@@_int:NNNnnNn}. Then convert the result to a string
% \begin{macrocode}
-\cs_new:Npn \@@_format_int:nn #1#2
+\cs_new:Npn \@@_int:nn #1#2
{
\tl_to_str:f
{
- \exp_last_unbraced:Nf \@@_format_int:NNNnnNn
- { \@@_format_parse:n {#2} }
+ \exp_last_unbraced:Nf \@@_int:NNNnnNn
+ { \@@_parse:n {#2} }
{#1}
}
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_int:NNNnnNn}
+% \begin{macro}[aux, EXP]{\@@_int:NNNnnNn}
% \begin{quote}
-% \cs{@@_format_int:NNNnnNn} \meta{fill} \meta{alignment}
+% \cs{@@_int:NNNnnNn} \meta{fill} \meta{alignment}
% \meta{sign} \Arg{width} \Arg{precision} \meta{style} \Arg{integer}
% \end{quote}
% First set the
@@ -611,22 +636,22 @@
% the \meta{precision} was absent. Finally, dispatch depending on the
% \meta{style}.
% \begin{macrocode}
-\cs_new:Npn \@@_format_int:NNNnnNn #1#2#3#4#5#6#7
+\cs_new:Npn \@@_int:NNNnnNn #1#2#3#4#5#6#7
{
\token_if_eq_charcode:NNTF #2 ?
- { \@@_format_put:nw { #1 > } }
- { \@@_format_put:nw { #1 #2 } }
+ { \@@_put:nw { #1 > } }
+ { \@@_put:nw { #1 #2 } }
\int_compare:nNnTF {#7} < \c_zero
- { \@@_format_put:nw { - } }
+ { \@@_put:nw { - } }
{
\str_case:nnn {#3}
{
- { ~ } { \@@_format_put:ow { \c_catcode_other_space_tl } }
- { + } { \@@_format_put:nw { + } }
+ { ~ } { \@@_put:ow { \c_catcode_other_space_tl } }
+ { + } { \@@_put:nw { + } }
}
- { \@@_format_put:nw { { } } }
+ { \@@_put:nw { { } } }
}
- \@@_format_put:nw { {#4} }
+ \@@_put:nw { {#4} }
\tl_if_empty:nF {#5}
{
\__msg_kernel_expandable_error:nnnn
@@ -634,25 +659,25 @@
}
\str_case:nnn {#6}
{
- { ? } { \@@_format_int:NwnnNNn \use:n }
- { d } { \@@_format_int:NwnnNNn \use:n }
- { b } { \@@_format_int:NwnnNNn \int_to_binary:n }
- { o } { \@@_format_int:NwnnNNn \int_to_octal:n }
- { X } { \@@_format_int:NwnnNNn \int_to_hexadecimal:n }
+ { ? } { \@@_int:NwnnNNn \use:n }
+ { d } { \@@_int:NwnnNNn \use:n }
+ { b } { \@@_int:NwnnNNn \int_to_binary:n }
+ { o } { \@@_int:NwnnNNn \int_to_octal:n }
+ { X } { \@@_int:NwnnNNn \int_to_hexadecimal:n }
}
{
\__msg_kernel_expandable_error:nnnn
{ str } { invalid-style-format } {#6} { int }
- \@@_format_int:NwnnNNn \use:n
+ \@@_int:NwnnNNn \use:n
}
\s__stop {#7}
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_int:NwnnNNn}
+% \begin{macro}[aux, EXP]{\@@_int:NwnnNNn}
% \begin{quote}
-% \cs{@@_format_int:NwnnNNn} \meta{function} \cs{s__stop}
+% \cs{@@_int:NwnnNNn} \meta{function} \cs{s__stop}
% \Arg{width} \Arg{sign} \meta{fill} \meta{alignment} \Arg{integer}
% \end{quote}
% Use the |format_align| function corresponding to the
@@ -665,48 +690,48 @@
% \item the \meta{fill} character.
% \end{itemize}
% \begin{macrocode}
-\cs_new:Npn \@@_format_int:NwnnNNn #1#2 \s__stop #3#4#5#6#7
+\cs_new:Npn \@@_int:NwnnNNn #1#2 \s__stop #3#4#5#6#7
{
\exp_args:Nc \exp_args:Nf
- { @@_format_align_#6:nnnN }
+ { @@_align_#6:nnnN }
{ #1 { \int_abs:n {#7} } }
{#4}
{#3} #5
}
% \end{macrocode}
-% ^^A todo: note similarity with \@@_format_tl_s:NNnnNNn
+% ^^A todo: note similarity with \@@_tl_s:NNnnNNn
% \end{macro}
%
% \subsection{Formatting floating points}
%
% \begin{macro}[EXP]{\fp_format:nn}
% Evalute the first argument to an internal floating point number, and
-% feed it to \cs{@@_format_fp:nn}.
+% feed it to \cs{@@_fp:nn}.
% \begin{macrocode}
\cs_new:Npn \fp_format:nn #1
- { \exp_args:Nf \@@_format_fp:nn { \__fp_parse:n {#1} } }
+ { \exp_args:Nf \@@_fp:nn { \__fp_parse:n {#1} } }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_fp:nn}
+% \begin{macro}[aux, EXP]{\@@_fp:nn}
% Parse the \meta{format specification} and feed it to
-% \cs{@@_format_fp:NNNnnNn}. Then convert the result to a string
+% \cs{@@_fp:NNNnnNn}. Then convert the result to a string
% \begin{macrocode}
-\cs_new:Npn \@@_format_fp:nn #1#2
+\cs_new:Npn \@@_fp:nn #1#2
{
\tl_to_str:f
{
- \exp_last_unbraced:Nf \@@_format_fp:NNNnnNw
- { \@@_format_parse:n {#2} }
+ \exp_last_unbraced:Nf \@@_fp:NNNnnNw
+ { \@@_parse:n {#2} }
#1
}
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_fp:NNNnnNw}
+% \begin{macro}[aux, EXP]{\@@_fp:NNNnnNw}
% \begin{quote}
-% \cs{@@_format_fp:NNNnnNw} \meta{fill} \meta{alignment}
+% \cs{@@_fp:NNNnnNw} \meta{fill} \meta{alignment}
% \meta{format sign} \Arg{width} \Arg{precision} \meta{style}
% \cs{s__fp} \cs{__fp_chk:w} \meta{fp type} \meta{fp sign} \meta{fp
% body} |;|
@@ -723,37 +748,37 @@
% (default precision). Finally, dispatch depending on the
% \meta{style}.
% \begin{macrocode}
-\cs_new:Npn \@@_format_fp:NNNnnNw
+\cs_new:Npn \@@_fp:NNNnnNw
#1#2#3#4#5#6 \s__fp \__fp_chk:w #7 #8
{
\token_if_eq_charcode:NNTF #2 ?
- { \@@_format_put:nw { #1 > } }
- { \@@_format_put:nw { #1 #2 } }
+ { \@@_put:nw { #1 > } }
+ { \@@_put:nw { #1 #2 } }
\token_if_eq_meaning:NNTF 2 #8
- { \@@_format_put:nw { - } }
+ { \@@_put:nw { - } }
{
\str_case:nnn {#3}
{
- { ~ } { \@@_format_put:ow { \c_catcode_other_space_tl } }
- { + } { \@@_format_put:nw { + } }
+ { ~ } { \@@_put:ow { \c_catcode_other_space_tl } }
+ { + } { \@@_put:nw { + } }
}
- { \@@_format_put:nw { { } } }
+ { \@@_put:nw { { } } }
}
- \@@_format_put:nw { {#4} }
+ \@@_put:nw { {#4} }
\tl_if_empty:nTF {#5}
- { \@@_format_put:nw { { 6} } }
- { \@@_format_put:nw { {#5} } }
+ { \@@_put:nw { { 6} } }
+ { \@@_put:nw { {#5} } }
\str_case:nnn {#6}
{
- { e } { \@@_format_fp:wnnnNNw \@@_format_fp_e:wn }
- { f } { \@@_format_fp:wnnnNNw \@@_format_fp_f:wn }
- { g } { \@@_format_fp:wnnnNNw \@@_format_fp_g:wn }
- { ? } { \@@_format_fp:wnnnNNw \@@_format_fp_g:wn }
+ { e } { \@@_fp:wnnnNNw \@@_fp_e:wn }
+ { f } { \@@_fp:wnnnNNw \@@_fp_f:wn }
+ { g } { \@@_fp:wnnnNNw \@@_fp_g:wn }
+ { ? } { \@@_fp:wnnnNNw \@@_fp_g:wn }
}
{
\__msg_kernel_expandable_error:nnnn
{ str } { invalid-style-format } {#6} { fp }
- \@@_format_fp:wnnnNNw \@@_format_fp_g:wn
+ \@@_fp:wnnnNNw \@@_fp_g:wn
}
\s__stop
\s__fp \__fp_chk:w #7 #8
@@ -761,19 +786,19 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_fp:wnnnNNw}
+% \begin{macro}[aux, EXP]{\@@_fp:wnnnNNw}
% \begin{quote}
-% \cs{@@_format_fp:wnnnNNw} \meta{formatting function} \cs{s__stop}
+% \cs{@@_fp:wnnnNNw} \meta{formatting function} \cs{s__stop}
% \Arg{precision} \Arg{width} \Arg{sign} \meta{fill}
% \meta{alignment} \cs{s__fp} \cs{__fp_chk:w} \meta{fp type}
% \meta{fp sign} \meta{fp body} |;|
% \end{quote}
% \begin{macrocode}
-\cs_new:Npn \@@_format_fp:wnnnNNw
+\cs_new:Npn \@@_fp:wnnnNNw
#1 \s__stop #2 #3 #4 #5#6 #7 ;
{
\exp_args:Nc \exp_args:Nf
- { @@_format_align_#6:nnnN }
+ { @@_align_#6:nnnN }
{ #1 #7 ; {#2} }
{#4}
{#3} #5
@@ -781,17 +806,17 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_fp_round:wn}
+% \begin{macro}[aux, EXP]{\@@_fp_round:wn}
% Round the given floating point (not its absolute value, to play
% nicely with unusual rounding modes).
% \begin{macrocode}
-\cs_new:Npn \@@_format_fp_round:wn #1 ; #2
+\cs_new:Npn \@@_fp_round:wn #1 ; #2
{ \__fp_parse:n { round ( #1; , #2 - \__fp_exponent:w #1; ) } }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_fp_e:wn}
-% \begin{macro}[aux, EXP]{\@@_format_fp_e_aux:wn}
+% \begin{macro}[aux, EXP]{\@@_fp_e:wn}
+% \begin{macro}[aux, EXP]{\@@_fp_e_aux:wn}
% With the |e| type, first filter out special cases. In the normal
% case, round to |#4+1| significant figures (one before the decimal
% separator, |#4| after).
@@ -801,7 +826,7 @@
\tl_to_lowercase:n
{
\group_end:
- \cs_new:Npn \@@_format_fp_e:wn \s__fp \__fp_chk:w #1#2#3 ; #4
+ \cs_new:Npn \@@_fp_e:wn \s__fp \__fp_chk:w #1#2#3 ; #4
{
\int_case:nnn {#1}
{
@@ -810,26 +835,26 @@
{3} { nan }
}
{
- \exp_last_unbraced:Nf \@@_format_fp_e_aux:wn
- \@@_format_fp_round:wn \s__fp \__fp_chk:w #1#2#3 ; { #4 + 1 }
+ \exp_last_unbraced:Nf \@@_fp_e_aux:wn
+ \@@_fp_round:wn \s__fp \__fp_chk:w #1#2#3 ; { #4 + 1 }
{#4}
}
}
- \cs_new:Npn \@@_format_fp_e_aux:wn
+ \cs_new:Npn \@@_fp_e_aux:wn
\s__fp \__fp_chk:w #1#2 #3 #4#5#6#7 ; #8
{
- \@@_format_put:fw { \int_eval:n { #3 - 1 } }
- \@@_format_put:nw { e }
+ \@@_put:fw { \int_eval:n { #3 - 1 } }
+ \@@_put:nw { e }
\int_compare:nNnTF {#8} > \c_sixteen
{
- \@@_format_put:fw { \prg_replicate:nn { #8 - \c_fifteen } {0} }
- \@@_format_put:fw { \use_none:n #4#5#6#7 }
+ \@@_put:fw { \prg_replicate:nn { #8 - \c_fifteen } {0} }
+ \@@_put:fw { \use_none:n #4#5#6#7 }
}
{
- \@@_format_put:fw
- { \str_substr:nnn { #4#5#6#7 0 } { 2 } { #8 + 1 } }
+ \@@_put:fw
+ { \str_range:nnn { #4#5#6#7 0 } { 2 } { #8 + 1 } }
}
- \@@_format_put:fw { \use_i:nnnn #4 . }
+ \@@_put:fw { \use_i:nnnn #4 . }
\use_none:n \s__stop
}
}
@@ -837,12 +862,12 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_fp_f:wn}
-% \begin{macro}[aux, EXP]{\@@_format_fp_f_aux:wwwn}
+% \begin{macro}[aux, EXP]{\@@_fp_f:wn}
+% \begin{macro}[aux, EXP]{\@@_fp_f_aux:wwwn}
% With the |f| type, first filter out special cases. In the normal
% case, round to |#4| (absolute) decimal places.
% \begin{macrocode}
-\cs_new:Npn \@@_format_fp_f:wn \s__fp \__fp_chk:w #1#2#3 ; #4
+\cs_new:Npn \@@_fp_f:wn \s__fp \__fp_chk:w #1#2#3 ; #4
{
\int_case:nnn {#1}
{
@@ -851,25 +876,25 @@
{3} { nan }
}
{
- \exp_last_unbraced:Nf \@@_format_fp_f_aux:wwwn
+ \exp_last_unbraced:Nf \@@_fp_f_aux:wwwn
\fp_to_decimal:n
{ abs ( round ( \s__fp \__fp_chk:w #1#2#3 ; , #4 ) ) }
. . ;
{#4}
}
}
-\cs_new:Npn \@@_format_fp_f_aux:wwwn #1 . #2 . #3 ; #4
+\cs_new:Npn \@@_fp_f_aux:wwwn #1 . #2 . #3 ; #4
{
\use:nf
{ #1 . #2 }
- { \prg_replicate:nn { #4 - \@@_count_unsafe:n {#2} } {0} }
+ { \prg_replicate:nn { #4 - \__str_count_unsafe:n {#2} } {0} }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[aux, EXP]{\@@_format_fp_g:wn}
-% \begin{macro}[aux, EXP]{\@@_format_fp_g_aux:wn}
+% \begin{macro}[aux, EXP]{\@@_fp_g:wn}
+% \begin{macro}[aux, EXP]{\@@_fp_g_aux:wn}
% With the |g| type, first filter out special cases. In the normal
% case, round to |#4| significant figures, then test the exponent: if
% $-4\leq \meta{exponent} < \meta{precision}$, use the presentation
@@ -880,7 +905,7 @@
% \cs{fp_to_decimal:n} and \cs{fp_to_scientific:n}, acting on the
% (absolute value of the) rounded value.
% \begin{macrocode}
-\cs_new:Npn \@@_format_fp_g:wn \s__fp \__fp_chk:w #1#2 ; #3
+\cs_new:Npn \@@_fp_g:wn \s__fp \__fp_chk:w #1#2 ; #3
{
\int_case:nnn {#1}
{
@@ -889,13 +914,13 @@
{3} { nan }
}
{
- \exp_last_unbraced:Nf \@@_format_fp_g_aux:wn
- \@@_format_fp_round:wn \s__fp \__fp_chk:w #1#2 ;
+ \exp_last_unbraced:Nf \@@_fp_g_aux:wn
+ \@@_fp_round:wn \s__fp \__fp_chk:w #1#2 ;
{ \int_max:nn {1} {#3} }
{ \int_max:nn {1} {#3} }
}
}
-\cs_new:Npn \@@_format_fp_g_aux:wn #1; #2
+\cs_new:Npn \@@_fp_g_aux:wn #1; #2
{
\int_compare:nNnTF { \__fp_exponent:w #1; } < { -3 }
{ \fp_to_scientific:n }
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx
index 301682c64be..0a4d72afd2f 100644
--- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3str.dtx Copyright (C) 2011-2012 The LaTeX3 Project
+%% File: l3str.dtx Copyright (C) 2011-2013 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
@@ -35,14 +35,13 @@
%
%<*driver|package>
\RequirePackage{expl3}
-\GetIdInfo$Id: l3str.dtx 4339 2012-11-24 19:16:43Z joseph $
+\GetIdInfo$Id: l3str.dtx 4452 2013-01-20 10:18:32Z joseph $
{L3 Experimental strings}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\usepackage{amsmath}
\begin{document}
- \tableofcontents
\DocInput{\jobname.dtx}
\end{document}
%</driver>
@@ -67,8 +66,9 @@
% \date{Released \ExplFileDate}
%
% \maketitle
+%
+% \tableofcontents
%
-% \newcommand{\hexnum}[1]{\text{\texttt{\char`\"}#1}}
% \begin{documentation}
%
% \LaTeX3 provides a set of functions to manipulate token lists
@@ -76,42 +76,39 @@
% characters.
%
% String variables are simply specialised token lists, but by convention
-% should be named with the suffix \texttt{\ldots str}. Such variables
+% should be named with the suffix \texttt{\ldots{}str}. Such variables
% should contain characters with category code $12$ (other), except
-% spaces, which have category code $10$ (blank space). All the functions
-% in this module first convert their argument to a string for internal
-% processing, and will not treat a token list or the corresponding
-% string representation differently.
+% spaces, which have category code $10$ (blank space). All the
+% functions in this module which accept a token list argument first
+% convert it to a string using \cs{tl_to_str:n} for internal processing,
+% and will not treat a token list or the corresponding string
+% representation differently.
%
-% Most functions in this module come in three flavours:
+% Most expandable functions in this module come in three flavours:
% \begin{itemize}
-% \item \cs{str_...:N...}, which expect a token list or string
+% \item \cs{str_...:N}, which expect a token list or string
% variable as their argument;
-% \item \cs{str_...:n...}, taking any token list (or string) as an
+% \item \cs{str_...:n}, taking any token list (or string) as an
% argument;
-% \item \cs{str_..._ignore_spaces:n...}, which ignores any space
-% encountered during the operation: these functions are faster than
-% those which take care of escaping spaces appropriately;
+% \item \cs{str_..._ignore_spaces:n}, which ignores any space
+% encountered during the operation: these functions are typically
+% faster than those which take care of escaping spaces
+% appropriately.
% \end{itemize}
%
% \section{Building strings}
%
-% \begin{variable}{\c_max_char_int}
-% The maximum valid character code, $255$ for pdf\TeX{}, and $1114111$
-% for \XeTeX{} and \LuaTeX{}.
-% \end{variable}
-%
% \begin{variable}
% {
% \c_backslash_str,
-% \c_lbrace_str,
-% \c_rbrace_str,
+% \c_left_brace_str,
+% \c_right_brace_str,
% \c_hash_str,
% \c_tilde_str,
% \c_percent_str
% }
-% Constant strings, containing a single character, with category code
-% $12$. Any character can be accessed as \cs{iow_char:N}
+% Constant strings, containing a single character token, with category
+% code $12$. Any character can be accessed as \cs{iow_char:N}
% |\|\meta{character}.
% \end{variable}
%
@@ -121,16 +118,31 @@
% \cs{tl_to_str:n} \Arg{token list}
% \end{syntax}
% Converts the \meta{token list} to a \meta{string}, leaving the
-% resulting tokens in the input stream.
+% resulting character tokens in the input stream.
% \begin{texnote}
-% The string representation of a token list may depend on the
-% category codes in effect when it is evaluated, and the value of
-% the \tn{escapechar}: for instance |\tl_to_str:n {\a}| normally
-% produces the three character \enquote{backslash},
-% \enquote{lower-case a}, \enquote{space}, but it may also produce
-% $1$ or $2$ characters depending on the escape character, and the
-% category code of \texttt{a}. This impacts almost all functions in
-% the module, which use \cs{tl_to_str:n} internally.
+% Converting a \meta{token list} to a \meta{string} yields a
+% concatenation of the string representations of every token in the
+% \meta{token list}.
+% The string representation of a control sequence is
+% \begin{itemize}
+% \item an escape character, whose character code is given by the
+% internal parameter \tn{escapechar}, absent if the
+% \tn{escapechar} is negative;
+% \item the control sequence name, as defined by \cs{cs_to_str:N};
+% \item a space, unless the control sequence name is a single
+% character whose category at the time of expansion of
+% \cs{tl_to_str:n} is not \enquote{letter}.
+% \end{itemize}
+% The string representation of an explicit character token is that
+% character, doubled in the case of (explicit) macro parameter
+% characters (normally |#|).
+% In particular, the string representation of a token list may
+% depend on the category codes in effect when it is evaluated, and
+% the value of the \tn{escapechar}: for instance |\tl_to_str:n {\a}|
+% normally produces the three character \enquote{backslash},
+% \enquote{lower-case a}, \enquote{space}, but it may also produce a
+% single \enquote{lower-case a} if the escape character is negative
+% and \texttt{a} is currently not a letter.
% \end{texnote}
% \end{function}
%
@@ -139,7 +151,7 @@
% \cs{str_new:N} \meta{str~var}
% \end{syntax}
% Creates a new \meta{str~var} or raises an error if the name is
-% already taken. The declaration is global. The \meta{str~var} will
+% already taken. The declaration is global. The \meta{str~var} will
% initially be empty.
% \end{function}
%
@@ -148,7 +160,7 @@
% \cs{str_const:Nn} \meta{str~var} \Arg{token list}
% \end{syntax}
% Creates a new constant \meta{str~var} or raises an error if the name
-% is already taken. The value of the \meta{str~var} will be set
+% is already taken. The value of the \meta{str~var} will be set
% globally to the \meta{token list}, converted to a string.
% \end{function}
%
@@ -201,13 +213,12 @@
% \begin{syntax}
% \cs{str_count:n} \Arg{token list}
% \end{syntax}
-% Leaves the number of tokens in the string representation of
-% \meta{token list}
-% in the input stream as an integer denotation. The functions differ
-% in their treatment of spaces. In the case of \cs{str_count:N} and
-% \cs{str_count:n}, all characters including spaces are counted. The
-% \cs{str_count_ignore_spaces:n} leaves the number of non-space
-% characters in the input stream.
+% Leaves in the input stream the number of characters in the string
+% representation of \meta{token list}, as an integer denotation. The
+% functions differ in their treatment of spaces. In the case of
+% \cs{str_count:N} and \cs{str_count:n}, all characters including
+% spaces are counted. The \cs{str_count_ignore_spaces:n} function
+% leaves the number of non-space characters in the input stream.
% \end{function}
%
% \begin{function}[EXP]{\str_count_spaces:N, \str_count_spaces:n}
@@ -226,14 +237,14 @@
% \end{syntax}
% Converts the \meta{token list} into a \meta{string}. The first
% character in the \meta{string} is then left in the input stream,
-% with category code \enquote{other}. The functions differ in their
-% treatment of spaces. In the case of \cs{str_head:N} and
-% \cs{str_head:n}, a leading space is returned with category code $10$
-% (blank space). The \cs{str_head_ignore_spaces:n} function leaves
-% the first non-space character in the input stream. If the
-% \meta{token list} is empty (or blank in the case of the
-% \texttt{_ignore_spaces} variant), then nothing is left on the input
-% stream.
+% with category code \enquote{other}. The functions differ if the
+% first character is a space: \cs{str_head:N} and \cs{str_head:n}
+% return a space token with category code~$10$ (blank space), while
+% the \cs{str_head_ignore_spaces:n} function ignores this space
+% character and leaves the first non-space character in the input
+% stream. If the \meta{string} is empty (or only contains spaces in
+% the case of the \texttt{_ignore_spaces} function), then nothing is
+% left on the input stream.
% \end{function}
%
% \begin{function}[EXP]{\str_tail:N, \str_tail:n, \str_tail_ignore_spaces:n}
@@ -257,35 +268,35 @@
% \end{syntax}
% Converts the \meta{token list} to a \meta{string}, and leaves in the
% input stream the character in position \meta{integer expression} of
-% the \meta{string}. In the case of \cs{str_item:Nn} and
-% \cs{str_item:nn}, all characters including spaces are taken into
-% account. The \cs{str_item_ignore_spaces:nn} function skips spaces
-% in its argument. If the \meta{integer expression} is negative,
+% the \meta{string}, starting at $1$ for the first (left-most)
+% character. In the case of \cs{str_item:Nn} and \cs{str_item:nn},
+% all characters including spaces are taken into account. The
+% \cs{str_item_ignore_spaces:nn} function skips spaces when counting
+% characters. If the \meta{integer expression} is negative,
% characters are counted from the end of the \meta{string}. Hence,
-% $-1$ is the right-most character, \emph{etc.}, while $1$ is the
-% first (left-most) character.
+% $-1$ is the right-most character, \emph{etc.}
% \end{function}
%
% \begin{function}[EXP]
-% {\str_substr:Nnn, \str_substr:nnn, \str_substr_ignore_spaces:nnn}
+% {\str_range:Nnn, \str_range:nnn, \str_range_ignore_spaces:nnn}
% \begin{syntax}
-% \cs{str_substr:nnn} \Arg{token list} \Arg{start index} \Arg{end index}
+% \cs{str_range:nnn} \Arg{token list} \Arg{start index} \Arg{end index}
% \end{syntax}
% Converts the \meta{token list} to a \meta{string}, and leaves in the
-% input stream the characters from the \meta{start index} inclusive to
-% the \meta{end index} exclusive. Note that the token count of the
-% substring is equal to the difference between the two \meta{indices}.
-% If either of \meta{start index} or \meta{end index} is negative,
-% then it is incremented by the token count of the list. If either of
-% \meta{start index} or \meta{end index} is empty, it is replaced by
-% the corresponding end-point of the string. Both \meta{start index}
-% and \meta{end index} count from $1$ for the first (left most)
-% character. For instance,
+% input stream the characters from the \meta{start index} to the
+% \meta{end index} inclusive. Positive \meta{indices} are counted
+% from the start of the string, $1$~being the first character, and
+% negative \meta{indices} are counted from the end of the string,
+% $-1$~being the last character. If either of \meta{start index} or
+% \meta{end index} is~$0$, the result is empty. For instance,
% \begin{verbatim}
-% \iow_term:x { \str_substr:nnn { abcdef } { 2 } { 5 } }
-% \iow_term:x { \str_substr:nnn { abcdef } { -4 } { } }
+% \iow_term:x { \str_range:nnn { abcdef } { 2 } { 5 } }
+% \iow_term:x { \str_range:nnn { abcdef } { -4 } { -1 } }
+% \iow_term:x { \str_range:nnn { abcdef } { -2 } { -1 } }
+% \iow_term:x { \str_range:nnn { abcdef } { 0 } { -1 } }
% \end{verbatim}
-% will print \texttt{bcd} and \texttt{cdef} to the terminal.
+% will print \texttt{bcd}, \texttt{cdef}, \texttt{ef}, and an empty
+% line to the terminal.
% \end{function}
%
% \section{String conditionals}
@@ -299,9 +310,10 @@
% \cs{str_if_eq_p:nn} \Arg{tl_1} \Arg{tl_2}
% \cs{str_if_eq:nnTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code}
% \end{syntax}
-% Compares the two \meta{token lists} on a character by character
-% basis, and is \texttt{true} if the two lists contain the same
-% characters in the same order. Thus for example
+% Compares the string representations of the two \meta{token lists} on
+% a character by character basis, and is \texttt{true} if the two
+% lists contain the same characters in the same order. Thus for
+% example
% \begin{verbatim}
% \str_if_eq_p:no { abc } { \tl_to_str:n { abc } }
% \end{verbatim}
@@ -387,211 +399,63 @@
% code and so should only be used for short-term storage.
% \end{variable}
%
-% \section{Encoding functions}
-%
-% Traditionally, string encodings only specify how strings of characters
-% should be stored as bytes. However, the resulting lists of bytes are
-% often to be used in contexts where only a restricted subset of bytes
-% are permitted (\emph{e.g.}, \textsc{pdf} string objects,
-% \textsc{url}s). Hence, storing a string of characters is done in two
-% steps.
-% \begin{itemize}
-% \item The code points (\enquote{character codes}) are expressed as
-% bytes following a given \enquote{encoding}. This can be
-% \textsc{utf-16}, \textsc{iso 8859-1}, \emph{etc.} See
-% Table~\ref{tab:encodings} for a list of supported
-% encodings.\footnote{Encodings and escapings will be added as they
-% are requested.}
-% \item Bytes are translated to \TeX{} tokens through a given
-% \enquote{escaping}. Those are defined for the most part by the
-% \texttt{pdf} file format. See Table~\ref{tab:escapings} for a
-% list of escaping methods supported.\footnotemark
-% \end{itemize}
-%
-% \begin{table}\centering
-% \caption{\label{tab:encodings}Supported encodings.
-% Non-alphanumeric characters are ignored,
-% and capital letters are lower-cased
-% before searching for the encoding in this list.}
-% \begin{tabular}{cc}
-% \toprule
-% \meta{Encoding} & description \\
-% \midrule
-% \texttt{utf8} & \textsc{utf-8} \\
-% \texttt{utf16} & \textsc{utf-16}, with byte-order mark \\
-% \texttt{utf16be} & \textsc{utf-16}, big-endian \\
-% \texttt{utf16le} & \textsc{utf-16}, little-endian \\
-% \texttt{utf32} & \textsc{utf-32}, with byte-order mark \\
-% \texttt{utf32be} & \textsc{utf-32}, big-endian \\
-% \texttt{utf32le} & \textsc{utf-32}, little-endian \\
-% \texttt{iso88591}, \texttt{latin1} & \textsc{iso 8859-1} \\
-% \texttt{iso88592}, \texttt{latin2} & \textsc{iso 8859-2} \\
-% \texttt{iso88593}, \texttt{latin3} & \textsc{iso 8859-3} \\
-% \texttt{iso88594}, \texttt{latin4} & \textsc{iso 8859-4} \\
-% \texttt{iso88595} & \textsc{iso 8859-5} \\
-% \texttt{iso88596} & \textsc{iso 8859-6} \\
-% \texttt{iso88597} & \textsc{iso 8859-7} \\
-% \texttt{iso88598} & \textsc{iso 8859-8} \\
-% \texttt{iso88599}, \texttt{latin5} & \textsc{iso 8859-9} \\
-% \texttt{iso885910}, \texttt{latin6} & \textsc{iso 8859-10} \\
-% \texttt{iso885911} & \textsc{iso 8859-11} \\
-% \texttt{iso885913}, \texttt{latin7} & \textsc{iso 8859-13} \\
-% \texttt{iso885914}, \texttt{latin8} & \textsc{iso 8859-14} \\
-% \texttt{iso885915}, \texttt{latin9} & \textsc{iso 8859-15} \\
-% \texttt{iso885916}, \texttt{latin10} & \textsc{iso 8859-16} \\
-% \midrule
-% Empty & Native (Unicode) string. \\
-% \bottomrule
-% \end{tabular}
-% \end{table}
-%
-% \begin{table}\centering
-% \caption{\label{tab:escapings}Supported escapings.
-% Non-alphanumeric characters are ignored,
-% and capital letters are lower-cased
-% before searching for the escaping in this list.}
-% \begin{tabular}{cc}
-% \toprule
-% \meta{Escaping} & description \\
-% \midrule
-% \texttt{bytes}, or empty
-% & arbitrary bytes \\
-% \texttt{hex}, \texttt{hexadecimal}
-% & byte $=$ two hexadecimal digits \\
-% \texttt{name}
-% & see \tn{pdfescapename} \\
-% \texttt{string}
-% & see \tn{pdfescapestring} \\
-% \texttt{url}
-% & encoding used in \textsc{url}s \\
-% \bottomrule
-% \end{tabular}
-% \end{table}
-%
-% \begin{function}{\str_set_convert:Nnnn,\str_gset_convert:Nnnn}
-% \begin{syntax}
-% \cs{str_set_convert:Nnnn} \meta{str~var} \Arg{string} \Arg{name~1} \Arg{name~2}
-% \end{syntax}
-% This function converts the \meta{string} from the encoding given by
-% \meta{name~1} to the encoding given by \meta{name~2}, and stores the
-% result in the \meta{str~var}. Each \meta{name} can have the form
-% \meta{encoding} or \meta{encoding}\texttt{/}\meta{escaping}, where
-% the possible values of \meta{encoding} and \meta{escaping} are given
-% in Tables~\ref{tab:encodings} and~\ref{tab:escapings}, respectively.
-% The default escaping is to input and output bytes directly. The
-% special case of an empty \meta{name} indicates the use of
-% \enquote{native} strings, 8-bit for pdf\TeX{}, and Unicode strings
-% for the other two engines.
-%
-% For example,
-% \begin{verbatim}
-% \str_set_convert:Nnnn \l_foo_str { Hello! } { } { utf16/hex }
-% \end{verbatim}
-% results in the variable \cs{l_foo_str} holding the string
-% \texttt{FEFF00480065006C006C006F0021}. This is obtained by
-% converting each character in the (native) string \texttt{Hello!} to
-% the \textsc{utf-16} encoding, and expressing each byte as a pair of
-% hexadecimal digits. Note the presence of a (big-endian) byte order
-% mark \hexnum{FEFF}, which can be avoided by specifying the encoding
-% \texttt{utf16be/hex}.
-%
-% An error is raised if the \meta{string} is not valid according to
-% the \meta{escaping~1} and \meta{encoding~1}, or if it cannot be
-% reencoded in the \meta{encoding~2} and \meta{escaping~2} (for
-% instance, if a character does not exist in the \meta{encoding~2}).
-% Erroneous input is replaced by the Unicode replacement character
-% \hexnum{FFFD}, and characters which cannot be reencoded are replaced
-% by either the replacement character \hexnum{FFFD} if it exists in
-% the \meta{encoding~2}, or an encoding-specific replacement
-% character, or the question mark character.
-% \end{function}
-%
-% \begin{function}[TF]{\str_set_convert:Nnnn,\str_gset_convert:Nnnn}
-% \begin{syntax}
-% \cs{str_set_convert:NnnnTF} \meta{str~var} \Arg{string} \Arg{name~1} \Arg{name~2} \Arg{true code} \Arg{false code}
-% \end{syntax}
-% As \cs{str_set_convert:Nnnn}, converts the \meta{string} from the
-% encoding given by \meta{name~1} to the encoding given by
-% \meta{name~2}, and assigns the result to \meta{str~var}. Contrarily
-% to \cs{str_set_convert:Nnnn}, the conditional variant does not raise
-% errors in case the \meta{string} is not valid according to the
-% \meta{name~1} encoding, or cannot be expressed in the \meta{name~2}
-% encoding. Instead, the \meta{false code} is performed.
-% \end{function}
-%
-% \section{Internal string functions}
+% \section{Internal \pkg{l3str} functions}
%
-% \begin{function}{\__str_gset_other:Nn}
+% \begin{function}[EXP]{\__str_to_other:n}
% \begin{syntax}
-% \cs{__str_gset_other:Nn} \meta{tl~var} \Arg{token list}
+% \cs{__str_to_other:n} \Arg{token list}
% \end{syntax}
-% Converts the \meta{token list} to an \meta{other string}, where
-% spaces have category code \enquote{other}, and assigns the result to
-% the \meta{tl~var}, globally.
+% Converts the \meta{token list} to a \meta{other string}, where
+% spaces have category code \enquote{other}. This function can be
+% \texttt{f}-expanded without fear of losing a leading space, since
+% spaces do not have category code $10$ in its result. It takes a
+% time quadratic in the character count of the string, but there exist
+% non-expandable ways to reach linear time.
% \end{function}
%
-% \begin{function}{\__str_hexadecimal_use:NTF}
+% \begin{function}[EXP]{\__str_count_unsafe:n}
% \begin{syntax}
-% \cs{__str_hexadecimal_use:NTF} \meta{token} \Arg{true code} \Arg{false code}
+% \cs{__str_count_unsafe:n} \Arg{other string}
% \end{syntax}
-% If the \meta{token} is a hexadecimal digit (upper case or lower
-% case), its upper-case version is left in the input stream,
-% \emph{followed} by the \meta{true code}. Otherwise, the \meta{false
-% code} is left in the input stream.
-% \begin{texnote}
-% This function fails on some inputs if the escape character is a
-% hexadecimal digit. We are thus careful to set the escape
-% character to a known (safe) value before using it.
-% \end{texnote}
+% This function expects an argument that is entirely made of
+% characters with category \enquote{other}, as produced by
+% \cs{__str_to_other:n}. It leaves in the input stream the number of
+% character tokens in the \meta{other string}, faster than the
+% analoguous \cs{str_count:n} function.
% \end{function}
%
-% \begin{function}[EXP]{\__str_output_byte:n}
+% \begin{function}[EXP]{\__str_range_unsafe:nnn}
% \begin{syntax}
-% \cs{__str_output_byte:n} \Arg{intexpr}
+% \cs{__str_range_unsafe:nnn} \Arg{other string} \Arg{start index} \Arg{end index}
% \end{syntax}
-% Expands to a character token with category other and character code
-% equal to the value of \meta{intexpr}. The value of \meta{intexpr}
-% must be in the range $[-1, 255]$, and any value outside this range
-% results in undefined behaviour. The special value $-1$ is used to
-% produce an empty result.
+% Identical to \cs{str_range:nnn} except that the first argument is
+% expected to be entirely made of characters with category
+% \enquote{other}, as produced by \cs{__str_to_other:n}, and the
+% result is also an \meta{other string}.
% \end{function}
%
-% \section{Possibilities, and things to do}
+% \section{Possible additions to \pkg{l3str}}
%
-% Encoding/escaping-related tasks.
+% Semantically correct copies of some \texttt{tl} functions.
% \begin{itemize}
-% \item Describe the internal format in the code comments. Refuse code
-% points in $[\hexnum{D800}, \hexnum{DFFF}]$ in the internal
-% representation?
-% \item Add documentation about each encoding and escaping method, and
-% add examples.
-% \item The \texttt{hex} unescaping should raise an error for
-% odd-token count strings.
-% \item Decide what bytes should be escaped in the \texttt{url}
-% escaping. Perhaps |!'()*-./0123456789_| are safe, and all other
-% characters should be escaped?
-% \item Automate generation of 8-bit mapping files.
-% \item Change the framework for 8-bit encodings: for decoding from
-% 8-bit to Unicode, use $256$ integer registers; for encoding, use a
-% tree-box.
-% \item More encodings (see Heiko's \pkg{stringenc}). CESU?
-% \item More escapings: shell escapes, lua escapes, etc?
+% \item \cs{c_space_str}
+% \item \cs{str_clear:N}, \cs{str_gclear:N}, \cs{str_clear_new:N},
+% \cs{str_gclear_new:N}.
+% \item \cs{str_concat:NNN}, \cs{str_gconcat:NNN}
+% \item \cs{str_set_eq:NN}, \cs{str_gset_eq:NN}
+% \item \cs{str_if_empty:NTF}, \cs{str_if_empty_p:N}
+% \item \cs{str_if_exist:NTF}, \cs{str_if_exist_p:N}
+% \item \cs{str_use:N}
% \end{itemize}
%
-% Other string tasks.
+% Some functions that are not copies of \texttt{tl} functions.
% \begin{itemize}
+% \item \cs{str_if_blank:NTF}, \cs{str_if_blank_p:N}.
+% \item \cs{str_map_inline:Nn}, \cs{str_map_function:NN},
+% \cs{str_map_variable:NNn}, and \texttt{:n} analogs.
% \item Expandable \cs{str_if_in:nnTF}?
-% \item \cs{str_if_head_eq:nN}
+% \item \cs{str_if_head_eq:nNTF}, \cs{str_if_head_eq_p:nN}
% \item \cs{str_if_numeric/decimal/integer:n}, perhaps in \pkg{l3fp}?
-% \item Should \cs{str_item:Nn} be \cs{str_char:Nn}?
-% \item Should \cs{str_substr:Nnn} be \cs{str_range:Nnn}?
-% \item Introduce \cs{str_slice:Nnnn} with a third \enquote{step}
-% argument? Or should we simply have \cs{str_slice:Nn}
-% \meta{string} \Arg{clist}, where the \meta{clist}'s items are
-% either one integer expression, two integer expressions separated
-% by |:|, or three integer expressions separated by |:|, \emph{cf.}
-% Python's extended slice syntax?
-% \item Analog of \texttt{printf}?
% \end{itemize}
%
% \end{documentation}
@@ -611,7 +475,6 @@
% \begin{macrocode}
\ProvidesExplPackage
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
-\RequirePackage{l3tl-analysis,l3tl-build,l3flag}
% \end{macrocode}
%
% The following string-related functions are currently defined in
@@ -623,23 +486,11 @@
% \item \cs{token_to_str:N}, \cs{cs_to_str:N}
% \item \cs{str_head:n}, \cs{__str_head:w}, (copied here)
% \item \cs{str_tail:n}, \cs{__str_tail:w}, (copied here)
-% \item \cs{str_count_ignore_spaces} (unchanged)
-% \item \cs{str_count_loop:NNNNNNNNN} (unchanged)
+% \item \cs{__str_count_ignore_spaces} (unchanged)
+% \item \cs{__str_count_loop:NNNNNNNNN} (unchanged)
% \end{itemize}
%
-% \subsection{Helpers}
-%
-% \subsubsection{A function unrelated to strings}
-%
-% \begin{macro}[EXP,aux]{\use_ii_i:nn}
-% A function used to swap its arguments.
-% \begin{macrocode}
-\cs_if_exist:NF \use_ii_i:nn
- { \cs_new:Npn \use_ii_i:nn #1#2 { #2 #1 } }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Assigning strings}
+% \subsection{String assignments}
%
% \begin{macro}{\str_new:N, \str_new:c}
% A string is simply a token list.
@@ -686,73 +537,13 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Variables and constants}
-%
-% \begin{macro}{\@@_tmp:w}
-% \begin{variable}{\l_@@_internal_int}
-% \begin{variable}{\l_@@_internal_tl}
-% Internal scratch space for some functions.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_tmp:w { }
-\tl_new:N \l_@@_internal_tl
-\int_new:N \l_@@_internal_int
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{macro}
-%
-% \begin{variable}{\g_@@_result_tl}
-% The \cs{g_@@_result_tl} variable is used to hold the result of
-% various internal string operations (mostly conversions) which are
-% typically performed in a group. The variable is global so that it
-% remains defined outside the group, to be assigned to a user-provided
-% variable.
-% \begin{macrocode}
-\tl_new:N \g_@@_result_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}
-% {
-% \c_forty_eight, \c_fifty_eight, \c_sixty_five, \c_ninety_one,
-% \c_ninety_seven, \c_one_hundred_twenty_three,
-% \c_one_hundred_twenty_seven
-% }
-% We declare here some integer values which delimit ranges of ASCII
-% characters of various types. This is mostly used in \pkg{l3regex}.
-% \begin{macrocode}
-\int_const:Nn \c_forty_eight { 48 }
-\int_const:Nn \c_fifty_eight { 58 }
-\int_const:Nn \c_sixty_five { 65 }
-\int_const:Nn \c_ninety_one { 91 }
-\int_const:Nn \c_ninety_seven { 97 }
-\int_const:Nn \c_one_hundred_twenty_three { 123 }
-\int_const:Nn \c_one_hundred_twenty_seven { 127 }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\c_max_char_int}
-% The maximum valid character code is $255$ for pdf\TeX{}, and
-% $1114111$ for other engines.
-% \begin{macrocode}
-\int_const:Nn \c_max_char_int
- { \pdftex_if_engine:TF { "FF } { "10FFFF } }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\c_@@_replacement_char_int}
-% When converting, invalid bytes are replaced by the Unicode
-% replacement character \hexnum{FFFD}.
-% \begin{macrocode}
-\int_const:Nn \c_@@_replacement_char_int { "FFFD }
-% \end{macrocode}
-% \end{variable}
+% \subsection{String variables and constants}
%
% \begin{variable}
% {
% \c_backslash_str,
-% \c_lbrace_str,
-% \c_rbrace_str,
+% \c_left_brace_str,
+% \c_right_brace_str,
% \c_hash_str,
% \c_tilde_str,
% \c_percent_str
@@ -760,153 +551,36 @@
% For all of those strings, use \cs{cs_to_str:N} to get characters with
% the correct category code.
% \begin{macrocode}
-\tl_const:Nx \c_backslash_str { \cs_to_str:N \\ }
-\tl_const:Nx \c_lbrace_str { \cs_to_str:N \{ }
-\tl_const:Nx \c_rbrace_str { \cs_to_str:N \} }
-\tl_const:Nx \c_hash_str { \cs_to_str:N \# }
-\tl_const:Nx \c_tilde_str { \cs_to_str:N \~ }
-\tl_const:Nx \c_percent_str { \cs_to_str:N \% }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\g_@@_alias_prop}
-% To avoid needing one file per encoding/escaping alias, we keep track
-% of those in a property list.
-% \begin{macrocode}
-\prop_new:N \g_@@_alias_prop
-\prop_gput:Nnn \g_@@_alias_prop { latin1 } { iso88591 }
-\prop_gput:Nnn \g_@@_alias_prop { latin2 } { iso88592 }
-\prop_gput:Nnn \g_@@_alias_prop { latin3 } { iso88593 }
-\prop_gput:Nnn \g_@@_alias_prop { latin4 } { iso88594 }
-\prop_gput:Nnn \g_@@_alias_prop { latin5 } { iso88599 }
-\prop_gput:Nnn \g_@@_alias_prop { latin6 } { iso885910 }
-\prop_gput:Nnn \g_@@_alias_prop { latin7 } { iso885913 }
-\prop_gput:Nnn \g_@@_alias_prop { latin8 } { iso885914 }
-\prop_gput:Nnn \g_@@_alias_prop { latin9 } { iso885915 }
-\prop_gput:Nnn \g_@@_alias_prop { latin10 } { iso885916 }
-\prop_gput:Nnn \g_@@_alias_prop { utf16le } { utf16 }
-\prop_gput:Nnn \g_@@_alias_prop { utf16be } { utf16 }
-\prop_gput:Nnn \g_@@_alias_prop { utf32le } { utf32 }
-\prop_gput:Nnn \g_@@_alias_prop { utf32be } { utf32 }
-\prop_gput:Nnn \g_@@_alias_prop { hexadecimal } { hex }
+\str_const:Nx \c_backslash_str { \cs_to_str:N \\ }
+\str_const:Nx \c_left_brace_str { \cs_to_str:N \{ }
+\str_const:Nx \c_right_brace_str { \cs_to_str:N \} }
+\str_const:Nx \c_hash_str { \cs_to_str:N \# }
+\str_const:Nx \c_tilde_str { \cs_to_str:N \~ }
+\str_const:Nx \c_percent_str { \cs_to_str:N \% }
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\g_@@_error_bool}
-% In conversion functions with a built-in conditional, errors are not
-% reported directly to the user, but the information is collected in
-% this boolean, used at the end to decide on which branch of the
-% conditional to take.
+% \begin{variable}{\l_tmpa_str, \l_tmpb_str, \g_tmpa_str, \g_tmpb_str}
+% Scratch strings.
% \begin{macrocode}
-\bool_new:N \g_@@_error_bool
+\str_new:N \l_tmpa_str
+\str_new:N \l_tmpb_str
+\str_new:N \g_tmpa_str
+\str_new:N \g_tmpb_str
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{str_byte, str_error}
-% Conversions from one \meta{encoding}/\meta{escaping} pair to another
-% are done within \texttt{x}-expanding assignments. Errors are
-% signalled by raising the relevant flag.
-% \begin{macrocode}
-\flag_new:n { str_byte }
-\flag_new:n { str_error }
-% \end{macrocode}
-% \end{variable}
-%
-% \subsubsection{Escaping spaces}
+% \subsection{Counting characters}
%
-% \begin{macro}[EXP]{\@@_to_other:n}
-% \begin{macro}[EXP, aux]{\@@_to_other_loop:w, \@@_to_other_end:w}
-% \begin{syntax}
-% \cs{@@_to_other:n} \Arg{token list}
-% \end{syntax}
-% Converts the \meta{token list} to a \meta{other string}, where
-% spaces have category code \enquote{other}. First apply
-% \cs{tl_to_str:n}, then replace all spaces by \enquote{other} spaces,
-% $8$ at a time, storing the converted part of the string between the
-% \cs{q_mark} and \cs{q_stop} markers. This function can be
-% \texttt{f}-expanded without fear of losing a leading space, since
-% spaces do not have category code $10$ in its result. This function
-% takes a time quadratic in the token count of the string;
-% \cs{@@_gset_other:Nn} is faster but not expandable.
+% \begin{macro}[EXP]{\str_count_spaces:N, \str_count_spaces:n}
+% \begin{macro}[EXP, aux]{\@@_count_spaces_loop:wwwwwwwww}
+% To speed up this function, we grab and discard $9$ space-delimited
+% arguments in each iteration of the loop. The loop stops when the
+% last argument is one of the trailing |X|\meta{number}, and that
+% \meta{number} is added to the sum of $9$ that preceeds, to adjust
+% the result.
% \begin{macrocode}
-\group_begin:
-\char_set_lccode:nn { `\* } { `\ }
-\char_set_lccode:nn { `\A } { `\A }
-\tl_to_lowercase:n
- {
- \group_end:
- \cs_new:Npn \@@_to_other:n #1
- {
- \exp_after:wN \@@_to_other_loop:w \tl_to_str:n {#1} ~ %
- A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_mark \q_stop
- }
- \cs_new:Npn \@@_to_other_loop:w
- #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 \q_stop
- {
- \if_meaning:w A #8
- \@@_to_other_end:w
- \fi:
- \@@_to_other_loop:w
- #9 #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * \q_stop
- }
- \cs_new:Npn \@@_to_other_end:w \fi: #1 \q_mark #2 * A #3 \q_stop
- { \fi: #2 }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_gset_other:Nn}
-% \begin{macro}[aux,EXP]{\@@_gset_other_loop:w}
-% \begin{macro}[aux,EXP]{\@@_gset_other_end:w}
-% This function could be done by using \cs{@@_to_other:n} within
-% an \texttt{x}-expansion, but that would take a time quadratic in the
-% size of the string. Instead, we can \enquote{leave the result behind
-% us} in the input stream, to be captured into the expanding
-% assignment. This gives us a linear time.
-% \begin{macrocode}
-\group_begin:
-\char_set_lccode:nn { `\* } { `\ }
-\char_set_lccode:nn { `\A } { `\A }
-\tl_to_lowercase:n
- {
- \group_end:
- \cs_new_protected:Npn \@@_gset_other:Nn #1#2
- {
- \tl_gset:Nx #1
- {
- \exp_after:wN \@@_gset_other_loop:w \tl_to_str:n {#2} ~ %
- A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_stop
- }
- }
- \cs_new:Npn \@@_gset_other_loop:w
- #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 ~
- {
- \if_meaning:w A #9
- \@@_gset_other_end:w
- \fi:
- #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * #9
- \@@_gset_other_loop:w *
- }
- \cs_new:Npn \@@_gset_other_end:w \fi: #1 * A #2 \q_stop
- { \fi: #1 }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Characters given by their position}
-%
-% \begin{macro}[EXP]{\str_count_spaces:N}
-% \begin{macro}[EXP]{\str_count_spaces:n}
-% \begin{macro}[EXP,aux]{\@@_count_spaces_loop:wwwwwwwww}
-% To speed up this function, we grab $9$ spaces in each step. The
-% loop stops when the last argument is one of the trailing
-% |X|\meta{number}, and that \meta{number} is added to the sum of $9$
-% that preceeds, to adjust the result.
-% \begin{macrocode}
-\cs_new:Npn \str_count_spaces:N
+\cs_new_nopar:Npn \str_count_spaces:N
{ \exp_args:No \str_count_spaces:n }
\cs_new:Npn \str_count_spaces:n #1
{
@@ -921,30 +595,29 @@
\cs_new:Npn \@@_count_spaces_loop:wwwwwwwww #1~#2~#3~#4~#5~#6~#7~#8~#9~
{
\if_meaning:w X #9
- \exp_after:wN \use_none_delimit_by_q_stop:w
+ \use_i_delimit_by_q_stop:nw
\fi:
\c_nine + \@@_count_spaces_loop:wwwwwwwww
}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}[EXP]{\str_count:N}
-% \begin{macro}[EXP]{\str_count:n}
-% \begin{macro}[EXP]{\@@_count_unsafe:n}
-% \begin{macro}[EXP]{\str_count_ignore_spaces:n}
-% \begin{macro}[EXP,aux]{\@@_count:n, \@@_count_loop:NNNNNNNNN}
-% To measure the token count of a string we could first escape all spaces
-% using \cs{@@_to_other:o}, then measure the count of this token
-% list. However, this would be quadratic in the length of the string,
-% and we can do better. Namely, add the number of spaces (counted
-% using the functions defined above) to the length ignoring spaces.
-% To measure the length ignoring spaces we use the same technique as
-% for counting spaces: loop, grabbing $9$ characters at each step, and
-% end as soon as we reach one of the $9$ trailing items. The
-% \texttt{_unsafe} variant expects a token list consisting entirely of
-% category code $12$ characters.
+% \begin{macro}[EXP]{\str_count:N, \str_count:n, \str_count_ignore_spaces:n}
+% \begin{macro}[EXP, int]{\@@_count_unsafe:n}
+% \begin{macro}[EXP, aux]{\@@_count:n, \@@_count_loop:NNNNNNNNN}
+% To count characters in a string we could first escape all spaces
+% using \cs{@@_to_other:n}, then pass the result to \cs{tl_count:n}.
+% However, the escaping step would be quadratic in the number of
+% characters in the string, and we can do better. Namely, sum the
+% number of spaces (\cs{str_count_spaces:n}) and the result of
+% \cs{tl_count:n}, which ignores spaces. Since strings tend to be
+% longer than token lists, we use specialized functions to count
+% characters ignoring spaces. Namely, loop, grabbing $9$ non-space
+% characters at each step, and end as soon as we reach one of the $9$
+% trailing items. The \texttt{_unsafe} variant expects a token list
+% already converted to category code $12$ characters, and is used by
+% \cs{str_item:nn} and \cs{str_range:nnn}.
% \begin{macrocode}
\cs_new_nopar:Npn \str_count:N { \exp_args:No \str_count:n }
\cs_new:Npn \str_count:n #1
@@ -987,22 +660,20 @@
% \end{macro}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
-% \begin{macro}[EXP]{\str_head:N}
-% \begin{macro}[EXP]{\str_head:n}
-% \begin{macro}[EXP]{\str_head_ignore_spaces:n}
-% \begin{macro}[EXP,aux]{\@@_head:w}
+% \subsection{Head and tail of a string}
+%
+% \begin{macro}[EXP]{\str_head:N, \str_head:n, \str_head_ignore_spaces:n}
+% \begin{macro}[EXP, aux]{\@@_head:w}
% The \texttt{_ignore_spaces} variant is almost identical to
% \cs{tl_head:n}. As usual, \cs{str_head:N} expands its argument and
-% hands it to \cs{str_head:n}. To circumvent the fact that \TeX{}
+% hands it to \cs{str_head:n}. To circumvent the fact that \TeX{}
% skips spaces when grabbing undelimited macro parameters,
% \cs{@@_head:w} takes an argument delimited by a space. If |#1|
% starts with a non-space character, \cs{use_i_delimit_by_q_stop:nw}
% leaves that in the input stream. On the other hand, if |#1| starts
-% with a space, the \cs{@@_head:w} takes an empty argument, and
-% the single (braced) space in the definition of \cs{@@_head:w}
+% with a space, the \cs{@@_head:w} takes an empty argument, and the
+% single (initially braced) space in the definition of \cs{@@_head:w}
% makes its way to the output. Finally, for an empty argument, the
% (braced) empty brace group in the definition of \cs{str_head:n}
% gives an empty result after passing through
@@ -1025,23 +696,23 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
-% \begin{macro}[EXP]{\str_tail:N}
-% \begin{macro}[EXP]{\str_tail:n}
-% \begin{macro}[EXP]{\str_tail_ignore_spaces:n}
-% \begin{macro}[EXP,aux]{\@@_tail_auxi:w}
-% \begin{macro}[EXP,aux]{\@@_tail_auxii:w}
-% As when fetching the head of a string, the \texttt{_ignore_spaces}
-% variant is similar to \cs{tl_tail:n}. The more commonly used
-% \cs{str_tail:n} function is a little bit more convoluted: hitting
-% the front of the string with \cs{reverse_if:N} \cs{if_charcode:w}
-% \cs{scan_stop:} removes the first character (which necessarily makes
-% the test true, since it cannot match \cs{scan_stop:}). The auxiliary
-% function inserts the required \cs{fi:} to close the conditional, and
-% leaves the tail of the string in the input string. The details are
-% such that an empty string has an empty tail.
+% \begin{macro}[EXP]{\str_tail:N, \str_tail:n, \str_tail_ignore_spaces:n}
+% \begin{macro}[EXP, aux]{\@@_tail_auxi:w, \@@_tail_auxii:w}
+% Getting the tail is a little bit more convoluted than the head of a
+% string. We hit the front of the string with \cs{reverse_if:N}
+% \cs{if_charcode:w} \cs{scan_stop:}. This removes the first
+% character, and necessarily makes the test true, since the character
+% cannot match \cs{scan_stop:}. The auxiliary function then inserts
+% the required \cs{fi:} to close the conditional, and leaves the tail
+% of the string in the input stream. The details are such that an
+% empty string has an empty tail (this requires in particular that the
+% end-marker |X| be unexpandable and not a control sequence). The
+% \texttt{_ignore_spaces} is rather simpler: after converting the
+% input to a string, \cs{@@_tail_auxii:w} removes one undelimited
+% argument and leaves everything else until an end-marker \cs{q_mark}.
+% One can check that an empty (or blank) string yields an empty
+% tail.
% \begin{macrocode}
\cs_new_nopar:Npn \str_tail:N { \exp_args:No \str_tail:n }
\cs_set:Npn \str_tail:n #1
@@ -1054,26 +725,63 @@
\cs_new:Npn \str_tail_ignore_spaces:n #1
{
\exp_after:wN \@@_tail_auxii:w
- \tl_to_str:n {#1} X X \q_stop
+ \tl_to_str:n {#1} \q_mark \q_mark \q_stop
}
-\cs_new:Npn \@@_tail_auxii:w #1 #2 X #3 \q_stop { #2 }
+\cs_new:Npn \@@_tail_auxii:w #1 #2 \q_mark #3 \q_stop { #2 }
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
+%
+% \subsection{Accessing specific characters in a string}
+%
+% \begin{macro}[EXP, int]{\@@_to_other:n}
+% \begin{macro}[EXP, aux]{\@@_to_other_loop:w, \@@_to_other_end:w}
+% First apply \cs{tl_to_str:n}, then replace all spaces by
+% \enquote{other} spaces, $8$ at a time, storing the converted part of
+% the string between the \cs{q_mark} and \cs{q_stop} markers. The end
+% is detected when \cs{@@_to_other_loop:w} finds one of the trailing
+% |A|, distinguished from any contents of the initial token list by
+% their category. Then \cs{@@_to_other_end:w} is called, and finds
+% the result between \cs{q_mark} and the first |A| (well, there is
+% also the need to remove a space).
+% \begin{macrocode}
+\group_begin:
+\char_set_lccode:nn { `\* } { `\ }
+\char_set_lccode:nn { `\A } { `\A }
+\tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new:Npn \@@_to_other:n #1
+ {
+ \exp_after:wN \@@_to_other_loop:w \tl_to_str:n {#1} ~ %
+ A ~ A ~ A ~ A ~ A ~ A ~ A ~ A ~ \q_mark \q_stop
+ }
+ \cs_new:Npn \@@_to_other_loop:w
+ #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 ~ #7 ~ #8 ~ #9 \q_stop
+ {
+ \if_meaning:w A #8
+ \@@_to_other_end:w
+ \fi:
+ \@@_to_other_loop:w
+ #9 #1 * #2 * #3 * #4 * #5 * #6 * #7 * #8 * \q_stop
+ }
+ \cs_new:Npn \@@_to_other_end:w \fi: #1 \q_mark #2 * A #3 \q_stop
+ { \fi: #2 }
+ }
+% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP, int]{\@@_skip_c_zero:w}
-% \begin{macro}[EXP, aux]{\@@_skip_loop:wNNNNNNNN}
-% \begin{macro}[EXP, aux]{\@@_skip_end:w, \@@_skip_end:NNNNNNNN}
+% \begin{macro}[EXP, aux]{\@@_skip_c_zero:w}
+% \begin{macro}[EXP, aux]
+% {\@@_skip_loop:wNNNNNNNN, \@@_skip_end:w, \@@_skip_end:NNNNNNNN}
% Removes |max(#1,0)| characters from the input stream, and then
-% leaves \cs{c_zero}. This should be expanded using
+% leaves \cs{c_zero}. This should be expanded using
% \cs{tex_romannumeral:D}. We remove characters $8$ at a time until
-% there are at most $8$ to remove. Then we do a dirty trick: the
+% there are at most $8$ to remove. Then we do a dirty trick: the
% \cs{if_case:w} construction leaves between $0$ and $8$ times the
% \cs{or:} control sequence, and those \cs{or:} become arguments of
-% \cs{@@_skip_end:NNNNNNNN}. If the number of characters to remove
+% \cs{@@_skip_end:NNNNNNNN}. If the number of characters to remove
% is $6$, say, then there are two \cs{or:} left, and the $8$ arguments
% of \cs{@@_skip_end:NNNNNNNN} are the two \cs{or:}, and $6$
% characters from the input stream, exactly what we wanted to
@@ -1083,7 +791,7 @@
% \begin{macrocode}
\cs_new:Npn \@@_skip_c_zero:w #1;
{
- \if_int_compare:w \__int_eval:w #1 > \c_eight
+ \if_int_compare:w #1 > \c_eight
\exp_after:wN \@@_skip_loop:wNNNNNNNN
\else:
\exp_after:wN \@@_skip_end:w
@@ -1096,34 +804,31 @@
\cs_new:Npn \@@_skip_end:w #1 ;
{
\exp_after:wN \@@_skip_end:NNNNNNNN
- \if_case:w \if_int_compare:w #1 > \c_zero #1 \else: 0 \fi: \exp_stop_f:
- \or: \or: \or: \or: \or: \or: \or: \or:
+ \if_case:w #1 \exp_stop_f: \or: \or: \or: \or: \or: \or: \or: \or:
}
\cs_new:Npn \@@_skip_end:NNNNNNNN #1#2#3#4#5#6#7#8 { \fi: \c_zero }
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}[EXP,int]{\@@_collect_delimit_by_q_stop:w}
-% \begin{macro}[EXP,aux]{\@@_collect_loop:wn, \@@_collect_loop:wnNNNNNNN}
-% \begin{macro}[EXP,aux]
-% {\@@_collect_end:wn, \@@_collect_end:nnnnnnnnw} Collects
-% |max(#1,0)| characters, and removes everything else until
+% \begin{macro}[EXP, aux]{\@@_collect_delimit_by_q_stop:w}
+% \begin{macro}[EXP, aux]
+% {
+% \@@_collect_loop:wn, \@@_collect_loop:wnNNNNNNN,
+% \@@_collect_end:wn, \@@_collect_end:nnnnnnnnw
+% }
+% Collects |max(#1,0)| characters, and removes everything else until
% \cs{q_stop}. This is somewhat similar to \cs{@@_skip_c_zero:w}, but
-% this time we can only grab $7$ characters at a time. At the end, we
-% use an \cs{if_case:w} trick again, so that the $8$ first arguments
-% of \cs{@@_collect_end:nnnnnnnnw} are some \cs{or:}, followed by
-% an \cs{fi:}, followed by |#1| characters from the input
-% stream. Simply leaving this in the input stream will close the
-% conditional properly and the \cs{or:} disappear.
+% accepts integer expression arguments. This time we can only grab
+% $7$ characters at a time. At the end, we use an \cs{if_case:w}
+% trick again, so that the $8$ first arguments of
+% \cs{@@_collect_end:nnnnnnnnw} are some \cs{or:}, followed by an
+% \cs{fi:}, followed by |#1| characters from the input stream. Simply
+% leaving this in the input stream will close the conditional properly
+% and the \cs{or:} disappear.
% \begin{macrocode}
\cs_new:Npn \@@_collect_delimit_by_q_stop:w #1;
- {
- \exp_after:wN \@@_collect_loop:wn
- \int_use:N \__int_eval:w #1 ;
- { }
- }
+ { \@@_collect_loop:wn #1 ; { } }
\cs_new:Npn \@@_collect_loop:wn #1 ;
{
\if_int_compare:w #1 > \c_seven
@@ -1150,20 +855,25 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}[EXP]{\str_item:Nn}
-% \begin{macro}[EXP]{\str_item:nn}
-% \begin{macro}[EXP]{\str_item_ignore_spaces:nn}
-% \begin{macro}[EXP]{\@@_item_unsafe:nn}
-% \begin{macro}[EXP,aux]{\@@_item:ww}
-% This is mostly shuffling arguments around to avoid measuring the
-% length of the string more than once, and make sure that the
-% parameters given to \cs{@@_skip_c_zero:w} are necessarily within
-% the bounds of the length of the string. The \texttt{_ignore_spaces}
-% function cheats a little bit in that it doesn't hand to
-% \cs{@@_item_unsafe:nn} an \enquote{other string}. This is alright,
-% as everything else is done with undelimited arguments.
+% \begin{macro}[EXP]{\str_item:Nn, \str_item:nn, \str_item_ignore_spaces:nn}
+% \begin{macro}[EXP, aux]{\@@_item_unsafe:nn, \@@_item:ww}
+% The \cs{str_item:nn} hands its argument with spaces escaped to
+% \cs{@@_item_unsafe:nn}, and makes sure to turn the result back into
+% a proper string (with category code~$10$ spaces) eventually. The
+% \cs{str_item_ignore_spaces:nn} function cheats a little bit in that
+% it doesn't hand to \cs{@@_item_unsafe:nn} an \enquote{other string}.
+% This is safe, as everything else is done with undelimited arguments.
+% Then evaluate the \meta{index} argument~|#2| and count characters in
+% the string, passing those two numbers to \cs{@@_item:ww} for further
+% analysis. If the \meta{index} is negative, shift by |#2|, and
+% remove that number of characters before returning the next item in
+% the input stream (and if |#1| is smaller than $-|#2|$, nothing is
+% returned). If the \meta{index} is positive, ignore that number
+% (minus one) of characters before returning the next one. The shift
+% by one is obtained by inserting an empty brace group before the
+% string in that case: that brace group also covers the case where the
+% \meta{index} is zero.
% \begin{macrocode}
\cs_new_nopar:Npn \str_item:Nn { \exp_args:No \str_item:nn }
\cs_new:Npn \str_item:nn #1#2
@@ -1181,8 +891,7 @@
\exp_after:wN \@@_item:ww
\int_use:N \__int_eval:w #2 \exp_after:wN ;
\__int_value:w \@@_count_unsafe:n {#1} ;
- { } #1
- \q_stop
+ #1 \q_stop
}
\cs_new:Npn \@@_item:ww #1; #2;
{
@@ -1192,7 +901,8 @@
{ \use_none_delimit_by_q_stop:w }
{
\exp_after:wN \use_i_delimit_by_q_stop:nw
- \tex_romannumeral:D \@@_skip_c_zero:w #1 + #2 + \c_one ;
+ \tex_romannumeral:D \exp_after:wN \@@_skip_c_zero:w
+ \int_use:N \__int_eval:w #1 + #2 ;
}
}
{
@@ -1200,99 +910,97 @@
{ \use_none_delimit_by_q_stop:w }
{
\exp_after:wN \use_i_delimit_by_q_stop:nw
- \tex_romannumeral:D \@@_skip_c_zero:w #1 ;
+ \tex_romannumeral:D \@@_skip_c_zero:w #1 ; { }
}
}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
+%
+% \begin{macro}[EXP, aux]{\@@_range_normalize:nn}
+% This function converts an \meta{index} argument into an explicit
+% position in the string (a result of $0$ denoting \enquote{out of
+% bounds}). Expects two explicit integer arguments: the
+% \meta{index} |#1| and the string count~|#2|. If |#1| is negative,
+% replace it by $|#1| + |#2| + 1$, then limit to the range $[0,
+% |#2|]$.
+% \begin{macrocode}
+\cs_new:Npn \@@_range_normalize:nn #1#2
+ {
+ \int_eval:n
+ {
+ \if_int_compare:w #1 < \c_zero
+ \if_int_compare:w #1 < -#2 \exp_stop_f:
+ \c_zero
+ \else:
+ #1 + #2 + \c_one
+ \fi:
+ \else:
+ \if_int_compare:w #1 < #2 \exp_stop_f:
+ #1
+ \else:
+ #2
+ \fi:
+ \fi:
+ }
+ }
+% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\str_substr:Nnn}
-% \begin{macro}[EXP]{\str_substr:nnn}
-% \begin{macro}[EXP]{\str_substr_ignore_spaces:nnn}
-% \begin{macro}[EXP,aux]
-% {
-% \@@_substr_unsafe:nnn,
-% \@@_substr:nN,
-% \@@_substr:www,
-% \@@_substr:nnw,
-% \@@_substr_normalize_range:nn
-% }
-% Sanitize the string. Then evaluate the arguments, replacing them by
-% \cs{c_zero} or \cs{c_max_int} if they are empty. Then limit the
-% range to be at most the length of the string (this avoids needing to
-% check for the end of the string when grabbing characters).
+% \begin{macro}[EXP]
+% {\str_range:Nnn, \str_range:nnn, \str_range_ignore_spaces:nnn}
+% \begin{macro}[EXP, int]{\@@_range_unsafe:nnn}
+% \begin{macro}[EXP, aux]{\@@_range:www, \@@_range:nnw}
+% Sanitize the string. Then evaluate the arguments. At this stage we
+% also decrement the \meta{start index}, since our goal is to know how
+% many characters should be removed. Then limit the range to be
+% non-negative and at most the length of the string (this avoids
+% needing to check for the end of the string when grabbing
+% characters), shifting negative numbers by the appropriate amount.
% Afterwards, skip characters, then keep some more, and finally drop
% the end of the string.
% \begin{macrocode}
-\cs_new_nopar:Npn \str_substr:Nnn { \exp_args:No \str_substr:nnn }
-\cs_new:Npn \str_substr:nnn #1#2#3
+\cs_new_nopar:Npn \str_range:Nnn { \exp_args:No \str_range:nnn }
+\cs_new:Npn \str_range:nnn #1#2#3
{
\exp_args:Nf \tl_to_str:n
{
- \exp_args:Nf \@@_substr_unsafe:nnn
+ \exp_args:Nf \@@_range_unsafe:nnn
{ \@@_to_other:n {#1} } {#2} {#3}
}
}
-\cs_new:Npn \str_substr_ignore_spaces:nnn #1
- { \exp_args:No \@@_substr_unsafe:nnn { \tl_to_str:n {#1} } }
-\cs_new:Npn \@@_substr_unsafe:nnn #1#2#3
+\cs_new:Npn \str_range_ignore_spaces:nnn #1
+ { \exp_args:No \@@_range_unsafe:nnn { \tl_to_str:n {#1} } }
+\cs_new:Npn \@@_range_unsafe:nnn #1#2#3
{
- \exp_after:wN \@@_substr:www
+ \exp_after:wN \@@_range:www
\__int_value:w \@@_count_unsafe:n {#1} \exp_after:wN ;
- \int_use:N \__int_eval:w #2 + \c_zero \exp_after:wN ;
- \int_use:N \__int_eval:w
- \exp_args:Nf \@@_substr:nN {#3} \c_max_int ;
- { } #1
- \q_stop
+ \int_use:N \__int_eval:w #2 - \c_one \exp_after:wN ;
+ \int_use:N \__int_eval:w #3 ;
+ #1 \q_stop
}
-\cs_new:Npn \@@_substr:nN #1 #2
- { \tl_if_empty:nTF {#1} {#2} {#1} }
-\cs_new:Npn \@@_substr:www #1; #2; #3;
+\cs_new:Npn \@@_range:www #1; #2; #3;
{
- \exp_args:Nf \@@_substr:nnw
- { \@@_substr_normalize_range:nn {#2} {#1} }
- { \@@_substr_normalize_range:nn {#3} {#1} }
+ \exp_args:Nf \@@_range:nnw
+ { \@@_range_normalize:nn {#2} {#1} }
+ { \@@_range_normalize:nn {#3} {#1} }
}
-\cs_new:Npn \@@_substr:nnw #1#2
+\cs_new:Npn \@@_range:nnw #1#2
{
\exp_after:wN \@@_collect_delimit_by_q_stop:w
- \int_use:N \__int_eval:w #2 + \c_one - #1 \exp_after:wN ;
+ \int_use:N \__int_eval:w #2 - #1 \exp_after:wN ;
\tex_romannumeral:D \@@_skip_c_zero:w #1 ;
}
-\cs_new:Npn \@@_substr_normalize_range:nn #1#2
- {
- \int_eval:n
- {
- \if_int_compare:w #1 < \c_zero
- \if_int_compare:w #1 < - #2 \exp_stop_f:
- \c_zero
- \else:
- #1 + #2 + \c_one
- \fi:
- \else:
- \if_int_compare:w #1 > #2 \exp_stop_f:
- #2
- \else:
- #1
- \fi:
- \fi:
- }
- }
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \subsection{String conditionals}
%
-% \begin{macro}[EXP,pTF]{\str_if_eq:NN}
-% \begin{macro}[EXP,pTF]{\str_if_eq:nn,\str_if_eq_x:nn}
+% \begin{macro}[EXP, pTF]{\str_if_eq:NN}
+% \begin{macro}[EXP, pTF]{\str_if_eq:nn, \str_if_eq_x:nn}
% Note that \cs{str_if_eq:NN} is different from
% \cs{tl_if_eq:NN} because it needs to ignore category codes.
% \begin{macrocode}
@@ -1305,109 +1013,10 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\str_case:nnn, \str_case:onn, \str_case_x:nnn}
+% \begin{macro}[EXP]{\str_case:nnn, \str_case:onn, \str_case_x:nnn}
% Defined in \pkg{l3basics} at present.
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_if_contains_char:NNT, \@@_if_contains_char:NNTF}
-% \begin{macro}[EXP]{\@@_if_contains_char:nNTF}
-% \begin{macro}[EXP,aux]{\@@_if_contains_char_aux:NN}
-% \begin{macro}[EXP,aux]{\@@_if_contains_char_true:}
-% \begin{syntax}
-% \cs{@@_if_contains_char:nNTF} \Arg{token list} \meta{char}
-% \end{syntax}
-% Expects the \meta{token list} to be an \meta{other string}: the
-% caller is responsible for ensuring that no (too-)special catcodes
-% remain. Spaces with catcode $10$ are ignored.
-% Loop over the characters of the string, comparing character codes.
-% The loop is broken if character codes match. Otherwise we return
-% \enquote{false}.
-% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_if_contains_char:NN #1#2 { T , TF }
- {
- \exp_after:wN \@@_if_contains_char_aux:NN \exp_after:wN #2
- #1 { \__prg_break:n { ? \fi: } }
- \__prg_break_point:
- \prg_return_false:
- }
-\prg_new_conditional:Npnn \@@_if_contains_char:nN #1#2 { TF }
- {
- \@@_if_contains_char_aux:NN #2 #1 { \__prg_break:n { ? \fi: } }
- \__prg_break_point:
- \prg_return_false:
- }
-\cs_new:Npn \@@_if_contains_char_aux:NN #1#2
- {
- \if_charcode:w #1 #2
- \exp_after:wN \@@_if_contains_char_true:
- \fi:
- \@@_if_contains_char_aux:NN #1
- }
-\cs_new_nopar:Npn \@@_if_contains_char_true:
- { \__prg_break:n { \prg_return_true: \use_none:n } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[aux, rEXP]{\@@_octal_use:NTF}
-% \begin{syntax}
-% \cs{@@_octal_use:NTF} \meta{token} \Arg{true code} \Arg{false code}
-% \end{syntax}
-% If the \meta{token} is an octal digit, it is left in the input
-% stream, \emph{followed} by the \meta{true code}. Otherwise, the
-% \meta{false code} is left in the input stream.
-% \begin{texnote}
-% This function will fail if the escape character is an octal
-% digit. We are thus careful to set the escape character to a known
-% value before using it.
-% \end{texnote}
-% \TeX{} dutifully detects octal digits for us: if |#1| is an octal
-% digit, then the right-hand side of the comparison is |'1#1|, greater
-% than $1$. Otherwise, the right-hand side stops as |'1|, and the
-% conditional takes the \texttt{false} branch.
-% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_octal_use:N #1 { TF }
- {
- \if_int_compare:w \c_one < '1 \token_to_str:N #1 \exp_stop_f:
- #1 \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[aux, rEXP]{\@@_hexadecimal_use:NTF}
-% \TeX{} detects uppercase hexadecimal digits for us (see
-% \cs{@@_octal_use:NTF}), but not the lowercase letters, which we
-% need to detect and replace by their uppercase counterpart.
-% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_hexadecimal_use:N #1 { TF }
- {
- \if_int_compare:w \c_two < "1 \token_to_str:N #1 \exp_stop_f:
- #1 \prg_return_true:
- \else:
- \if_case:w \__int_eval:w
- \exp_after:wN ` \token_to_str:N #1 - `a
- \__int_eval_end:
- A
- \or: B
- \or: C
- \or: D
- \or: E
- \or: F
- \else:
- \prg_return_false:
- \exp_after:wN \use_none:n
- \fi:
- \prg_return_true:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-%
% \subsection{Viewing strings}
%
% \begin{macro}{\str_show:n, \str_show:N, \str_show:c}
@@ -1419,3084 +1028,41 @@
% \end{macrocode}
% \end{macro}
%
-% \subsection{Conversions}
-%
-% \subsubsection{Producing one byte or character}
-%
-% \begin{variable}{\c_@@_byte_0_tl, \c_@@_byte_1_tl, \c_@@_byte_255_tl}
-% \begin{variable}{\c_@@_byte_-1_tl}
-% For each integer $N$ in the range $[0,255]$, we create a constant
-% token list which holds three character tokens with category code
-% other: the character with character code $N$, followed by the
-% representation of $N$ as two hexadecimal digits. The value $-1$ is
-% given a default token list which ensures that later functions give
-% an empty result for the input $-1$.
-% \begin{macrocode}
-\group_begin:
- \char_set_catcode_other:n { \c_zero }
- \tl_set:Nx \l_@@_internal_tl { \tl_to_str:n { 0123456789ABCDEF } }
- \exp_args:No \tl_map_inline:nn { \l_@@_internal_tl " }
- { \char_set_lccode:nn {`#1} { \c_zero } }
- \tl_map_inline:Nn \l_@@_internal_tl
- {
- \tl_map_inline:Nn \l_@@_internal_tl
- {
- \char_set_lccode:nn { \c_zero } {"#1##1}
- \tl_to_lowercase:n
- {
- \tl_const:cx
- { c_@@_byte_ \int_eval:n {"#1##1} _tl }
- { ^^@ #1 ##1 }
- }
- }
- }
-\group_end:
-\tl_const:cn { c_@@_byte_-1_tl } { { } \use_none:n { } }
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-%
-% \begin{macro}[int, EXP]{\@@_output_byte:n}
-% \begin{macro}[int, EXP]{\@@_output_byte:w}
-% \begin{macro}[int, EXP]{\@@_output_hexadecimal:n}
-% \begin{macro}[int, EXP]{\@@_output_hexadecimal:w}
-% \begin{macro}[int, EXP]{\@@_output_end:}
-% Those functions must be used carefully: feeding them a value outside
-% the range $[-1,255]$ will attempt to use the undefined token list
-% variable \cs{c_@@_byte_\meta{number}_tl}. Assuming that the
-% argument is in the right range, we expand the corresponding token
-% list, and pick either the byte (first token) or the hexadecimal
-% representations (second and third tokens). The value $-1$ produces
-% an empty result in both cases.
-% \begin{macrocode}
-\cs_new:Npn \@@_output_byte:n #1
- { \@@_output_byte:w #1 \@@_output_end: }
-\cs_new_nopar:Npn \@@_output_byte:w
- {
- \exp_after:wN \exp_after:wN
- \exp_after:wN \use_i:nnn
- \cs:w c_@@_byte_ \int_use:N \__int_eval:w
- }
-\cs_new:Npn \@@_output_hexadecimal:n #1
- { \@@_output_hexadecimal:w #1 \@@_output_end: }
-\cs_new_nopar:Npn \@@_output_hexadecimal:w
- {
- \exp_after:wN \exp_after:wN
- \exp_after:wN \use_none:n
- \cs:w c_@@_byte_ \int_use:N \__int_eval:w
- }
-\cs_new_nopar:Npn \@@_output_end:
- { \__int_eval_end: _tl \cs_end: }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int, rEXP]{\@@_output_byte_pair_be:n}
-% \begin{macro}[int, rEXP]{\@@_output_byte_pair_le:n}
-% \begin{macro}[aux, rEXP]{\@@_output_byte_pair:nnN}
-% Convert a number in the range $[0,65535]$ to a pair of bytes, either
-% big-endian or little-endian.
-% \begin{macrocode}
-\cs_new:Npn \@@_output_byte_pair_be:n #1
- {
- \exp_args:Nf \@@_output_byte_pair:nnN
- { \int_div_truncate:nn { #1 } { "100 } } {#1} \use:nn
- }
-\cs_new:Npn \@@_output_byte_pair_le:n #1
- {
- \exp_args:Nf \@@_output_byte_pair:nnN
- { \int_div_truncate:nn { #1 } { "100 } } {#1} \use_ii_i:nn
- }
-\cs_new:Npn \@@_output_byte_pair:nnN #1#2#3
- {
- #3
- { \@@_output_byte:n { #1 } }
- { \@@_output_byte:n { #2 - #1 * "100 } }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Mapping functions for conversions}
-%
-% \begin{macro}{\@@_convert_gmap:N}
-% \begin{macro}[aux, rEXP]{\@@_convert_gmap_loop:NN}
-% This maps the function |#1| over all characters in
-% \cs{g_@@_result_tl}, which should be a byte string in most cases,
-% sometimes a native string.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_convert_gmap:N #1
- {
- \tl_gset:Nx \g_@@_result_tl
- {
- \exp_after:wN \@@_convert_gmap_loop:NN
- \exp_after:wN #1
- \g_@@_result_tl { ? \__prg_break: }
- \__prg_break_point:
- }
- }
-\cs_new:Npn \@@_convert_gmap_loop:NN #1#2
- {
- \use_none:n #2
- #1#2
- \@@_convert_gmap_loop:NN #1
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@@_convert_gmap_internal:N}
-% \begin{macro}[aux, rEXP]{\@@_convert_gmap_internal_loop:Nw}
-% This maps the function |#1| over all character codes in
-% \cs{g_@@_result_tl}, which must be in the internal representation.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_convert_gmap_internal:N #1
- {
- \tl_gset:Nx \g_@@_result_tl
- {
- \exp_after:wN \@@_convert_gmap_internal_loop:Nww
- \exp_after:wN #1
- \g_@@_result_tl \s__tl \q_stop \__prg_break: \s__tl
- \__prg_break_point:
- }
- }
-\cs_new:Npn \@@_convert_gmap_internal_loop:Nww #1 #2 \s__tl #3 \s__tl
- {
- \use_none_delimit_by_q_stop:w #3 \q_stop
- #1 {#3}
- \@@_convert_gmap_internal_loop:Nww #1
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Error-reporting during conversion}
-%
-% \begin{macro}[int]{\@@_if_flag_error:nnx}
-% \begin{macro}[aux]{\@@_if_flag_no_error:nnx}
-% When converting using the function \cs{str_set_convert:Nnnn}, errors
-% should be reported to the user after each step in the
-% conversion. Errors are signalled by raising some flag (typically
-% \texttt{@@_error}), so here we test that flag: if it is raised,
-% give the user an error, otherwise remove the arguments. On the other
-% hand, in the conditional functions \cs{str_set_convert:NnnnTF},
-% errors should be suppressed. This is done by changing
-% \cs{@@_if_flag_error:nnx} into \cs{@@_if_flag_no_error:nnx}
-% locally.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_if_flag_error:nnx #1
- {
- \flag_if_raised:nTF {#1}
- { \__msg_kernel_error:nnx { str } }
- { \use_none:nn }
- }
-\cs_new_protected:Npn \@@_if_flag_no_error:nnx #1#2#3
- { \flag_if_raised:nT {#1} { \bool_gset_true:N \g_@@_error_bool } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_if_flag_times:nT}
-% At the end of each conversion step, we raise all relevant errors as
-% one error message, built on the fly. The height of each flag
-% indicates how many times a given error was encountered. This
-% function prints |#2| followed by the number of occurrences of an
-% error if it occurred, nothing otherwise.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_if_flag_times:nT #1#2
- { \flag_if_raised:nT {#1} { #2~(x \flag_height:n {#1} ) } }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Framework for conversions}
-%
-% Most functions in this module expect to be working with
-% \enquote{native} strings. Strings can also be stored as bytes, in one
-% of many encodings, for instance \textsc{utf8}. The bytes themselves
-% can be expressed in various ways in terms of \TeX{} tokens, for
-% instance as pairs of hexadecimal digits. The questions of going from
-% arbitrary Unicode code points to bytes, and from bytes to tokens are
-% mostly independent.
-%
-% Conversions are done in four steps:
-% \begin{itemize}
-% \item \enquote{unescape} produces a string of bytes;
-% \item \enquote{decode} takes in a string of bytes, and converts it
-% to a list of Unicode characters in an internal representation,
-% with items of the form
-% \begin{quote}
-% \meta{bytes} \cs{s__tl} \meta{Unicode code point} \cs{s__tl}
-% \end{quote}
-% where we have collected the \meta{bytes} which combined to form
-% this particular Unicode character, and the \meta{Unicode code
-% point} is in the range $[0,\hexnum{10FFFF}]$.
-% \item \enquote{encode} encodes the internal list of code points as a
-% byte string in the new encoding;
-% \item \enquote{escape} escapes bytes as requested.
-% \end{itemize}
-% The process is modified in case one of the encoding is empty (or the
-% conversion function has been set equal to the empty encoding because
-% it was not found): then the unescape or escape step is ignored, and
-% the decode or encode steps work on tokens instead of bytes. Otherwise,
-% each step must ensure that it passes a correct byte string or internal
-% string to the next step.
-%
-% \begin{macro}{\str_set_convert:Nnnn, \str_gset_convert:Nnnn}
-% \begin{macro}[TF]{\str_set_convert:Nnnn, \str_gset_convert:Nnnn}
-% \begin{macro}[aux]{\@@_convert:nNNnnn}
-% The input string is stored in \cs{g_@@_result_tl}, then we:
-% unescape and decode; encode and escape; exit the group and store the
-% result in the user's variable. The various conversion functions all
-% act on \cs{g_@@_result_tl}. Errors are silenced for the conditional
-% functions by redefining \cs{@@_if_flag_error:nnx} locally.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \str_set_convert:Nnnn
- { \@@_convert:nNNnnn { } \tl_set_eq:NN }
-\cs_new_protected_nopar:Npn \str_gset_convert:Nnnn
- { \@@_convert:nNNnnn { } \tl_gset_eq:NN }
-\prg_new_protected_conditional:Npnn
- \str_set_convert:Nnnn #1#2#3#4 { T , F , TF }
- {
- \bool_gset_false:N \g_@@_error_bool
- \@@_convert:nNNnnn
- { \cs_set_eq:NN \@@_if_flag_error:nnx \@@_if_flag_no_error:nnx }
- \tl_set_eq:NN #1 {#2} {#3} {#4}
- \bool_if:NTF \g_@@_error_bool \prg_return_false: \prg_return_true:
- }
-\prg_new_protected_conditional:Npnn
- \str_gset_convert:Nnnn #1#2#3#4 { T , F , TF }
- {
- \bool_gset_false:N \g_@@_error_bool
- \@@_convert:nNNnnn
- { \cs_set_eq:NN \@@_if_flag_error:nnx \@@_if_flag_no_error:nnx }
- \tl_gset_eq:NN #1 {#2} {#3} {#4}
- \bool_if:NTF \g_@@_error_bool \prg_return_false: \prg_return_true:
- }
-\cs_new_protected:Npn \@@_convert:nNNnnn #1#2#3#4#5#6
- {
- \group_begin:
- #1
- \@@_gset_other:Nn \g_@@_result_tl {#4}
- \exp_after:wN \@@_convert:wwwnn
- \tl_to_str:n {#5} /// \q_stop
- { decode } { unescape }
- \prg_do_nothing:
- \@@_convert_decode_:
- \exp_after:wN \@@_convert:wwwnn
- \tl_to_str:n {#6} /// \q_stop
- { encode } { escape }
- \use_ii_i:nn
- \@@_convert_encode_:
- \group_end:
- #2 #3 \g_@@_result_tl
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[aux]{\@@_convert:wwwnn}
-% \begin{macro}[aux]{\@@_convert:NNnNN}
-% The task of \cs{@@_convert:wwwnn} is to split
-% \meta{encoding}/\meta{escaping} pairs into their components, |#1|
-% and |#2|. Calls to \cs{@@_convert:nnn} ensure that the
-% corresponding conversion functions are defined. The third auxiliary
-% does the main work.
-% \begin{itemize}
-% \item |#1| is the encoding conversion function;
-% \item |#2| is the escaping function;
-% \item |#3| is the escaping name for use in an error message;
-% \item |#4| is \cs{prg_do_nothing:} for unescaping/decoding, and
-% \cs{use_ii_i:nn} for encoding/escaping;
-% \item |#5| is the default encoding function (either
-% \enquote{decode} or \enquote{encode}), for which there should be
-% no escaping.
-% \end{itemize}
-% Let us ignore the native encoding for a second. In the
-% unescaping/decoding phase, we want to do |#2#1| in this order, and
-% in the encoding/escaping phase, the order should be reversed:
-% |#4#2#1| does exactly that. If one of the encodings is the default
-% (native), then the escaping should be ignored, with an error if any
-% was given, and only the encoding, |#1|, should be performed.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_convert:wwwnn
- #1 / #2 // #3 \q_stop #4#5
- {
- \@@_convert:nnn {enc} {#4} {#1}
- \@@_convert:nnn {esc} {#5} {#2}
- \exp_args:Ncc \@@_convert:NNnNN
- { @@_convert_#4_#1: } { @@_convert_#5_#2: } {#2}
- }
-\cs_new_protected:Npn \@@_convert:NNnNN #1#2#3#4#5
- {
- \if_meaning:w #1 #5
- \tl_if_empty:nF {#3}
- { \__msg_kernel_error:nnx { str } { native-escaping } {#3} }
- #1
- \else:
- #4 #2 #1
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[aux]{\@@_convert:nnn}
-% \begin{macro}[aux]{\@@_convert:nnnn}
-% The arguments of \cs{@@_convert:nnn} are: \texttt{enc} or
-% \texttt{esc}, used to build filenames, the type of the conversion
-% (unescape, decode, encode, escape), and the encoding or escaping
-% name. If the function is already defined, no need to do anything.
-% Otherwise, filter out all non-alphanumerics in the name, and
-% lowercase it. Feed that, and the same three arguments, to
-% \cs{@@_convert:nnnn}. The task is then to make sure that the
-% conversion function |#3_#1| corresponding to the type |#3| and
-% filtered name |#1| is defined, then set our initial conversion
-% function |#3_#4| equal to that.
-%
-% How do we get the |#3_#1| conversion to be defined if it isn't?
-% Two main cases.
-%
-% First, if |#1| is a key in \cs{g_@@_alias_prop}, then the value
-% \cs{l_@@_internal_tl} tells us what file to load. Loading is
-% skipped if the file was already read, \emph{i.e.}, if the conversion
-% command based on \cs{l_@@_internal_tl} already exists. Otherwise,
-% try to load the file; if that fails, there is an error, use the
-% default empty name instead.
-%
-% Second, |#1| may be absent from the property list. The
-% \cs{cs_if_exist:cF} test is automatically false, and we search for a
-% file defining the encoding or escaping |#1| (this should allow
-% third-party \texttt{.def} files). If the file is not found, there is
-% an error, use the default empty name instead.
-%
-% In all cases, the conversion based on \cs{l_@@_internal_tl} is
-% defined, so we can set the |#3_#1| function equal to that. In some
-% cases (\emph{e.g.}, \texttt{utf16be}), the |#3_#1| function is
-% actually defined within the file we just loaded, and it is different
-% from the \cs{l_@@_internal_tl}-based function: we mustn't clobber
-% that different definition.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_convert:nnn #1#2#3
- {
- \cs_if_exist:cF { @@_convert_#2_#3: }
- {
- \exp_args:Nx \@@_convert:nnnn
- { \@@_convert_lowercase_alphanum:n {#3} }
- {#1} {#2} {#3}
- }
- }
-\cs_new_protected:Npn \@@_convert:nnnn #1#2#3#4
- {
- \cs_if_exist:cF { @@_convert_#3_#1: }
- {
- \prop_get:NnNF \g_@@_alias_prop {#1} \l_@@_internal_tl
- { \tl_set:Nn \l_@@_internal_tl {#1} }
- \cs_if_exist:cF { @@_convert_#3_ \l_@@_internal_tl : }
- {
- \file_if_exist:nTF { l3str-#2- \l_@@_internal_tl .def }
- {
- \group_begin:
- \@@_load_catcodes:
- \file_input:n { l3str-#2- \l_@@_internal_tl .def }
- \group_end:
- }
- {
- \tl_clear:N \l_@@_internal_tl
- \__msg_kernel_error:nnxx { str } { unknown-#2 } {#4} {#1}
- }
- }
- \cs_if_exist:cF { @@_convert_#3_#1: }
- {
- \cs_gset_eq:cc { @@_convert_#3_#1: }
- { @@_convert_#3_ \l_@@_internal_tl : }
- }
- }
- \cs_gset_eq:cc { @@_convert_#3_#4: } { @@_convert_#3_#1: }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int, rEXP]{\@@_convert_lowercase_alphanum:n}
-% \begin{macro}[aux, rEXP]{\@@_convert_lowercase_alphanum_loop:N}
-% This function keeps only letters and digits, with upper case letters
-% converted to lower case.
-% \begin{macrocode}
-\cs_new:Npn \@@_convert_lowercase_alphanum:n #1
- {
- \exp_after:wN \@@_convert_lowercase_alphanum_loop:N
- \tl_to_str:n {#1} { ? \__prg_break: }
- \__prg_break_point:
- }
-\cs_new:Npn \@@_convert_lowercase_alphanum_loop:N #1
- {
- \use_none:n #1
- \if_int_compare:w `#1 < \c_ninety_one
- \if_int_compare:w `#1 < \c_sixty_five
- \if_int_compare:w \c_one < 1#1 \exp_stop_f:
- #1
- \fi:
- \else:
- \@@_output_byte:n { `#1 + \c_thirty_two }
- \fi:
- \else:
- \if_int_compare:w `#1 < \c_one_hundred_twenty_three
- \if_int_compare:w `#1 < \c_ninety_seven
- \else:
- #1
- \fi:
- \fi:
- \fi:
- \@@_convert_lowercase_alphanum_loop:N
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_load_catcodes:}
-% Since encoding files may be loaded at arbitrary places in a \TeX{}
-% document, including within verbatim mode, we set the catcodes of all
-% characters appearing in any encoding definition file.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_load_catcodes:
- {
- \char_set_catcode_escape:N \\
- \char_set_catcode_group_begin:N \{
- \char_set_catcode_group_end:N \}
- \char_set_catcode_math_toggle:N \$
- \char_set_catcode_alignment:N \&
- \char_set_catcode_parameter:N \#
- \char_set_catcode_math_superscript:N \^
- \char_set_catcode_ignore:N \ %
- \char_set_catcode_space:N \~
- \tl_map_function:nN { abcdefghijklmnopqrstuvwxyz_:ABCDEFILNPSTUX }
- \char_set_catcode_letter:N
- \tl_map_function:nN { 0123456789"'?*+-.(),`!/<>[];= }
- \char_set_catcode_other:N
- \char_set_catcode_comment:N \%
- \int_set:Nn \tex_endlinechar:D {32}
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Byte unescape and escape}
-%
-% Strings of bytes may need to be stored in auxiliary files in safe
-% \enquote{escaping} formats. Each such escaping is only loaded as
-% needed. By default, on input any non-byte is filtered out, while the
-% output simply consists in letting bytes through.
-%
-% \begin{macro}[int, rEXP]{\@@_filter_bytes:n}
-% \begin{macro}[aux, rEXP]{\@@_filter_bytes_aux:N}
-% In the case of pdf\TeX{}, every character is a byte. For
-% Unicode-aware engines, test the character code; non-bytes cause us
-% to raise the flag \texttt{str_byte}. Spaces have already been given
-% the correct category code when this function is called.
-% \begin{macrocode}
-\pdftex_if_engine:TF
- { \cs_new_eq:NN \@@_filter_bytes:n \use:n }
- {
- \cs_new:Npn \@@_filter_bytes:n #1
- {
- \@@_filter_bytes_aux:N #1
- { ? \__prg_break: }
- \__prg_break_point:
- }
- \cs_new:Npn \@@_filter_bytes_aux:N #1
- {
- \use_none:n #1
- \if_int_compare:w `#1 < 256 \exp_stop_f:
- #1
- \else:
- \flag_raise:n { str_byte }
- \fi:
- \@@_filter_bytes_aux:N
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_unescape_:}
-% \begin{macro}[int]{\@@_convert_unescape_bytes:}
-% The simplest unescaping method removes non-bytes from
-% \cs{g_@@_result_tl}.
-% \begin{macrocode}
-\pdftex_if_engine:TF
- { \cs_new_protected_nopar:Npn \@@_convert_unescape_: { } }
- {
- \cs_new_protected_nopar:Npn \@@_convert_unescape_:
- {
- \flag_clear:n { str_byte }
- \tl_gset:Nx \g_@@_result_tl
- { \exp_args:No \@@_filter_bytes:n \g_@@_result_tl }
- \@@_if_flag_error:nnx { str_byte } { non-byte } { bytes }
- }
- }
-\cs_new_eq:NN \@@_convert_unescape_bytes: \@@_convert_unescape_:
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_escape_:}
-% \begin{macro}[int]{\@@_convert_escape_bytes:}
-% The simplest form of escape leaves the bytes from the previous step
-% of the conversion unchanged.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_convert_escape_: { }
-\cs_new_eq:NN \@@_convert_escape_bytes: \@@_convert_escape_:
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Native strings}
-%
-% \begin{macro}[int]{\@@_convert_decode_:}
-% \begin{macro}[aux, rEXP]{\@@_decode_native_char:N}
-% Convert each character to its character code, one at a time.
-% \begin{macrocode}
-\cs_new_protected_nopar:Npn \@@_convert_decode_:
- { \@@_convert_gmap:N \@@_decode_native_char:N }
-\cs_new:Npn \@@_decode_native_char:N #1
- { #1 \s__tl \__int_value:w `#1 \s__tl }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_encode_:}
-% The conversion from an internal string to native character tokens is
-% very different in pdf\TeX{} and in other engines. For Unicode-aware
-% engines, we need the definitions to be read when the null byte has
-% category code $12$, so we set that inside a group.
-% \begin{macrocode}
-\group_begin:
- \char_set_catcode_other:n { 0 }
- \pdftex_if_engine:TF
-% \end{macrocode}
-% \begin{macro}[aux, EXP]{\@@_encode_native_char:n}
-% Since pdf\TeX{} only supports 8-bit characters, and we have a table
-% of all bytes, the conversion can be done in linear time within an
-% \texttt{x}-expanding assignment. Look out for character codes larger
-% than $255$, those characters are replaced by |?|, and raise a flag,
-% which then triggers a pdf\TeX{}-specific error.
-% \begin{macrocode}
- {
- \cs_new_protected_nopar:Npn \@@_convert_encode_:
- {
- \flag_clear:n { str_error }
- \@@_convert_gmap_internal:N \@@_encode_native_char:n
- \@@_if_flag_error:nnx { str_error }
- { pdfTeX-native-overflow } { }
- }
- \cs_new:Npn \@@_encode_native_char:n #1
- {
- \if_int_compare:w #1 < \c_two_hundred_fifty_six
- \@@_output_byte:n {#1}
- \else:
- \flag_raise:n { str_error }
- ?
- \fi:
- }
- \__msg_kernel_new:nnnn { str } { pdfTeX-native-overflow }
- { Character~code~too~large~for~pdfTeX. }
- {
- The~pdfTeX~engine~only~supports~8-bit~characters:~
- valid~character~codes~are~in~the~range~[0,255].~
- To~manipulate~arbitrary~Unicode,~use~LuaTeX~or~XeTeX.
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}[aux]{\@@_encode_native_loop:w}
-% \begin{macro}[aux]{\@@_encode_native_flush:}
-% \begin{macro}[aux, rEXP]{\@@_encode_native_filter:N}
-% In Unicode-aware engines, since building particular characters
-% cannot be done expandably in \TeX{}, we cannot hope to get a
-% linear-time function. However, we get quite close using the
-% \pkg{l3tl-build} module, which abuses \tn{toks} to reach an almost
-% linear time. Use the standard lowercase trick to produce an
-% arbitrary character from the null character, and add that character
-% to the end of the token list being built. At the end of the loop,
-% put the token list together with \cs{__tl_build_end:}. Note that we
-% use an \texttt{x}-expanding assignment because it is slightly
-% faster. Unicode-aware engines will never incur an overflow because
-% the internal string is guaranteed to only contain code points in
-% $[0,\hexnum{10FFFF}]$.
-% \begin{macrocode}
- {
- \cs_new_protected_nopar:Npn \@@_convert_encode_:
- {
- \int_zero:N \l__tl_build_offset_int
- \__tl_gbuild_x:Nw \g_@@_result_tl
- \exp_after:wN \@@_encode_native_loop:w
- \g_@@_result_tl \s__tl { \q_stop \__prg_break: } \s__tl
- \__prg_break_point:
- \__tl_build_end:
- }
- \cs_new_protected:Npn \@@_encode_native_loop:w #1 \s__tl #2 \s__tl
- {
- \use_none_delimit_by_q_stop:w #2 \q_stop
- \tex_lccode:D \l_@@_internal_int \__int_eval:w #2 \__int_eval_end:
- \tl_to_lowercase:n { \__tl_build_one:n { ^^@ } }
- \@@_encode_native_loop:w
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% End the group to restore the catcode of the null byte.
-% \begin{macrocode}
-\group_end:
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{8-bit encodings}
-%
-% This section will be entirely rewritten: it is not yet clear in what
-% situations 8-bit encodings are used, hence I don't know what exactly
-% should be optimized. The current approach is reasonably efficient to
-% convert long strings, and it scales well when using many different
-% encodings. An approach based on csnames would have a smaller constant
-% load time for each individual conversion, but has a large hash table
-% cost. Using a range of \tn{count} registers works for decoding, but
-% not for encoding: one possibility there would be to use a binary tree
-% for the mapping of Unicode characters to bytes, stored as a box, one
-% per encoding.
-%
-% Since the section is going to be rewritten, documentation lacks.
-%
-% All the 8-bit encodings which \pkg{l3str} supports rely on the same
-% internal functions.
-%
-% \begin{macro}[int]{\@@_declare_eight_bit_encoding:nnn}
-% \begin{syntax}
-% \cs{@@_declare_eight_bit_encoding:nnn} \Arg{name} \Arg{mapping} \Arg{missing}
-% \end{syntax}
-% This declares the encoding \meta{name} to map bytes to Unicode
-% characters according to the \meta{mapping}, and map those bytes
-% which are not mentionned in the \meta{mapping} either to the
-% replacement character (if they appear in \meta{missing}), or to
-% themselves.
-%
-% All the 8-bit encoding definition file start with
-% \cs{@@_declare_eight_bit_encoding:nnn} \Arg{encoding name}
-% \Arg{mapping} \Arg{missing bytes}. The \meta{mapping} argument is a
-% token list of pairs \Arg{byte} \Arg{Unicode} expressed in uppercase
-% hexadecimal notation. The \meta{missing} argument is a token list
-% of \Arg{byte}. Every \meta{byte} which does not appear in the
-% \meta{mapping} nor the \meta{missing} lists maps to the same code
-% point in Unicode.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_declare_eight_bit_encoding:nnn #1#2#3
- {
- \tl_set:Nn \l_@@_internal_tl {#1}
- \cs_new_protected_nopar:cpn { @@_convert_decode_#1: }
- { \@@_convert_decode_eight_bit:n {#1} }
- \cs_new_protected_nopar:cpn { @@_convert_encode_#1: }
- { \@@_convert_encode_eight_bit:n {#1} }
- \tl_const:cn { c_@@_encoding_#1_tl } {#2}
- \tl_const:cn { c_@@_encoding_#1_missing_tl } {#3}
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_decode_eight_bit:n}
-% \begin{macro}[aux]{\@@_decode_eight_bit_load:nn}
-% \begin{macro}[aux]{\@@_decode_eight_bit_load_missing:n}
-% \begin{macro}[aux, EXP]{\@@_decode_eight_bit_char:N}
-%^^A todo: document
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_convert_decode_eight_bit:n #1
- {
- \group_begin:
- \int_zero:N \l_@@_internal_int
- \exp_last_unbraced:Nx \@@_decode_eight_bit_load:nn
- { \tl_use:c { c_@@_encoding_#1_tl } }
- { \q_stop \__prg_break: } { }
- \__prg_break_point:
- \exp_last_unbraced:Nx \@@_decode_eight_bit_load_missing:n
- { \tl_use:c { c_@@_encoding_#1_missing_tl } }
- { \q_stop \__prg_break: }
- \__prg_break_point:
- \flag_clear:n { str_error }
- \@@_convert_gmap:N \@@_decode_eight_bit_char:N
- \@@_if_flag_error:nnx { str_error } { decode-8-bit } {#1}
- \group_end:
- }
-\cs_new_protected:Npn \@@_decode_eight_bit_load:nn #1#2
- {
- \use_none_delimit_by_q_stop:w #1 \q_stop
- \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop:
- \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop:
- \tex_toks:D \l_@@_internal_int \exp_after:wN { \__int_value:w "#2 }
- \tex_advance:D \l_@@_internal_int \c_one
- \@@_decode_eight_bit_load:nn
- }
-\cs_new_protected:Npn \@@_decode_eight_bit_load_missing:n #1
- {
- \use_none_delimit_by_q_stop:w #1 \q_stop
- \tex_dimen:D "#1 = \l_@@_internal_int sp \scan_stop:
- \tex_skip:D \l_@@_internal_int = "#1 sp \scan_stop:
- \tex_toks:D \l_@@_internal_int \exp_after:wN
- { \int_use:N \c_@@_replacement_char_int }
- \tex_advance:D \l_@@_internal_int \c_one
- \@@_decode_eight_bit_load_missing:n
- }
-\cs_new:Npn \@@_decode_eight_bit_char:N #1
- {
- #1 \s__tl
- \if_int_compare:w \tex_dimen:D `#1 < \l_@@_internal_int
- \if_int_compare:w \tex_skip:D \tex_dimen:D `#1 = `#1 \exp_stop_f:
- \tex_the:D \tex_toks:D \tex_dimen:D
- \fi:
- \fi:
- \__int_value:w `#1 \s__tl
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_encode_eight_bit:n}
-% \begin{macro}[aux]{\@@_encode_eight_bit_load:nn}
-% \begin{macro}[aux, rEXP]{\@@_encode_eight_bit_char:n}
-% \begin{macro}[aux, rEXP]{\@@_encode_eight_bit_char_aux:n}
-%^^A todo: document
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_convert_encode_eight_bit:n #1
- {
- \group_begin:
- \int_zero:N \l_@@_internal_int
- \exp_last_unbraced:Nx \@@_encode_eight_bit_load:nn
- { \tl_use:c { c_@@_encoding_#1_tl } }
- { \q_stop \__prg_break: } { }
- \__prg_break_point:
- \flag_clear:n { str_error }
- \@@_convert_gmap_internal:N \@@_encode_eight_bit_char:n
- \@@_if_flag_error:nnx { str_error } { encode-8-bit } {#1}
- \group_end:
- }
-\cs_new_protected:Npn \@@_encode_eight_bit_load:nn #1#2
- {
- \use_none_delimit_by_q_stop:w #1 \q_stop
- \tex_dimen:D "#2 = \l_@@_internal_int sp \scan_stop:
- \tex_skip:D \l_@@_internal_int = "#2 sp \scan_stop:
- \exp_args:NNf \tex_toks:D \l_@@_internal_int
- { \@@_output_byte:n { "#1 } }
- \tex_advance:D \l_@@_internal_int \c_one
- \@@_encode_eight_bit_load:nn
- }
-\cs_new:Npn \@@_encode_eight_bit_char:n #1
- {
- \if_int_compare:w #1 > \c_max_register_int
- \flag_raise:n { str_error }
- \else:
- \if_int_compare:w \tex_dimen:D #1 < \l_@@_internal_int
- \if_int_compare:w \tex_skip:D \tex_dimen:D #1 = #1 \exp_stop_f:
- \tex_the:D \tex_toks:D \tex_dimen:D #1 \exp_stop_f:
- \exp_after:wN \exp_after:wN \exp_after:wN \use_none:nn
- \fi:
- \fi:
- \@@_encode_eight_bit_char_aux:n {#1}
- \fi:
- }
-\cs_new:Npn \@@_encode_eight_bit_char_aux:n #1
- {
- \if_int_compare:w #1 < \c_two_hundred_fifty_six
- \@@_output_byte:n {#1}
- \else:
- \flag_raise:n { str_error }
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Messages}
-%
-% General messages, and messages for the encodings and escapings loaded
-% by default (\enquote{native}, and \enquote{bytes}).
-% \begin{macrocode}
-\__msg_kernel_new:nnn { str } { unknown-esc }
- { Escaping~scheme~'#1'~(filtered:~'#2')~unknown. }
-\__msg_kernel_new:nnn { str } { unknown-enc }
- { Encoding~scheme~'#1'~(filtered:~'#2')~unknown. }
-\__msg_kernel_new:nnnn { str } { native-escaping }
- { The~'native'~encoding~scheme~does~not~support~any~escaping. }
- {
- Since~native~strings~do~not~consist~in~bytes,~
- none~of~the~escaping~methods~make~sense.~
- The~specified~escaping,~'#1',~will be ignored.
- }
-\__msg_kernel_new:nnn { str } { file-not-found }
- { File~'l3str-#1.def'~not~found. }
-% \end{macrocode}
-%
-% Message used when the \enquote{bytes} unescaping fails because the
-% string given to \cs{str_set_convert:Nnnn} contains a non-byte. This
-% cannot happen for the pdf\TeX{} engine, since that engine only
-% supports 8-bit characters. Messages used for other escapings and
-% encodings are defined in each definition file.
-% \begin{macrocode}
-\pdftex_if_engine:F
- {
- \__msg_kernel_new:nnnn { str } { non-byte }
- { String~invalid~in~escaping~'#1':~it~may~only~contain~bytes. }
- {
- Some~characters~in~the~string~you~asked~to~convert~are~not~
- 8-bit~characters.~Perhaps~the~string~is~a~'native'~Unicode~string?~
- If~it~is,~try~using\\
- \\
- \iow_indent:n
- {
- \iow_char:N\\str_set_convert:Nnnn \\
- \ \ <str~var>~\{~<string>~\}~\{~native~\}~\{~<target~encoding>~\}
- }
- }
- }
-% \end{macrocode}
-%
-% Those messages are used when converting to and from 8-bit encodings.
-% \begin{macrocode}
-\__msg_kernel_new:nnnn { str } { decode-8-bit }
- { Invalid~string~in~encoding~'#1'. }
- {
- LaTeX~came~across~a~byte~which~is~not~defined~to~represent~
- any~character~in~the~encoding~'#1'.
- }
-\__msg_kernel_new:nnnn { str } { encode-8-bit }
- { Unicode~string~cannot~be~converted~to~encoding~'#1'. }
- {
- The~encoding~'#1'~only~contains~a~subset~of~all~Unicode~characters.~
- LaTeX~was~asked~to~convert~a~string~to~that~encoding,~but~that~
- string~contains~a~character~that~'#1'~does~not~support.
- }
-% \end{macrocode}
-%
% \subsection{Deprecated string functions}
-%
-% Deprecated 2012-05-13 for removal by 2012-08-31.
-%
-% \begin{macro}{\str_length:N, \str_length:n, \str_length_ignore_spaces:n}
-% \begin{macrocode}
-\cs_new_eq:NN \str_length:N \str_count:N
-\cs_new_eq:NN \str_length:n \str_count:n
-\cs_new_eq:NN \str_length_ignore_spaces:n \str_count_ignore_spaces:n
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macrocode}
-%</initex|package>
-% \end{macrocode}
-%
-% \subsection{Escaping definition files}
-%
-% Several of those encodings are defined by the pdf file format. The
-% following byte storage methods are defined:
-% \begin{itemize}
-% \item \texttt{bytes} (default), non-bytes are filtered out, and
-% bytes are left untouched (this is defined by default);
-% \item \texttt{hex} or \texttt{hexadecimal}, as per the pdf\TeX{}
-% primitive \tn{pdfescapehex}
-% \item \texttt{name}, as per the pdf\TeX{} primitive
-% \tn{pdfescapename}
-% \item \texttt{string}, as per the pdf\TeX{} primitive
-% \tn{pdfescapestring}
-% \item \texttt{url}, as per the percent encoding of urls.
-% \end{itemize}
-%
-% \subsubsection{Unescape methods}
-%
-% \begin{macro}[int]{\@@_convert_unescape_hex:}
-% \begin{macro}[aux, rEXP]{\@@_unescape_hex_auxi:N}
-% \begin{macro}[aux, rEXP]{\@@_unescape_hex_auxii:N}
-% Take chars two by two, and interpret each pair as the hexadecimal
-% code for a byte. Anything else than hexadecimal digits is ignored,
-% raising the flag. A string which contains an odd number of
-% hexadecimal digits gets |0| appended to it: this is equivalent to
-% appending a |0| in all cases, and dropping it if it is alone.
-% \begin{macrocode}
-%<*hex>
-\cs_new_protected_nopar:Npn \@@_convert_unescape_hex:
- {
- \group_begin:
- \flag_clear:n { str_error }
- \int_set:Nn \tex_escapechar:D { 92 }
- \tl_gset:Nx \g_@@_result_tl
- {
- \@@_output_byte:w "
- \exp_last_unbraced:Nf \@@_unescape_hex_auxi:N
- { \tl_to_str:N \g_@@_result_tl }
- 0 { ? 0 - \c_one \__prg_break: }
- \__prg_break_point:
- \@@_output_end:
- }
- \@@_if_flag_error:nnx { str_error } { unescape-hex } { }
- \group_end:
- }
-\cs_new:Npn \@@_unescape_hex_auxi:N #1
- {
- \use_none:n #1
- \@@_hexadecimal_use:NTF #1
- { \@@_unescape_hex_auxii:N }
- {
- \flag_raise:n { str_error }
- \@@_unescape_hex_auxi:N
- }
- }
-\cs_new:Npn \@@_unescape_hex_auxii:N #1
- {
- \use_none:n #1
- \@@_hexadecimal_use:NTF #1
- {
- \@@_output_end:
- \@@_output_byte:w " \@@_unescape_hex_auxi:N
- }
- {
- \flag_raise:n { str_error }
- \@@_unescape_hex_auxii:N
- }
- }
-\__msg_kernel_new:nnnn { str } { unescape-hex }
- { String~invalid~in~escaping~'hex':~only~hexadecimal~digits~allowed. }
- {
- Some~characters~in~the~string~you~asked~to~convert~are~not~
- hexadecimal~digits~(0-9,~A-F,~a-f)~nor~spaces.
- }
-%</hex>
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_unescape_name:}
-% \begin{macro}[aux, rEXP]{\@@_unescape_name_loop:wNN}
-% \begin{macro}[int]{\@@_convert_unescape_url:}
-% \begin{macro}[aux, rEXP]{\@@_unescape_url_loop:wNN}
-% The \cs{@@_convert_unescape_name:} function replaces each
-% occurrence of |#| followed by two hexadecimal digits in
-% \cs{g_@@_result_tl} by the corresponding byte. The \texttt{url}
-% function is identical, with escape character |%| instead of |#|.
-% Thus we define the two together. The arguments of \cs{@@_tmp:w} are
-% the character code of |#| or |%| in hexadecimal, the name of the
-% main function to define, and the name of the auxiliary which
-% performs the loop.
-%
-% The looping auxiliary |#3| finds the next escape character, reads
-% the following two characters, and tests them. The test
-% \cs{@@_hexadecimal_use:NTF} leaves the upper-case digit in the
-% input stream, hence we surround the test with
-% \cs{@@_output_byte:w}~|"| and \cs{@@_output_end:}. If both
-% characters are hexadecimal digits, they should be removed before
-% looping: this is done by \cs{use_i:nnn}. If one of the characters
-% is not a hexadecimal digit, then feed |"#1| to
-% \cs{@@_output_byte:w} to produce the escape character, raise the
-% flag, and call the looping function followed by the two characters
-% (remove \cs{use_i:nnn}).
-% \begin{macrocode}
-%<*name|url>
-\cs_set_protected:Npn \@@_tmp:w #1#2#3
- {
- \cs_new_protected:cpn { @@_convert_unescape_#2: }
- {
- \group_begin:
- \flag_clear:n { str_byte }
- \flag_clear:n { str_error }
- \int_set:Nn \tex_escapechar:D { 92 }
- \tl_gset:Nx \g_@@_result_tl
- {
- \exp_after:wN #3 \g_@@_result_tl
- #1 ? { ? \__prg_break: }
- \__prg_break_point:
- }
- \@@_if_flag_error:nnx { str_byte } { non-byte } { #2 }
- \@@_if_flag_error:nnx { str_error } { unescape-#2 } { }
- \group_end:
- }
- \cs_new:Npn #3 ##1#1##2##3
- {
- \@@_filter_bytes:n {##1}
- \use_none:n ##3
- \@@_output_byte:w "
- \@@_hexadecimal_use:NTF ##2
- {
- \@@_hexadecimal_use:NTF ##3
- { }
- {
- \flag_raise:n { str_error }
- * \c_zero + `#1 \use_i:nn
- }
- }
- {
- \flag_raise:n { str_error }
- 0 + `#1 \use_i:nn
- }
- \@@_output_end:
- \use_i:nnn #3 ##2##3
- }
- \__msg_kernel_new:nnnn { str } { unescape-#2 }
- { String~invalid~in~escaping~'#2'. }
- {
- LaTeX~came~across~the~escape~character~'#1'~not~followed~by~
- two~hexadecimal~digits.~This~is~invalid~in~the~escaping~'#2'.
- }
- }
-%</name|url>
-%<*name>
-\exp_after:wN \@@_tmp:w \c_hash_str { name }
- \@@_unescape_name_loop:wNN
-%</name>
-%<*url>
-\exp_after:wN \@@_tmp:w \c_percent_str { url }
- \@@_unescape_url_loop:wNN
-%</url>
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_unescape_string:}
-% \begin{macro}[aux, rEXP]{\@@_unescape_string_newlines:wN}
-% \begin{macro}[aux, rEXP]{\@@_unescape_string_loop:wNNN}
-% \begin{macro}[aux, rEXP]{\@@_unescape_string_repeat:NNNNNN}
-% The \texttt{string} escaping is somewhat similar to the
-% \texttt{name} and \texttt{url} escapings, with escape character |\|.
-% The first step is to convert all three line endings, |^^J|, |^^M|,
-% and |^^M^^J| to the common |^^J|, as per the \textsc{pdf}
-% specification. This step cannot raise the flag.
-%
-% Then the following escape sequences are decoded.
-% \begin{itemize}\def\makelabel#1{\hss\llap{\ttfamily\string#1}}
-% \item[\n] Line feed ($10$)
-% \item[\r] Carriage return ($13$)
-% \item[\t] Horizontal tab ($9$)
-% \item[\b] Backspace ($8$)
-% \item[\f] Form feed ($12$)
-% \item[\(] Left parenthesis
-% \item[\)] Right parenthesis
-% \item[\\] Backslash
-% \item[\ddd] (backslash followed by $1$ to $3$ octal digits) Byte
-% \texttt{ddd} (octal), subtracting $256$ in case of overflow.
-% \end{itemize}
-% If followed by an end-of-line character, the backslash and the
-% end-of-line are ignored. If followed by anything else, the backslash
-% is ignored, raising the error flag.
-%^^A Be paranoid: \tl_to_lowercase:n is unsafe.
-% \begin{macrocode}
-%<*string>
-\group_begin:
- \char_set_lccode:nn {`\*} {`\\}
- \char_set_catcode_other:N \^^J
- \char_set_catcode_other:N \^^M
- \tl_to_lowercase:n
- {
- \cs_new_protected_nopar:Npn \@@_convert_unescape_string:
- {
- \group_begin:
- \flag_clear:n { str_byte }
- \flag_clear:n { str_error }
- \int_set:Nn \tex_escapechar:D { 92 }
- \tl_gset:Nx \g_@@_result_tl
- {
- \exp_after:wN \@@_unescape_string_newlines:wN
- \g_@@_result_tl \__prg_break: ^^M ?
- \__prg_break_point:
- }
- \tl_gset:Nx \g_@@_result_tl
- {
- \exp_after:wN \@@_unescape_string_loop:wNNN
- \g_@@_result_tl * ?? { ? \__prg_break: }
- \__prg_break_point:
- }
- \@@_if_flag_error:nnx { str_byte } { non-byte } { string }
- \@@_if_flag_error:nnx { str_error } { unescape-string } { }
- \group_end:
- }
- \cs_new:Npn \@@_unescape_string_loop:wNNN #1 *#2#3#4
- }
- {
- \@@_filter_bytes:n {#1}
- \use_none:n #4
- \@@_output_byte:w '
- \@@_octal_use:NTF #2
- {
- \@@_octal_use:NTF #3
- {
- \@@_octal_use:NTF #4
- {
- \if_int_compare:w #2 > \c_three
- - 256
- \fi:
- \@@_unescape_string_repeat:NNNNNN
- }
- { \@@_unescape_string_repeat:NNNNNN ? }
- }
- { \@@_unescape_string_repeat:NNNNNN ?? }
- }
- {
- \str_case_x:nnn {#2}
- {
- { \c_backslash_str } { 134 }
- { ( } { 50 }
- { ) } { 51 }
- { r } { 15 }
- { f } { 14 }
- { n } { 12 }
- { t } { 11 }
- { b } { 10 }
- { ^^J } { 0 - \c_one }
- }
- {
- \flag_raise:n { str_error }
- 0 - \c_one \use_i:nn
- }
- }
- \@@_output_end:
- \use_i:nn \@@_unescape_string_loop:wNNN #2#3#4
- }
- \cs_new:Npn \@@_unescape_string_repeat:NNNNNN #1#2#3#4#5#6
- { \@@_output_end: \@@_unescape_string_loop:wNNN }
- \cs_new:Npn \@@_unescape_string_newlines:wN #1 ^^M #2
- {
- #1
- \if_charcode:w ^^J #2 \else: ^^J \fi:
- \@@_unescape_string_newlines:wN #2
- }
- \__msg_kernel_new:nnnn { str } { unescape-string }
- { String~invalid~in~escaping~'string'. }
- {
- LaTeX~came~across~an~escape~character~'\c_backslash_str'~
- not~followed~by~any~of:~'n',~'r',~'t',~'b',~'f',~'(',~')',~
- '\c_backslash_str',~one~to~three~octal~digits,~or~the~end~
- of~a~line.
- }
-\group_end:
-%</string>
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Escape methods}
-%
-% Currently, none of the escape methods can lead to errors, assuming
-% that their input is made out of bytes.
-%
-% \begin{macro}[int]{\@@_convert_escape_hex:}
-% \begin{macro}[aux, rEXP]{\@@_escape_hex_char:N}
-% Loop and convert each byte to hexadecimal.
-% \begin{macrocode}
-%<*hex>
-\cs_new_protected_nopar:Npn \@@_convert_escape_hex:
- { \@@_convert_gmap:N \@@_escape_hex_char:N }
-\cs_new:Npn \@@_escape_hex_char:N #1
- { \@@_output_hexadecimal:n { `#1 } }
-%</hex>
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_escape_name:}
-% \begin{macro}[aux, rEXP]{\@@_escape_name_char:N}
-% \begin{macro}[aux, rEXP]{\@@_if_escape_name:NTF}
-% \begin{variable}{\c_@@_escape_name_str}
-% \begin{variable}{\c_@@_escape_name_not_str}
-% For each byte, test whether it should be output as is, or be
-% \enquote{hash-encoded}. Roughly, bytes outside the range
-% $[\hexnum{2A},\hexnum{7E}]$ are hash-encoded. We keep two lists of
-% exceptions: characters in \cs{c_@@_escape_name_not_str} are not
-% hash-encoded, and characters in the \cs{c_@@_escape_name_str} are
-% encoded.
-% \begin{macrocode}
-%<*name>
-\str_const:Nn \c_@@_escape_name_not_str { ! " $ & ' } %$
-\str_const:Nn \c_@@_escape_name_str { {}/<>[] }
-\cs_new_protected_nopar:Npn \@@_convert_escape_name:
- { \@@_convert_gmap:N \@@_escape_name_char:N }
-\cs_new:Npn \@@_escape_name_char:N #1
- {
- \@@_if_escape_name:NTF #1 {#1}
- { \c_hash_str \@@_output_hexadecimal:n {`#1} }
- }
-\prg_new_conditional:Npnn \@@_if_escape_name:N #1 { TF }
- {
- \if_int_compare:w `#1 < "2A \exp_stop_f:
- \@@_if_contains_char:NNTF \c_@@_escape_name_not_str #1
- \prg_return_true: \prg_return_false:
- \else:
- \if_int_compare:w `#1 > "7E \exp_stop_f:
- \prg_return_false:
- \else:
- \@@_if_contains_char:NNTF \c_@@_escape_name_str #1
- \prg_return_false: \prg_return_true:
- \fi:
- \fi:
- }
-%</name>
-% \end{macrocode}
-% \end{variable}
-% \end{variable}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_escape_string:}
-% \begin{macro}[aux, rEXP]{\@@_escape_string_char:N}
-% \begin{macro}[aux, rEXP]{\@@_if_escape_string:NTF}
-% \begin{variable}{\c_@@_escape_string_str}
-% Any character below (and including) space, and any character above
-% (and including) \texttt{del}, are converted to octal. One backslash
-% is added before each parenthesis and backslash.
-% \begin{macrocode}
-%<*string>
-\str_const:Nx \c_@@_escape_string_str
- { \c_backslash_str ( ) }
-\cs_new_protected_nopar:Npn \@@_convert_escape_string:
- { \@@_convert_gmap:N \@@_escape_string_char:N }
-\cs_new:Npn \@@_escape_string_char:N #1
- {
- \@@_if_escape_string:NTF #1
- {
- \@@_if_contains_char:NNT
- \c_@@_escape_string_str #1
- { \c_backslash_str }
- #1
- }
- {
- \c_backslash_str
- \int_div_truncate:nn {`#1} {64}
- \int_mod:nn { \int_div_truncate:nn {`#1} \c_eight } \c_eight
- \int_mod:nn {`#1} \c_eight
- }
- }
-\prg_new_conditional:Npnn \@@_if_escape_string:N #1 { TF }
- {
- \if_int_compare:w `#1 < "21 \exp_stop_f:
- \prg_return_false:
- \else:
- \if_int_compare:w `#1 > "7E \exp_stop_f:
- \prg_return_false:
- \else:
- \prg_return_true:
- \fi:
- \fi:
- }
-%</string>
-% \end{macrocode}
-% \end{variable}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_convert_escape_url:}
-% \begin{macro}[aux, rEXP]{\@@_escape_url_char:N}
-% \begin{macro}[aux, rEXP]{\@@_if_escape_url:NTF}
-% This function is similar to \cs{@@_convert_escape_name:}, escaping
-% different characters.
-% \begin{macrocode}
-%<*url>
-\cs_new_protected_nopar:Npn \@@_convert_escape_url:
- { \@@_convert_gmap:N \@@_escape_url_char:N }
-\cs_new:Npn \@@_escape_url_char:N #1
- {
- \@@_if_escape_url:NTF #1 {#1}
- { \c_percent_str \@@_output_hexadecimal:n { `#1 } }
- }
-\prg_new_conditional:Npnn \@@_if_escape_url:N #1 { TF }
- {
- \if_int_compare:w `#1 < "41 \exp_stop_f:
- \@@_if_contains_char:nNTF { "-.<> } #1
- \prg_return_true: \prg_return_false:
- \else:
- \if_int_compare:w `#1 > "7E \exp_stop_f:
- \prg_return_false:
- \else:
- \@@_if_contains_char:nNTF { [ ] } #1
- \prg_return_false: \prg_return_true:
- \fi:
- \fi:
- }
-%</url>
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Encoding definition files}
-%
-% The \texttt{native} encoding is automatically defined. Other encodings
-% are loaded as needed. The following encodings are supported:
-% \begin{itemize}
-% \item \textsc{utf-8};
-% \item \textsc{utf-16}, big-, little-endian, or with byte order mark;
-% \item \textsc{utf-32}, big-, little-endian, or with byte order mark;
-% \item the \textsc{iso 8859} code pages, numbered from $1$ to $16$,
-% skipping the inexistent \textsc{iso 8859-12}.
-% \end{itemize}
-%
-% \subsubsection{\textsc{utf-8} support}
-%
-% \begin{macrocode}
-%<*utf8>
-% \end{macrocode}
-%
-% \begin{macro}[int]{\@@_convert_encode_utf8:}
-% \begin{macro}[aux, rEXP]{\@@_encode_utf_viii_char:n}
-% \begin{macro}[aux, rEXP]{\@@_encode_utf_viii_loop:wwnnw}
-% Loop through the internal string, and convert each character to its
-% \textsc{utf-8} representation. The representation is built from the
-% right-most (least significant) byte to the left-most (most
-% significant) byte. Continuation bytes are in the range $[128,191]$,
-% taking $64$ different values, hence we roughly want to express the
-% character code in base $64$, shifting the first digit in the
-% representation by some number depending on how many continuation
-% bytes there are. In the range $[0,127]$, output the corresponding
-% byte directly. In the range $[128,2047]$, output the remainder
-% modulo $64$, plus $128$ as a continuation byte, then output the
-% quotient (which is in the range $[0,31]$), shifted by $192$. In the
-% next range, $[2048,65535]$, split the character code into residue
-% and quotient modulo $64$, output the residue as a first continuation
-% byte, then repeat; this leaves us with a quotient in the range
-% $[0,15]$, which we output shifted by $224$. The last range,
-% $[65536,1114111]$, follows the same pattern: once we realize that
-% dividing twice by $64$ leaves us with a number larger than $15$, we
-% repeat, producing a last continuation byte, and offset the quotient
-% by $240$ for the leading byte.
-%
-% How is that implemented? \cs{@@_encode_utf_vii_loop:wwnnw} takes
-% successive quotients as its first argument, the quotient from the
-% previous step as its second argument (except in step~$1$), the bound
-% for quotients that trigger one more step or not, and finally the
-% offset used if this step should produce the leading byte. Leading
-% bytes can be in the ranges $[0,127]$, $[192,223]$, $[224,239]$, and
-% $[240,247]$ (really, that last limit should be $244$ because Unicode
-% stops at the code point $1114111$). At each step, if the quotient
-% |#1| is less than the limit |#3| for that range, output the leading
-% byte (|#1| shifted by |#4|) and stop. Otherwise, we need one more
-% step: use the quotient of |#1| by $64$, and |#1| as arguments for
-% the looping auxiliary, and output the continuation byte
-% corresponding to the remainder $|#2|-64|#1|+128$. The bizarre
-% construction |\c_minus_one + \c_zero *| removes the spurious initial
-% continuation byte (better methods welcome).
-% \begin{macrocode}
-\cs_new_protected_nopar:cpn { @@_convert_encode_utf8: }
- { \@@_convert_gmap_internal:N \@@_encode_utf_viii_char:n }
-\cs_new:Npn \@@_encode_utf_viii_char:n #1
- {
- \@@_encode_utf_viii_loop:wwnnw #1 ; \c_minus_one + \c_zero * ;
- { 128 } { \c_zero }
- { 32 } { 192 }
- { 16 } { 224 }
- { 8 } { 240 }
- \q_stop
- }
-\cs_new:Npn \@@_encode_utf_viii_loop:wwnnw #1; #2; #3#4 #5 \q_stop
- {
- \if_int_compare:w #1 < #3 \exp_stop_f:
- \@@_output_byte:n { #1 + #4 }
- \exp_after:wN \use_none_delimit_by_q_stop:w
- \fi:
- \exp_after:wN \@@_encode_utf_viii_loop:wwnnw
- \__int_value:w \int_div_truncate:nn {#1} {64} ; #1 ;
- #5 \q_stop
- \@@_output_byte:n { #2 - 64 * ( #1 - \c_two ) }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{variable}
-% {
-% \l_@@_missing_flag ,
-% \l_@@_extra_flag ,
-% \l_@@_overlong_flag ,
-% \l_@@_overflow_flag ,
-% }
-% When decoding a string that is purportedly in the \textsc{utf-8}
-% encoding, four different errors can occur, signalled by a specific
-% flag for each (we define those flags using \cs{flag_clear_new:n}
-% rather than \cs{flag_new:n}, because they are shared with other
-% encoding definition files).
-% \begin{itemize}
-% \item \enquote{Missing continuation byte}: a leading byte is not
-% followed by the right number of continuation bytes.
-% \item \enquote{Extra continuation byte}: a continuation byte
-% appears where it was not expected, \emph{i.e.}, not after an
-% appropriate leading byte.
-% \item \enquote{Overlong}: a Unicode character is expressed using
-% more bytes than necessary, for instance, \hexnum{C0}\hexnum{80}
-% for the code point $0$, instead of a single null byte.
-% \item \enquote{Overflow}: this occurs when decoding produces
-% Unicode code points greater than $1114111$.
-% \end{itemize}
-% We only raise one \LaTeX3 error message, combining all the errors
-% which occurred. In the short message, the leading comma must be
-% removed to get a grammatically correct sentence. In the long text,
-% first remind the user what a correct \textsc{utf-8} string should
-% look like, then add error-specific information.
-% \begin{macrocode}
-\flag_clear_new:n { str_missing }
-\flag_clear_new:n { str_extra }
-\flag_clear_new:n { str_overlong }
-\flag_clear_new:n { str_overflow }
-\__msg_kernel_new:nnnn { str } { utf8-decode }
- {
- Invalid~UTF-8~string: \exp_last_unbraced:Nf \use_none:n
- \@@_if_flag_times:nT { str_missing } { ,~missing~continuation~byte }
- \@@_if_flag_times:nT { str_extra } { ,~extra~continuation~byte }
- \@@_if_flag_times:nT { str_overlong } { ,~overlong~form }
- \@@_if_flag_times:nT { str_overflow } { ,~code~point~too~large }
- .
- }
- {
- In~the~UTF-8~encoding,~each~Unicode~character~consists~in~
- 1~to~4~bytes,~with~the~following~bit~pattern: \\
- \iow_indent:n
- {
- Code~point~\ \ \ \ <~128:~0xxxxxxx \\
- Code~point~\ \ \ <~2048:~110xxxxx~10xxxxxx \\
- Code~point~\ \ <~65536:~1110xxxx~10xxxxxx~10xxxxxx \\
- Code~point~ <~1114112:~11110xxx~10xxxxxx~10xxxxxx~10xxxxxx \\
- }
- Bytes~of~the~form~10xxxxxx~are~called~continuation~bytes.
- \flag_if_raised:nT { str_missing }
- {
- \\\\
- A~leading~byte~(in~the~range~[192,255])~was~not~followed~by~
- the~appropriate~number~of~continuation~bytes.
- }
- \flag_if_raised:nT { str_extra }
- {
- \\\\
- LaTeX~came~across~a~continuation~byte~when~it~was~not~expected.
- }
- \flag_if_raised:nT { str_overlong }
- {
- \\\\
- Every~Unicode~code~point~must~be~expressed~in~the~shortest~
- possible~form.~For~instance,~'0xC0'~'0x83'~is~not~a~valid~
- representation~for~the~code~point~3.
- }
- \flag_if_raised:nT { str_overflow }
- {
- \\\\
- Unicode~limits~code~points~to~the~range~[0,1114111].
- }
- }
-% \end{macrocode}
-% \end{variable}
%
-% \begin{macro}[int]{\@@_convert_decode_utf8:}
-% \begin{macro}[aux, rEXP]
-% {
-% \@@_decode_utf_viii_start:N,
-% \@@_decode_utf_viii_continuation:wwN,
-% \@@_decode_utf_viii_aux:wNnnwN
-% }
-% \begin{macro}[aux, rEXP]
-% {\@@_decode_utf_viii_overflow:w, \@@_decode_utf_viii_end:}
-% Decoding is significantly harder than encoding. As before, lower
-% some flags, which are tested at the end (in bulk, to trigger at most
-% one \LaTeX3 error, as explained above). We expect successive
-% multi-byte sequences of the form \meta{start byte}
-% \meta{continuation bytes}. The \texttt{_start} auxiliary tests the
-% first byte:
-% \begin{itemize}
-% \item $[0,\hexnum{7F}]$: the byte stands alone, and is converted
-% to its own character code;
-% \item $[\hexnum{80}, \hexnum{BF}]$: unexpected continuation byte,
-% raise the appropriate flag, and convert that byte to the
-% replacement character \hexnum{FFFD};
-% \item $[\hexnum{C0}, \hexnum{FF}]$: this byte should be followed
-% by some continuation byte(s).
-% \end{itemize}
-% In the first two cases, \cs{use_none_delimit_by_q_stop:w} removes
-% data that only the third case requires, namely the limits of ranges
-% of Unicode characters which can be expressed with $1$, $2$, $3$, or
-% $4$ bytes.
-%
-% We can now concentrate on the multi-byte case and the
-% \texttt{_continuation} auxiliary. We expect |#3| to be in the range
-% $[\hexnum{80}, \hexnum{BF}]$. The test for this goes as follows: if
-% the character code is less than \hexnum{80}, we compare it to
-% $-\hexnum{C0}$, yielding \texttt{false}; otherwise to \hexnum{C0},
-% yielding \texttt{true} in the range $[\hexnum{80}, \hexnum{BF}]$ and
-% \texttt{false} otherwise. If we find that the byte is not a
-% continuation range, stop the current slew of bytes, output the
-% replacement character, and continue parsing with the \texttt{_start}
-% auxiliary, starting at the byte we just tested. Once we know that
-% the byte is a continuation byte, leave it behind us in the input
-% stream, compute what code point the bytes read so far would produce,
-% and feed that number to the \texttt{_aux} function.
-%
-% The \texttt{_aux} function tests whether we should look for more
-% continuation bytes or not. If the number it receives as |#1| is less
-% than the maximum |#4| for the current range, then we are done: check
-% for an overlong representation by comparing |#1| with the maximum
-% |#3| for the previous range. Otherwise, we call the
-% \texttt{_continuation} auxiliary again, after shifting the
-% \enquote{current code point} by |#4| (maximum from the range we just
-% checkedd).
-%
-% Two additional tests are needed: if we reach the end of the list of
-% range maxima and we are still not done, then we are faced with an
-% overflow. Clean up, and again insert the code point \hexnum{FFFD}
-% for the replacement character. Also, every time we read a byte, we
-% need to check whether we reached the end of the string. In a correct
-% \textsc{utf-8} string, this happens automatically when the
-% \texttt{_start} auxiliary leaves its first argument in the input
-% stream: the end-marker begins with \cs{__prg_break:}, which ends
-% the loop. On the other hand, if the end is reached when looking for
-% a continuation byte, the \cs{use_none:n} |#3| construction removes
-% the first token from the end-marker, and leaves the \texttt{_end}
-% auxiliary, which raises the appropriate error flag before ending the
-% mapping.
-% \begin{macrocode}
-\cs_new_protected_nopar:cpn { @@_convert_decode_utf8: }
- {
- \flag_clear:n { str_error }
- \flag_clear:n { str_missing }
- \flag_clear:n { str_extra }
- \flag_clear:n { str_overlong }
- \flag_clear:n { str_overflow }
- \tl_gset:Nx \g_@@_result_tl
- {
- \exp_after:wN \@@_decode_utf_viii_start:N \g_@@_result_tl
- { \__prg_break: \@@_decode_utf_viii_end: }
- \__prg_break_point:
- }
- \@@_if_flag_error:nnx { str_error } { utf8-decode } { }
- }
-\cs_new:Npn \@@_decode_utf_viii_start:N #1
- {
- #1
- \if_int_compare:w `#1 < "C0 \exp_stop_f:
- \s__tl
- \if_int_compare:w `#1 < "80 \exp_stop_f:
- \__int_value:w `#1
- \else:
- \flag_raise:n { str_extra }
- \flag_raise:n { str_error }
- \int_use:N \c_@@_replacement_char_int
- \fi:
- \else:
- \exp_after:wN \@@_decode_utf_viii_continuation:wwN
- \int_use:N \__int_eval:w `#1 - "C0 \exp_after:wN \__int_eval_end:
- \fi:
- \s__tl
- \use_none_delimit_by_q_stop:w {"80} {"800} {"10000} {"110000} \q_stop
- \@@_decode_utf_viii_start:N
- }
-\cs_new:Npn \@@_decode_utf_viii_continuation:wwN
- #1 \s__tl #2 \@@_decode_utf_viii_start:N #3
- {
- \use_none:n #3
- \if_int_compare:w `#3 <
- \if_int_compare:w `#3 < "80 \exp_stop_f: - \fi:
- "C0 \exp_stop_f:
- #3
- \exp_after:wN \@@_decode_utf_viii_aux:wNnnwN
- \int_use:N \__int_eval:w
- #1 * "40 + `#3 - "80
- \exp_after:wN \__int_eval_end:
- \else:
- \s__tl
- \flag_raise:n { str_missing }
- \flag_raise:n { str_error }
- \int_use:N \c_@@_replacement_char_int
- \fi:
- \s__tl
- #2
- \@@_decode_utf_viii_start:N #3
- }
-\cs_new:Npn \@@_decode_utf_viii_aux:wNnnwN
- #1 \s__tl #2#3#4 #5 \@@_decode_utf_viii_start:N #6
- {
- \if_int_compare:w #1 < #4 \exp_stop_f:
- \s__tl
- \if_int_compare:w #1 < #3 \exp_stop_f:
- \flag_raise:n { str_overlong }
- \flag_raise:n { str_error }
- \int_use:N \c_@@_replacement_char_int
- \else:
- #1
- \fi:
- \else:
- \if_meaning:w \q_stop #5
- \@@_decode_utf_viii_overflow:w #1
- \fi:
- \exp_after:wN \@@_decode_utf_viii_continuation:wwN
- \int_use:N \__int_eval:w #1 - #4 \exp_after:wN \__int_eval_end:
- \fi:
- \s__tl
- #2 {#4} #5
- \@@_decode_utf_viii_start:N
- }
-\cs_new:Npn \@@_decode_utf_viii_overflow:w #1 \fi: #2 \fi:
- {
- \fi: \fi:
- \flag_raise:n { str_overflow }
- \flag_raise:n { str_error }
- \int_use:N \c_@@_replacement_char_int
- }
-\cs_new_nopar:Npn \@@_decode_utf_viii_end:
+% Deprecated 2013-01-20 for removal by 2013-04-30
+% \begin{macro}[EXP]
+% {\str_substr:Nnn, \str_substr:nnn, \str_substr_ignore_spaces:nnn}
+% \begin{macro}[EXP, aux]{\@@_substr:nnn}
+% These functions used to allow for an empty argument to denote the
+% start/end of the string. We reimplement them here by first checking
+% for an empty argument, then only calling the appropriate version of
+% the \cs{str_range:nnn} function.
+% \begin{macrocode}
+\cs_new:Npn \str_substr:Nnn #1 { \@@_substr:nnn { \str_range:Nnn #1 } }
+\cs_new:Npn \str_substr:nnn #1 { \@@_substr:nnn { \str_range:nnn {#1} } }
+\cs_new:Npn \str_substr_ignore_spaces:nnn #1
+ { \@@_substr:nnn { \str_range_ignore_spaces:nnn {#1} } }
+\cs_new:Npn \@@_substr:nnn #1#2#3
{
- \s__tl
- \flag_raise:n { str_missing }
- \flag_raise:n { str_error }
- \int_use:N \c_@@_replacement_char_int \s__tl
- \__prg_break:
+ \tl_if_empty:nTF {#2}
+ { \tl_if_empty:nTF {#3} { #1 { 1} { -1 } } { #1 { 1} {#3} } }
+ { \tl_if_empty:nTF {#3} { #1 {#2} { -1 } } { #1 {#2} {#3} } }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
+% Deprecated 2013-01-20 for removal by 2013-04-30
+% \begin{variable}{\c_lbrace_str, \c_rbrace_str}
% \begin{macrocode}
-%</utf8>
-% \end{macrocode}
-%
-% \subsubsection{\textsc{utf-16} support}
-%
-% The definitions are done in a category code regime where the bytes
-% $254$ and $255$ used by the byte order mark have catcode~$12$.
-% \begin{macrocode}
-%<*utf16>
-\group_begin:
- \char_set_catcode_other:N \^^fe
- \char_set_catcode_other:N \^^ff
-% \end{macrocode}
-%
-% \begin{macro}[int]
-% {
-% \@@_convert_encode_utf16: ,
-% \@@_convert_encode_utf16be: ,
-% \@@_convert_encode_utf16le: ,
-% }
-% \begin{macro}[aux, rEXP]
-% {
-% \@@_encode_utf_xvi_aux:N ,
-% \@@_encode_utf_xvi_char:n ,
-% }
-% When the endianness is not specified, it is big-endian by default,
-% and we add a byte-order mark. Convert characters one by one in a
-% loop, with different behaviours depending on the character code.
-% \begin{itemize}
-% \item $[0, \hexnum{D7FF}]$: converted to two bytes;
-% \item $[\hexnum{D800}, \hexnum{DFFF}]$ are used as surrogates:
-% they cannot be converted and are replaced by the replacement
-% character;
-% \item $[\hexnum{E000}, \hexnum{FFFF}]$: converted to two bytes;
-% \item $[\hexnum{10000}, \hexnum{10FFFF}]$: converted to a pair of
-% surrogates, each two bytes. The magic \hexnum{D7C0} is
-% $\hexnum{D800}-\hexnum{10000}/\hexnum{400}$.
-% \end{itemize}
-% For the duration of this operation, \cs{@@_tmp:w} is defined as a
-% function to convert a number in the range $[0, \hexnum{FFFF}]$ to a
-% pair of bytes (either big endian or little endian), by feeding the
-% quotient of the division of |#1| by \hexnum{100}, followed by |#1|
-% to \cs{@@_encode_utf_xvi_be:nn} or its \texttt{le} analog: those
-% compute the remainder, and output two bytes for the quotient and
-% remainder.
-% \begin{macrocode}
- \cs_new_protected_nopar:cpn { @@_convert_encode_utf16: }
- {
- \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_be:n
- \tl_gput_left:Nx \g_@@_result_tl { ^^fe ^^ff }
- }
- \cs_new_protected_nopar:cpn { @@_convert_encode_utf16be: }
- { \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_be:n }
- \cs_new_protected_nopar:cpn { @@_convert_encode_utf16le: }
- { \@@_encode_utf_xvi_aux:N \@@_output_byte_pair_le:n }
- \cs_new_protected:Npn \@@_encode_utf_xvi_aux:N #1
- {
- \flag_clear:n { str_error }
- \cs_set_eq:NN \@@_tmp:w #1
- \@@_convert_gmap_internal:N \@@_encode_utf_xvi_char:n
- \@@_if_flag_error:nnx { str_error } { utf16-encode } { }
- }
- \cs_new:Npn \@@_encode_utf_xvi_char:n #1
- {
- \if_int_compare:w #1 < "D800 \exp_stop_f:
- \@@_tmp:w {#1}
- \else:
- \if_int_compare:w #1 < "10000 \exp_stop_f:
- \if_int_compare:w #1 < "E000 \exp_stop_f:
- \flag_raise:n { str_error }
- \@@_tmp:w { \c_@@_replacement_char_int }
- \else:
- \@@_tmp:w {#1}
- \fi:
- \else:
- \exp_args:Nf \@@_tmp:w { \int_div_truncate:nn {#1} {"400} + "D7C0 }
- \exp_args:Nf \@@_tmp:w { \int_mod:nn {#1} {"400} + "DC00 }
- \fi:
- \fi:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{variable}
-% {
-% \l_@@_missing_flag ,
-% \l_@@_extra_flag ,
-% \l_@@_end_flag ,
-% }
-% When encoding a Unicode string to \textsc{utf-16}, only one error
-% can occur: code points in the range $[\hexnum{D800},
-% \hexnum{DFFF}]$, corresponding to surrogates, cannot be encoded. We
-% use the all-purpose flag \texttt{@@_error} to signal that error.
-%
-% When decoding a Unicode string which is purportedly in
-% \textsc{utf-16}, three errors can occur: a missing trail surrogate,
-% an unexpected trail surrogate, and a string containing an odd number
-% of bytes.
-% \begin{macrocode}
- \flag_clear_new:n { str_missing }
- \flag_clear_new:n { str_extra }
- \flag_clear_new:n { str_end }
- \__msg_kernel_new:nnnn { str } { utf16-encode }
- { Unicode~string~cannot~be~expressed~in~UTF-16:~surrogate. }
- {
- Surrogate~code~points~(in~the~range~[U+D800,~U+DFFF])~
- can~be~expressed~in~the~UTF-8~and~UTF-32~encodings,~
- but~not~in~the~UTF-16~encoding.
- }
- \__msg_kernel_new:nnnn { str } { utf16-decode }
- {
- Invalid~UTF-16~string: \exp_last_unbraced:Nf \use_none:n
- \@@_if_flag_times:nT { str_missing } { ,~missing~trail~surrogate }
- \@@_if_flag_times:nT { str_extra } { ,~extra~trail~surrogate }
- \@@_if_flag_times:nT { str_end } { ,~odd~number~of~bytes }
- .
- }
- {
- In~the~UTF-16~encoding,~each~Unicode~character~is~encoded~as~
- 2~or~4~bytes: \\
- \iow_indent:n
- {
- Code~point~in~[U+0000,~U+D7FF]:~two~bytes \\
- Code~point~in~[U+D800,~U+DFFF]:~illegal \\
- Code~point~in~[U+E000,~U+FFFF]:~two~bytes \\
- Code~point~in~[U+10000,~U+10FFFF]:~
- a~lead~surrogate~and~a~trail~surrogate \\
- }
- Lead~surrogates~are~pairs~of~bytes~in~the~range~[0xD800,~0xDBFF],~
- and~trail~surrogates~are~in~the~range~[0xDC00,~0xDFFF].
- \flag_if_raised:nT { str_missing }
- {
- \\\\
- A~lead~surrogate~was~not~followed~by~a~trail~surrogate.
- }
- \flag_if_raised:nT { str_extra }
- {
- \\\\
- LaTeX~came~across~a~trail~surrogate~when~it~was~not~expected.
- }
- \flag_if_raised:nT { str_end }
- {
- \\\\
- The~string~contained~an~odd~number~of~bytes.~This~is~invalid:~
- the~basic~code~unit~for~UTF-16~is~16~bits~(2~bytes).
- }
- }
+\cs_new_eq:NN \c_lbrace_str \c_left_brace_str
+\cs_new_eq:NN \c_rbrace_str \c_right_brace_str
% \end{macrocode}
% \end{variable}
%
-% \begin{macro}[int]
-% {
-% \@@_convert_decode_utf16: ,
-% \@@_convert_decode_utf16be: ,
-% \@@_convert_decode_utf16le: ,
-% }
-% \begin{macro}[aux]{\@@_decode_utf_xvi_bom:NN, \@@_decode_utf_xvi:Nw}
-% As for \textsc{utf-8}, decoding \textsc{utf-16} is harder than
-% encoding it. If the endianness is unknown, check the first two
-% bytes: if those are \hexnum{FE} and \hexnum{FF} in either order,
-% remove them and use the corresponding endianness, otherwise assume
-% big-endianness. The three endianness cases are based on a common
-% auxiliary whose first argument is $1$ for big-endian and $2$ for
-% little-endian, and whose second argument, delimited by the scan mark
-% \cs{s__stop}, is expanded once (the string may be long; passing
-% \cs{g_@@_result_tl} as an argument before expansion is cheaper).
-%
-% The \cs{@@_decode_utf_xvi:Nw} function defines \cs{@@_tmp:w} to
-% take two arguments and return the character code of the first one if
-% the string is big-endian, and the second one if the string is
-% little-endian, then loops over the string using
-% \cs{@@_decode_utf_xvi_pair:NN} described below.
-% \begin{macrocode}
- \cs_new_protected_nopar:cpn { @@_convert_decode_utf16be: }
- { \@@_decode_utf_xvi:Nw 1 \g_@@_result_tl \s__stop }
- \cs_new_protected_nopar:cpn { @@_convert_decode_utf16le: }
- { \@@_decode_utf_xvi:Nw 2 \g_@@_result_tl \s__stop }
- \cs_new_protected_nopar:cpn { @@_convert_decode_utf16: }
- {
- \exp_after:wN \@@_decode_utf_xvi_bom:NN
- \g_@@_result_tl \s__stop \s__stop \s__stop
- }
- \cs_new_protected:Npn \@@_decode_utf_xvi_bom:NN #1#2
- {
- \str_if_eq_x:nnTF { #1#2 } { ^^ff ^^fe }
- { \@@_decode_utf_xvi:Nw 2 }
- {
- \str_if_eq_x:nnTF { #1#2 } { ^^fe ^^ff }
- { \@@_decode_utf_xvi:Nw 1 }
- { \@@_decode_utf_xvi:Nw 1 #1#2 }
- }
- }
- \cs_new_protected:Npn \@@_decode_utf_xvi:Nw #1#2 \s__stop
- {
- \flag_clear:n { str_error }
- \flag_clear:n { str_missing }
- \flag_clear:n { str_extra }
- \flag_clear:n { str_end }
- \cs_set:Npn \@@_tmp:w ##1 ##2 { ` ## #1 }
- \tl_gset:Nx \g_@@_result_tl
- {
- \exp_after:wN \@@_decode_utf_xvi_pair:NN
- #2 \q_nil \q_nil
- \__prg_break_point:
- }
- \@@_if_flag_error:nnx { str_error } { utf16-decode } { }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[aux, rEXP]
-% {
-% \@@_decode_utf_xvi_pair:NN ,
-% \@@_decode_utf_xvi_quad:NNwNN ,
-% \@@_decode_utf_xvi_pair_end:Nw ,
-% }
-% \begin{macro}[aux, rEXP]
-% {
-% \@@_decode_utf_xvi_error:nNN ,
-% \@@_decode_utf_xvi_extra:NNw ,
-% }
-% Bytes are read two at a time. At this stage, |\@@_tmp:w #1#2|
-% expands to the character code of the most significant byte, and we
-% distinguish cases depending on which range it lies in:
-% \begin{itemize}
-% \item $[\hexnum{D8}, \hexnum{DB}]$ signals a lead surrogate, and
-% the integer expression yields $1$ (\eTeX{} rounds ties away from
-% zero);
-% \item $[\hexnum{DC}, \hexnum{DF}]$ signals a trail surrogate,
-% unexpected here, and the integer expression yields $2$;
-% \item any other value signals a code point in the Basic
-% Multilingual Plane, which stands for itself, and the
-% \cs{if_case:w} construction expands to nothing (cases other than
-% $1$ or $2$), leaving the relevant material in the input stream,
-% followed by another call to the \texttt{_pair} auxiliary.
-% \end{itemize}
-% The case of a lead surrogate is treated by the \texttt{_quad}
-% auxiliary, whose arguments |#1|, |#2|, |#4| and |#5| are the four
-% bytes. We expect the most significant byte of |#4#5| to be in the
-% range $[\hexnum{DC}, \hexnum{DF}]$ (trail surrogate). The test is
-% similar to the test used for continuation bytes in the
-% \textsc{utf-8} decoding functions. In the case where |#4#5| is
-% indeed a trail surrogate, leave |#1#2#4#5| \cs{s__tl}
-% \meta{code~point} \cs{s__tl}, and remove the pair |#4#5| before
-% looping with \cs{@@_decode_utf_xvi_pair:NN}. Otherwise, of course,
-% complain about the missing surrogate.
-%
-% The magic number \hexnum{D7F7} is such that
-% $\hexnum{D7F7}*\hexnum{400} = \hexnum{D800}*\hexnum{400} +
-% \hexnum{DC00} - \hexnum{10000}$.
-%
-% Every time we read a pair of bytes, we test for the end-marker
-% \cs{q_nil}. When reaching the end, we additionally check that the
-% string had an even length. Also, if the end is reached when
-% expecting a trail surrogate, we treat that as a missing surrogate.
-% \begin{macrocode}
- \cs_new:Npn \@@_decode_utf_xvi_pair:NN #1#2
- {
- \if_meaning:w \q_nil #2
- \@@_decode_utf_xvi_pair_end:Nw #1
- \fi:
- \if_case:w
- \__int_eval:w ( \@@_tmp:w #1#2 - "D6 ) / \c_four \__int_eval_end:
- \or: \exp_after:wN \@@_decode_utf_xvi_quad:NNwNN
- \or: \exp_after:wN \@@_decode_utf_xvi_extra:NNw
- \fi:
- #1#2 \s__tl
- \int_eval:n { "100 * \@@_tmp:w #1#2 + \@@_tmp:w #2#1 } \s__tl
- \@@_decode_utf_xvi_pair:NN
- }
- \cs_new:Npn \@@_decode_utf_xvi_quad:NNwNN
- #1#2 #3 \@@_decode_utf_xvi_pair:NN #4#5
- {
- \if_meaning:w \q_nil #5
- \@@_decode_utf_xvi_error:nNN { missing } #1#2
- \@@_decode_utf_xvi_pair_end:Nw #4
- \fi:
- \if_int_compare:w
- \if_int_compare:w \@@_tmp:w #4#5 < "DC \exp_stop_f:
- \c_zero = \c_one
- \else:
- \@@_tmp:w #4#5 < "E0 \exp_stop_f:
- \fi:
- #1 #2 #4 #5 \s__tl
- \int_eval:n
- {
- ( "100 * \@@_tmp:w #1#2 + \@@_tmp:w #2#1 - "D7F7 ) * "400
- + "100 * \@@_tmp:w #4#5 + \@@_tmp:w #5#4
- }
- \s__tl
- \exp_after:wN \use_i:nnn
- \else:
- \@@_decode_utf_xvi_error:nNN { missing } #1#2
- \fi:
- \@@_decode_utf_xvi_pair:NN #4#5
- }
- \cs_new:Npn \@@_decode_utf_xvi_pair_end:Nw #1 \fi:
- {
- \fi:
- \if_meaning:w \q_nil #1
- \else:
- \@@_decode_utf_xvi_error:nNN { end } #1 \prg_do_nothing:
- \fi:
- \__prg_break:
- }
- \cs_new:Npn \@@_decode_utf_xvi_extra:NNw #1#2 \s__tl #3 \s__tl
- { \@@_decode_utf_xvi_error:nNN { extra } #1#2 }
- \cs_new:Npn \@@_decode_utf_xvi_error:nNN #1#2#3
- {
- \flag_raise:n { str_error }
- \flag_raise:n { str_#1 }
- #2 #3 \s__tl
- \int_use:N \c_@@_replacement_char_int \s__tl
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% Restore the original catcodes of bytes $254$ and $255$.
-% \begin{macrocode}
-\group_end:
-%</utf16>
-% \end{macrocode}
-%
-% \subsubsection{\textsc{utf-32} support}
-%
-% The definitions are done in a category code regime where the bytes
-% $0$, $254$ and $255$ used by the byte order mark have catcode
-% \enquote{other}.
-% \begin{macrocode}
-%<*utf32>
-\group_begin:
- \char_set_catcode_other:N \^^00
- \char_set_catcode_other:N \^^fe
- \char_set_catcode_other:N \^^ff
-% \end{macrocode}
-%
-% \begin{macro}[int]
-% {
-% \@@_convert_encode_utf32: ,
-% \@@_convert_encode_utf32be: ,
-% \@@_convert_encode_utf32le: ,
-% }
-% \begin{macro}[aux, rEXP]
-% {
-% \@@_encode_utf_xxxii_be:n ,
-% \@@_encode_utf_xxxii_be_aux:nn ,
-% \@@_encode_utf_xxxii_le:n ,
-% \@@_encode_utf_xxxii_le_aux:nn ,
-% }
-% Convert each integer in the comma-list \cs{g_@@_result_tl} to a
-% sequence of four bytes. The functions for big-endian and
-% little-endian encodings are very similar, but the
-% \cs{@@_output_byte:n} instructions are reversed.
-% \begin{macrocode}
- \cs_new_protected_nopar:cpn { @@_convert_encode_utf32: }
- {
- \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_be:n
- \tl_gput_left:Nx \g_@@_result_tl { ^^00 ^^00 ^^fe ^^ff }
- }
- \cs_new_protected_nopar:cpn { @@_convert_encode_utf32be: }
- { \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_be:n }
- \cs_new_protected_nopar:cpn { @@_convert_encode_utf32le: }
- { \@@_convert_gmap_internal:N \@@_encode_utf_xxxii_le:n }
- \cs_new:Npn \@@_encode_utf_xxxii_be:n #1
- {
- \exp_args:Nf \@@_encode_utf_xxxii_be_aux:nn
- { \int_div_truncate:nn {#1} { "100 } } {#1}
- }
- \cs_new:Npn \@@_encode_utf_xxxii_be_aux:nn #1#2
- {
- ^^00
- \@@_output_byte_pair_be:n {#1}
- \@@_output_byte:n { #2 - #1 * "100 }
- }
- \cs_new:Npn \@@_encode_utf_xxxii_le:n #1
- {
- \exp_args:Nf \@@_encode_utf_xxxii_le_aux:nn
- { \int_div_truncate:nn {#1} { "100 } } {#1}
- }
- \cs_new:Npn \@@_encode_utf_xxxii_le_aux:nn #1#2
- {
- \@@_output_byte:n { #2 - #1 * "100 }
- \@@_output_byte_pair_le:n {#1}
- ^^00
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{variable}{str_overflow, str_end}
-% There can be no error when encoding in \textsc{utf-32}. When
-% decoding, the string may not have length $4n$, or it may contain
-% code points larger than \hexnum{10FFFF}. The latter case often
-% happens if the encoding was in fact not \textsc{utf-32}, because
-% most arbitrary strings are not valid in \textsc{utf-32}.
-% \begin{macrocode}
- \flag_clear_new:n { str_overflow }
- \flag_clear_new:n { str_end }
- \__msg_kernel_new:nnnn { str } { utf32-decode }
- {
- Invalid~UTF-32~string: \exp_last_unbraced:Nf \use_none:n
- \@@_if_flag_times:nT { str_overflow } { ,~code~point~too~large }
- \@@_if_flag_times:nT { str_end } { ,~truncated~string }
- .
- }
- {
- In~the~UTF-32~encoding,~every~Unicode~character~
- (in~the~range~[U+0000,~U+10FFFF])~is~encoded~as~4~bytes.
- \flag_if_raised:nT { str_overflow }
- {
- \\\\
- LaTeX~came~across~a~code~point~larger~than~1114111,~
- the~maximum~code~point~defined~by~Unicode.~
- Perhaps~the~string~was~not~encoded~in~the~UTF-32~encoding?
- }
- \flag_if_raised:nT { str_end }
- {
- \\\\
- The~length~of~the~string~is~not~a~multiple~of~4.~
- Perhaps~the~string~was~truncated?
- }
- }
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[int]
-% {
-% \@@_convert_decode_utf32: ,
-% \@@_convert_decode_utf32be: ,
-% \@@_convert_decode_utf32le: ,
-% }
-% \begin{macro}[aux]
-% {\@@_decode_utf_xxxii_bom:NNNN, \@@_decode_utf_xxxii:Nw}
-% \begin{macro}[aux, rEXP]
-% {\@@_decode_utf_xxxii_loop:NNNN, \@@_decode_utf_xxxii_end:w}
-%
-% The structure is similar to \textsc{utf-16} decoding functions. If
-% the endianness is not given, test the first $4$ bytes of the string
-% (possibly \cs{s__stop} if the string is too short) for the presence
-% of a byte-order mark. If there is a byte-order mark, use that
-% endianness, and remove the $4$ bytes, otherwise default to
-% big-endian, and leave the $4$ bytes in place. The
-% \cs{@@_decode_utf_xxxii:Nw} auxiliary recieves $1$ or $2$ as its
-% first argument indicating endianness, and the string to convert as
-% its second argument (expanded or not). It sets \cs{@@_tmp:w} to
-% expand to the character code of either of its two arguments
-% depending on endianness, then triggers the \texttt{_loop} auxiliary
-% inside an \texttt{x}-expanding assignment to \cs{g_@@_result_tl}.
-%
-% The \texttt{_loop} auxiliary first checks for the end-of-string
-% marker \cs{s__stop}, calling the \texttt{_end} auxiliary if
-% appropriate. Otherwise, leave the \meta{4~bytes} \cs{s__tl} behind,
-% then check that the code point is not overflowing: the leading byte
-% must be $0$, and the following byte at most $16$.
-%
-% In the ending code, we check that there remains no byte: there
-% should be nothing left until the first \cs{s__stop}. Break the map.
-% \begin{macrocode}
- \cs_new_protected_nopar:cpn { @@_convert_decode_utf32be: }
- { \@@_decode_utf_xxxii:Nw 1 \g_@@_result_tl \s__stop }
- \cs_new_protected_nopar:cpn { @@_convert_decode_utf32le: }
- { \@@_decode_utf_xxxii:Nw 2 \g_@@_result_tl \s__stop }
- \cs_new_protected_nopar:cpn { @@_convert_decode_utf32: }
- {
- \exp_after:wN \@@_decode_utf_xxxii_bom:NNNN \g_@@_result_tl
- \s__stop \s__stop \s__stop \s__stop \s__stop
- }
- \cs_new_protected:Npn \@@_decode_utf_xxxii_bom:NNNN #1#2#3#4
- {
- \str_if_eq_x:nnTF { #1#2#3#4 } { ^^ff ^^fe ^^00 ^^00 }
- { \@@_decode_utf_xxxii:Nw 2 }
- {
- \str_if_eq_x:nnTF { #1#2#3#4 } { ^^00 ^^00 ^^fe ^^ff }
- { \@@_decode_utf_xxxii:Nw 1 }
- { \@@_decode_utf_xxxii:Nw 1 #1#2#3#4 }
- }
- }
- \cs_new_protected:Npn \@@_decode_utf_xxxii:Nw #1#2 \s__stop
- {
- \flag_clear:n { str_overflow }
- \flag_clear:n { str_end }
- \flag_clear:n { str_error }
- \cs_set:Npn \@@_tmp:w ##1 ##2 { ` ## #1 }
- \tl_gset:Nx \g_@@_result_tl
- {
- \exp_after:wN \@@_decode_utf_xxxii_loop:NNNN
- #2 \s__stop \s__stop \s__stop \s__stop
- \__prg_break_point:
- }
- \@@_if_flag_error:nnx { str_error } { utf32-decode } { }
- }
- \cs_new:Npn \@@_decode_utf_xxxii_loop:NNNN #1#2#3#4
- {
- \if_meaning:w \s__stop #4
- \exp_after:wN \@@_decode_utf_xxxii_end:w
- \fi:
- #1#2#3#4 \s__tl
- \if_int_compare:w \@@_tmp:w #1#4 > \c_zero
- \flag_raise:n { str_overflow }
- \flag_raise:n { str_error }
- \int_use:N \c_@@_replacement_char_int
- \else:
- \if_int_compare:w \@@_tmp:w #2#3 > \c_sixteen
- \flag_raise:n { str_overflow }
- \flag_raise:n { str_error }
- \int_use:N \c_@@_replacement_char_int
- \else:
- \int_eval:n
- { \@@_tmp:w #2#3*"10000 + \@@_tmp:w #3#2*"100 + \@@_tmp:w #4#1 }
- \fi:
- \fi:
- \s__tl
- \@@_decode_utf_xxxii_loop:NNNN
- }
- \cs_new:Npn \@@_decode_utf_xxxii_end:w #1 \s__stop
- {
- \tl_if_empty:nF {#1}
- {
- \flag_raise:n { str_end }
- \flag_raise:n { str_error }
- #1 \s__tl
- \int_use:N \c_@@_replacement_char_int \s__tl
- }
- \__prg_break:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% Restore the original catcodes of bytes $0$, $254$ and $255$.
-% \begin{macrocode}
-\group_end:
-%</utf32>
-% \end{macrocode}
-%
-% \subsubsection{\textsc{iso 8859} support}
-%
-% The \textsc{iso-8859-1} encoding exactly matches with the $256$ first
-% Unicode characters. For other 8-bit encodings of the \textsc{iso-8859}
-% family, we keep track only of differences, and of unassigned bytes.
-% \begin{macrocode}
-%<*iso88591>
-\@@_declare_eight_bit_encoding:nnn { iso88591 }
- {
- }
- {
- }
-%</iso88591>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso88592>
-\@@_declare_eight_bit_encoding:nnn { iso88592 }
- {
- { A1 } { 0104 }
- { A2 } { 02D8 }
- { A3 } { 0141 }
- { A5 } { 013D }
- { A6 } { 015A }
- { A9 } { 0160 }
- { AA } { 015E }
- { AB } { 0164 }
- { AC } { 0179 }
- { AE } { 017D }
- { AF } { 017B }
- { B1 } { 0105 }
- { B2 } { 02DB }
- { B3 } { 0142 }
- { B5 } { 013E }
- { B6 } { 015B }
- { B7 } { 02C7 }
- { B9 } { 0161 }
- { BA } { 015F }
- { BB } { 0165 }
- { BC } { 017A }
- { BD } { 02DD }
- { BE } { 017E }
- { BF } { 017C }
- { C0 } { 0154 }
- { C3 } { 0102 }
- { C5 } { 0139 }
- { C6 } { 0106 }
- { C8 } { 010C }
- { CA } { 0118 }
- { CC } { 011A }
- { CF } { 010E }
- { D0 } { 0110 }
- { D1 } { 0143 }
- { D2 } { 0147 }
- { D5 } { 0150 }
- { D8 } { 0158 }
- { D9 } { 016E }
- { DB } { 0170 }
- { DE } { 0162 }
- { E0 } { 0155 }
- { E3 } { 0103 }
- { E5 } { 013A }
- { E6 } { 0107 }
- { E8 } { 010D }
- { EA } { 0119 }
- { EC } { 011B }
- { EF } { 010F }
- { F0 } { 0111 }
- { F1 } { 0144 }
- { F2 } { 0148 }
- { F5 } { 0151 }
- { F8 } { 0159 }
- { F9 } { 016F }
- { FB } { 0171 }
- { FE } { 0163 }
- { FF } { 02D9 }
- }
- {
- }
-%</iso88592>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso88593>
-\@@_declare_eight_bit_encoding:nnn { iso88593 }
- {
- { A1 } { 0126 }
- { A2 } { 02D8 }
- { A6 } { 0124 }
- { A9 } { 0130 }
- { AA } { 015E }
- { AB } { 011E }
- { AC } { 0134 }
- { AF } { 017B }
- { B1 } { 0127 }
- { B6 } { 0125 }
- { B9 } { 0131 }
- { BA } { 015F }
- { BB } { 011F }
- { BC } { 0135 }
- { BF } { 017C }
- { C5 } { 010A }
- { C6 } { 0108 }
- { D5 } { 0120 }
- { D8 } { 011C }
- { DD } { 016C }
- { DE } { 015C }
- { E5 } { 010B }
- { E6 } { 0109 }
- { F5 } { 0121 }
- { F8 } { 011D }
- { FD } { 016D }
- { FE } { 015D }
- { FF } { 02D9 }
- }
- {
- { A5 }
- { AE }
- { BE }
- { C3 }
- { D0 }
- { E3 }
- { F0 }
- }
-%</iso88593>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso88594>
-\@@_declare_eight_bit_encoding:nnn { iso88594 }
- {
- { A1 } { 0104 }
- { A2 } { 0138 }
- { A3 } { 0156 }
- { A5 } { 0128 }
- { A6 } { 013B }
- { A9 } { 0160 }
- { AA } { 0112 }
- { AB } { 0122 }
- { AC } { 0166 }
- { AE } { 017D }
- { B1 } { 0105 }
- { B2 } { 02DB }
- { B3 } { 0157 }
- { B5 } { 0129 }
- { B6 } { 013C }
- { B7 } { 02C7 }
- { B9 } { 0161 }
- { BA } { 0113 }
- { BB } { 0123 }
- { BC } { 0167 }
- { BD } { 014A }
- { BE } { 017E }
- { BF } { 014B }
- { C0 } { 0100 }
- { C7 } { 012E }
- { C8 } { 010C }
- { CA } { 0118 }
- { CC } { 0116 }
- { CF } { 012A }
- { D0 } { 0110 }
- { D1 } { 0145 }
- { D2 } { 014C }
- { D3 } { 0136 }
- { D9 } { 0172 }
- { DD } { 0168 }
- { DE } { 016A }
- { E0 } { 0101 }
- { E7 } { 012F }
- { E8 } { 010D }
- { EA } { 0119 }
- { EC } { 0117 }
- { EF } { 012B }
- { F0 } { 0111 }
- { F1 } { 0146 }
- { F2 } { 014D }
- { F3 } { 0137 }
- { F9 } { 0173 }
- { FD } { 0169 }
- { FE } { 016B }
- { FF } { 02D9 }
- }
- {
- }
-%</iso88594>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso88595>
-\@@_declare_eight_bit_encoding:nnn { iso88595 }
- {
- { A1 } { 0401 }
- { A2 } { 0402 }
- { A3 } { 0403 }
- { A4 } { 0404 }
- { A5 } { 0405 }
- { A6 } { 0406 }
- { A7 } { 0407 }
- { A8 } { 0408 }
- { A9 } { 0409 }
- { AA } { 040A }
- { AB } { 040B }
- { AC } { 040C }
- { AE } { 040E }
- { AF } { 040F }
- { B0 } { 0410 }
- { B1 } { 0411 }
- { B2 } { 0412 }
- { B3 } { 0413 }
- { B4 } { 0414 }
- { B5 } { 0415 }
- { B6 } { 0416 }
- { B7 } { 0417 }
- { B8 } { 0418 }
- { B9 } { 0419 }
- { BA } { 041A }
- { BB } { 041B }
- { BC } { 041C }
- { BD } { 041D }
- { BE } { 041E }
- { BF } { 041F }
- { C0 } { 0420 }
- { C1 } { 0421 }
- { C2 } { 0422 }
- { C3 } { 0423 }
- { C4 } { 0424 }
- { C5 } { 0425 }
- { C6 } { 0426 }
- { C7 } { 0427 }
- { C8 } { 0428 }
- { C9 } { 0429 }
- { CA } { 042A }
- { CB } { 042B }
- { CC } { 042C }
- { CD } { 042D }
- { CE } { 042E }
- { CF } { 042F }
- { D0 } { 0430 }
- { D1 } { 0431 }
- { D2 } { 0432 }
- { D3 } { 0433 }
- { D4 } { 0434 }
- { D5 } { 0435 }
- { D6 } { 0436 }
- { D7 } { 0437 }
- { D8 } { 0438 }
- { D9 } { 0439 }
- { DA } { 043A }
- { DB } { 043B }
- { DC } { 043C }
- { DD } { 043D }
- { DE } { 043E }
- { DF } { 043F }
- { E0 } { 0440 }
- { E1 } { 0441 }
- { E2 } { 0442 }
- { E3 } { 0443 }
- { E4 } { 0444 }
- { E5 } { 0445 }
- { E6 } { 0446 }
- { E7 } { 0447 }
- { E8 } { 0448 }
- { E9 } { 0449 }
- { EA } { 044A }
- { EB } { 044B }
- { EC } { 044C }
- { ED } { 044D }
- { EE } { 044E }
- { EF } { 044F }
- { F0 } { 2116 }
- { F1 } { 0451 }
- { F2 } { 0452 }
- { F3 } { 0453 }
- { F4 } { 0454 }
- { F5 } { 0455 }
- { F6 } { 0456 }
- { F7 } { 0457 }
- { F8 } { 0458 }
- { F9 } { 0459 }
- { FA } { 045A }
- { FB } { 045B }
- { FC } { 045C }
- { FD } { 00A7 }
- { FE } { 045E }
- { FF } { 045F }
- }
- {
- }
-%</iso88595>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso88596>
-\@@_declare_eight_bit_encoding:nnn { iso88596 }
- {
- { AC } { 060C }
- { BB } { 061B }
- { BF } { 061F }
- { C1 } { 0621 }
- { C2 } { 0622 }
- { C3 } { 0623 }
- { C4 } { 0624 }
- { C5 } { 0625 }
- { C6 } { 0626 }
- { C7 } { 0627 }
- { C8 } { 0628 }
- { C9 } { 0629 }
- { CA } { 062A }
- { CB } { 062B }
- { CC } { 062C }
- { CD } { 062D }
- { CE } { 062E }
- { CF } { 062F }
- { D0 } { 0630 }
- { D1 } { 0631 }
- { D2 } { 0632 }
- { D3 } { 0633 }
- { D4 } { 0634 }
- { D5 } { 0635 }
- { D6 } { 0636 }
- { D7 } { 0637 }
- { D8 } { 0638 }
- { D9 } { 0639 }
- { DA } { 063A }
- { E0 } { 0640 }
- { E1 } { 0641 }
- { E2 } { 0642 }
- { E3 } { 0643 }
- { E4 } { 0644 }
- { E5 } { 0645 }
- { E6 } { 0646 }
- { E7 } { 0647 }
- { E8 } { 0648 }
- { E9 } { 0649 }
- { EA } { 064A }
- { EB } { 064B }
- { EC } { 064C }
- { ED } { 064D }
- { EE } { 064E }
- { EF } { 064F }
- { F0 } { 0650 }
- { F1 } { 0651 }
- { F2 } { 0652 }
- }
- {
- { A1 }
- { A2 }
- { A3 }
- { A5 }
- { A6 }
- { A7 }
- { A8 }
- { A9 }
- { AA }
- { AB }
- { AE }
- { AF }
- { B0 }
- { B1 }
- { B2 }
- { B3 }
- { B4 }
- { B5 }
- { B6 }
- { B7 }
- { B8 }
- { B9 }
- { BA }
- { BC }
- { BD }
- { BE }
- { C0 }
- { DB }
- { DC }
- { DD }
- { DE }
- { DF }
- }
-%</iso88596>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso88597>
-\@@_declare_eight_bit_encoding:nnn { iso88597 }
- {
- { A1 } { 2018 }
- { A2 } { 2019 }
- { A4 } { 20AC }
- { A5 } { 20AF }
- { AA } { 037A }
- { AF } { 2015 }
- { B4 } { 0384 }
- { B5 } { 0385 }
- { B6 } { 0386 }
- { B8 } { 0388 }
- { B9 } { 0389 }
- { BA } { 038A }
- { BC } { 038C }
- { BE } { 038E }
- { BF } { 038F }
- { C0 } { 0390 }
- { C1 } { 0391 }
- { C2 } { 0392 }
- { C3 } { 0393 }
- { C4 } { 0394 }
- { C5 } { 0395 }
- { C6 } { 0396 }
- { C7 } { 0397 }
- { C8 } { 0398 }
- { C9 } { 0399 }
- { CA } { 039A }
- { CB } { 039B }
- { CC } { 039C }
- { CD } { 039D }
- { CE } { 039E }
- { CF } { 039F }
- { D0 } { 03A0 }
- { D1 } { 03A1 }
- { D3 } { 03A3 }
- { D4 } { 03A4 }
- { D5 } { 03A5 }
- { D6 } { 03A6 }
- { D7 } { 03A7 }
- { D8 } { 03A8 }
- { D9 } { 03A9 }
- { DA } { 03AA }
- { DB } { 03AB }
- { DC } { 03AC }
- { DD } { 03AD }
- { DE } { 03AE }
- { DF } { 03AF }
- { E0 } { 03B0 }
- { E1 } { 03B1 }
- { E2 } { 03B2 }
- { E3 } { 03B3 }
- { E4 } { 03B4 }
- { E5 } { 03B5 }
- { E6 } { 03B6 }
- { E7 } { 03B7 }
- { E8 } { 03B8 }
- { E9 } { 03B9 }
- { EA } { 03BA }
- { EB } { 03BB }
- { EC } { 03BC }
- { ED } { 03BD }
- { EE } { 03BE }
- { EF } { 03BF }
- { F0 } { 03C0 }
- { F1 } { 03C1 }
- { F2 } { 03C2 }
- { F3 } { 03C3 }
- { F4 } { 03C4 }
- { F5 } { 03C5 }
- { F6 } { 03C6 }
- { F7 } { 03C7 }
- { F8 } { 03C8 }
- { F9 } { 03C9 }
- { FA } { 03CA }
- { FB } { 03CB }
- { FC } { 03CC }
- { FD } { 03CD }
- { FE } { 03CE }
- }
- {
- { AE }
- { D2 }
- }
-%</iso88597>
-% \end{macrocode}
-%
% \begin{macrocode}
-%<*iso88598>
-\@@_declare_eight_bit_encoding:nnn { iso88598 }
- {
- { AA } { 00D7 }
- { BA } { 00F7 }
- { DF } { 2017 }
- { E0 } { 05D0 }
- { E1 } { 05D1 }
- { E2 } { 05D2 }
- { E3 } { 05D3 }
- { E4 } { 05D4 }
- { E5 } { 05D5 }
- { E6 } { 05D6 }
- { E7 } { 05D7 }
- { E8 } { 05D8 }
- { E9 } { 05D9 }
- { EA } { 05DA }
- { EB } { 05DB }
- { EC } { 05DC }
- { ED } { 05DD }
- { EE } { 05DE }
- { EF } { 05DF }
- { F0 } { 05E0 }
- { F1 } { 05E1 }
- { F2 } { 05E2 }
- { F3 } { 05E3 }
- { F4 } { 05E4 }
- { F5 } { 05E5 }
- { F6 } { 05E6 }
- { F7 } { 05E7 }
- { F8 } { 05E8 }
- { F9 } { 05E9 }
- { FA } { 05EA }
- { FD } { 200E }
- { FE } { 200F }
- }
- {
- { A1 }
- { BF }
- { C0 }
- { C1 }
- { C2 }
- { C3 }
- { C4 }
- { C5 }
- { C6 }
- { C7 }
- { C8 }
- { C9 }
- { CA }
- { CB }
- { CC }
- { CD }
- { CE }
- { CF }
- { D0 }
- { D1 }
- { D2 }
- { D3 }
- { D4 }
- { D5 }
- { D6 }
- { D7 }
- { D8 }
- { D9 }
- { DA }
- { DB }
- { DC }
- { DD }
- { DE }
- { FB }
- { FC }
- }
-%</iso88598>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso88599>
-\@@_declare_eight_bit_encoding:nnn { iso88599 }
- {
- { D0 } { 011E }
- { DD } { 0130 }
- { DE } { 015E }
- { F0 } { 011F }
- { FD } { 0131 }
- { FE } { 015F }
- }
- {
- }
-%</iso88599>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso885910>
-\@@_declare_eight_bit_encoding:nnn { iso885910 }
- {
- { A1 } { 0104 }
- { A2 } { 0112 }
- { A3 } { 0122 }
- { A4 } { 012A }
- { A5 } { 0128 }
- { A6 } { 0136 }
- { A8 } { 013B }
- { A9 } { 0110 }
- { AA } { 0160 }
- { AB } { 0166 }
- { AC } { 017D }
- { AE } { 016A }
- { AF } { 014A }
- { B1 } { 0105 }
- { B2 } { 0113 }
- { B3 } { 0123 }
- { B4 } { 012B }
- { B5 } { 0129 }
- { B6 } { 0137 }
- { B8 } { 013C }
- { B9 } { 0111 }
- { BA } { 0161 }
- { BB } { 0167 }
- { BC } { 017E }
- { BD } { 2015 }
- { BE } { 016B }
- { BF } { 014B }
- { C0 } { 0100 }
- { C7 } { 012E }
- { C8 } { 010C }
- { CA } { 0118 }
- { CC } { 0116 }
- { D1 } { 0145 }
- { D2 } { 014C }
- { D7 } { 0168 }
- { D9 } { 0172 }
- { E0 } { 0101 }
- { E7 } { 012F }
- { E8 } { 010D }
- { EA } { 0119 }
- { EC } { 0117 }
- { F1 } { 0146 }
- { F2 } { 014D }
- { F7 } { 0169 }
- { F9 } { 0173 }
- { FF } { 0138 }
- }
- {
- }
-%</iso885910>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso885911>
-\@@_declare_eight_bit_encoding:nnn { iso885911 }
- {
- { A1 } { 0E01 }
- { A2 } { 0E02 }
- { A3 } { 0E03 }
- { A4 } { 0E04 }
- { A5 } { 0E05 }
- { A6 } { 0E06 }
- { A7 } { 0E07 }
- { A8 } { 0E08 }
- { A9 } { 0E09 }
- { AA } { 0E0A }
- { AB } { 0E0B }
- { AC } { 0E0C }
- { AD } { 0E0D }
- { AE } { 0E0E }
- { AF } { 0E0F }
- { B0 } { 0E10 }
- { B1 } { 0E11 }
- { B2 } { 0E12 }
- { B3 } { 0E13 }
- { B4 } { 0E14 }
- { B5 } { 0E15 }
- { B6 } { 0E16 }
- { B7 } { 0E17 }
- { B8 } { 0E18 }
- { B9 } { 0E19 }
- { BA } { 0E1A }
- { BB } { 0E1B }
- { BC } { 0E1C }
- { BD } { 0E1D }
- { BE } { 0E1E }
- { BF } { 0E1F }
- { C0 } { 0E20 }
- { C1 } { 0E21 }
- { C2 } { 0E22 }
- { C3 } { 0E23 }
- { C4 } { 0E24 }
- { C5 } { 0E25 }
- { C6 } { 0E26 }
- { C7 } { 0E27 }
- { C8 } { 0E28 }
- { C9 } { 0E29 }
- { CA } { 0E2A }
- { CB } { 0E2B }
- { CC } { 0E2C }
- { CD } { 0E2D }
- { CE } { 0E2E }
- { CF } { 0E2F }
- { D0 } { 0E30 }
- { D1 } { 0E31 }
- { D2 } { 0E32 }
- { D3 } { 0E33 }
- { D4 } { 0E34 }
- { D5 } { 0E35 }
- { D6 } { 0E36 }
- { D7 } { 0E37 }
- { D8 } { 0E38 }
- { D9 } { 0E39 }
- { DA } { 0E3A }
- { DF } { 0E3F }
- { E0 } { 0E40 }
- { E1 } { 0E41 }
- { E2 } { 0E42 }
- { E3 } { 0E43 }
- { E4 } { 0E44 }
- { E5 } { 0E45 }
- { E6 } { 0E46 }
- { E7 } { 0E47 }
- { E8 } { 0E48 }
- { E9 } { 0E49 }
- { EA } { 0E4A }
- { EB } { 0E4B }
- { EC } { 0E4C }
- { ED } { 0E4D }
- { EE } { 0E4E }
- { EF } { 0E4F }
- { F0 } { 0E50 }
- { F1 } { 0E51 }
- { F2 } { 0E52 }
- { F3 } { 0E53 }
- { F4 } { 0E54 }
- { F5 } { 0E55 }
- { F6 } { 0E56 }
- { F7 } { 0E57 }
- { F8 } { 0E58 }
- { F9 } { 0E59 }
- { FA } { 0E5A }
- { FB } { 0E5B }
- }
- {
- { DB }
- { DC }
- { DD }
- { DE }
- }
-%</iso885911>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso885913>
-\@@_declare_eight_bit_encoding:nnn { iso885913 }
- {
- { A1 } { 201D }
- { A5 } { 201E }
- { A8 } { 00D8 }
- { AA } { 0156 }
- { AF } { 00C6 }
- { B4 } { 201C }
- { B8 } { 00F8 }
- { BA } { 0157 }
- { BF } { 00E6 }
- { C0 } { 0104 }
- { C1 } { 012E }
- { C2 } { 0100 }
- { C3 } { 0106 }
- { C6 } { 0118 }
- { C7 } { 0112 }
- { C8 } { 010C }
- { CA } { 0179 }
- { CB } { 0116 }
- { CC } { 0122 }
- { CD } { 0136 }
- { CE } { 012A }
- { CF } { 013B }
- { D0 } { 0160 }
- { D1 } { 0143 }
- { D2 } { 0145 }
- { D4 } { 014C }
- { D8 } { 0172 }
- { D9 } { 0141 }
- { DA } { 015A }
- { DB } { 016A }
- { DD } { 017B }
- { DE } { 017D }
- { E0 } { 0105 }
- { E1 } { 012F }
- { E2 } { 0101 }
- { E3 } { 0107 }
- { E6 } { 0119 }
- { E7 } { 0113 }
- { E8 } { 010D }
- { EA } { 017A }
- { EB } { 0117 }
- { EC } { 0123 }
- { ED } { 0137 }
- { EE } { 012B }
- { EF } { 013C }
- { F0 } { 0161 }
- { F1 } { 0144 }
- { F2 } { 0146 }
- { F4 } { 014D }
- { F8 } { 0173 }
- { F9 } { 0142 }
- { FA } { 015B }
- { FB } { 016B }
- { FD } { 017C }
- { FE } { 017E }
- { FF } { 2019 }
- }
- {
- }
-%</iso885913>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso885914>
-\@@_declare_eight_bit_encoding:nnn { iso885914 }
- {
- { A1 } { 1E02 }
- { A2 } { 1E03 }
- { A4 } { 010A }
- { A5 } { 010B }
- { A6 } { 1E0A }
- { A8 } { 1E80 }
- { AA } { 1E82 }
- { AB } { 1E0B }
- { AC } { 1EF2 }
- { AF } { 0178 }
- { B0 } { 1E1E }
- { B1 } { 1E1F }
- { B2 } { 0120 }
- { B3 } { 0121 }
- { B4 } { 1E40 }
- { B5 } { 1E41 }
- { B7 } { 1E56 }
- { B8 } { 1E81 }
- { B9 } { 1E57 }
- { BA } { 1E83 }
- { BB } { 1E60 }
- { BC } { 1EF3 }
- { BD } { 1E84 }
- { BE } { 1E85 }
- { BF } { 1E61 }
- { D0 } { 0174 }
- { D7 } { 1E6A }
- { DE } { 0176 }
- { F0 } { 0175 }
- { F7 } { 1E6B }
- { FE } { 0177 }
- }
- {
- }
-%</iso885914>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso885915>
-\@@_declare_eight_bit_encoding:nnn { iso885915 }
- {
- { A4 } { 20AC }
- { A6 } { 0160 }
- { A8 } { 0161 }
- { B4 } { 017D }
- { B8 } { 017E }
- { BC } { 0152 }
- { BD } { 0153 }
- { BE } { 0178 }
- }
- {
- }
-%</iso885915>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%<*iso885916>
-\@@_declare_eight_bit_encoding:nnn { iso885916 }
- {
- { A1 } { 0104 }
- { A2 } { 0105 }
- { A3 } { 0141 }
- { A4 } { 20AC }
- { A5 } { 201E }
- { A6 } { 0160 }
- { A8 } { 0161 }
- { AA } { 0218 }
- { AC } { 0179 }
- { AE } { 017A }
- { AF } { 017B }
- { B2 } { 010C }
- { B3 } { 0142 }
- { B4 } { 017D }
- { B5 } { 201D }
- { B8 } { 017E }
- { B9 } { 010D }
- { BA } { 0219 }
- { BC } { 0152 }
- { BD } { 0153 }
- { BE } { 0178 }
- { BF } { 017C }
- { C3 } { 0102 }
- { C5 } { 0106 }
- { D0 } { 0110 }
- { D1 } { 0143 }
- { D5 } { 0150 }
- { D7 } { 015A }
- { D8 } { 0170 }
- { DD } { 0118 }
- { DE } { 021A }
- { E3 } { 0103 }
- { E5 } { 0107 }
- { F0 } { 0111 }
- { F1 } { 0144 }
- { F5 } { 0151 }
- { F7 } { 015B }
- { F8 } { 0171 }
- { FD } { 0119 }
- { FE } { 021B }
- }
- {
- }
-%</iso885916>
+%</initex|package>
% \end{macrocode}
%
% \end{implementation}
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins
index 4605b50c851..8f6983abde3 100644
--- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3str.ins
@@ -1,6 +1,6 @@
\iffalse meta-comment
-File l3str.ins Copyright (C) 2011 The LaTeX3 Project
+File l3str.ins Copyright (C) 2011, 2013 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
@@ -38,6 +38,7 @@ Do not distribute a modified version of this file.
\generate{\file{l3flag.sty} {\from{l3flag.dtx} {package}}}
\generate{\file{l3str.sty} {\from{l3str.dtx} {package}}}
\generate{\file{l3regex.sty} {\from{l3regex.dtx} {package}}}
+\generate{\file{l3str-convert.sty} {\from{l3str-convert.dtx} {package}}}
\generate{\file{l3str-format.sty} {\from{l3str-format.dtx} {package}}}
\generate{\file{l3tl-analysis.sty} {\from{l3tl-analysis.dtx} {package}}}
\generate{\file{l3tl-build.sty} {\from{l3tl-build.dtx} {package}}}
@@ -45,36 +46,36 @@ Do not distribute a modified version of this file.
% Escapings.
\generate{%
- \file{l3str-esc-hex.def} {\from{l3str.dtx}{hex}}%
- \file{l3str-esc-name.def} {\from{l3str.dtx}{name}}%
- \file{l3str-esc-string.def} {\from{l3str.dtx}{string}}%
- \file{l3str-esc-url.def} {\from{l3str.dtx}{url}}%
+ \file{l3str-esc-hex.def} {\from{l3str-convert.dtx}{hex}}%
+ \file{l3str-esc-name.def} {\from{l3str-convert.dtx}{name}}%
+ \file{l3str-esc-string.def} {\from{l3str-convert.dtx}{string}}%
+ \file{l3str-esc-url.def} {\from{l3str-convert.dtx}{url}}%
}
% UTF encodings.
\generate{%
- \file{l3str-enc-utf8.def} {\from{l3str.dtx}{utf8}}%
- \file{l3str-enc-utf16.def} {\from{l3str.dtx}{utf16}}%
- \file{l3str-enc-utf32.def} {\from{l3str.dtx}{utf32}}%
+ \file{l3str-enc-utf8.def} {\from{l3str-convert.dtx}{utf8}}%
+ \file{l3str-enc-utf16.def} {\from{l3str-convert.dtx}{utf16}}%
+ \file{l3str-enc-utf32.def} {\from{l3str-convert.dtx}{utf32}}%
}
% ISO-8859 encodings.
\generate{%
- \file{l3str-enc-iso88591.def} {\from{l3str.dtx}{iso88591}}%
- \file{l3str-enc-iso88592.def} {\from{l3str.dtx}{iso88592}}%
- \file{l3str-enc-iso88593.def} {\from{l3str.dtx}{iso88593}}%
- \file{l3str-enc-iso88594.def} {\from{l3str.dtx}{iso88594}}%
- \file{l3str-enc-iso88595.def} {\from{l3str.dtx}{iso88595}}%
- \file{l3str-enc-iso88596.def} {\from{l3str.dtx}{iso88596}}%
- \file{l3str-enc-iso88597.def} {\from{l3str.dtx}{iso88597}}%
- \file{l3str-enc-iso88598.def} {\from{l3str.dtx}{iso88598}}%
- \file{l3str-enc-iso88599.def} {\from{l3str.dtx}{iso88599}}%
- \file{l3str-enc-iso885910.def} {\from{l3str.dtx}{iso885910}}%
- \file{l3str-enc-iso885911.def} {\from{l3str.dtx}{iso885911}}%
- \file{l3str-enc-iso885913.def} {\from{l3str.dtx}{iso885913}}%
- \file{l3str-enc-iso885914.def} {\from{l3str.dtx}{iso885914}}%
- \file{l3str-enc-iso885915.def} {\from{l3str.dtx}{iso885915}}%
- \file{l3str-enc-iso885916.def} {\from{l3str.dtx}{iso885916}}%
+ \file{l3str-enc-iso88591.def} {\from{l3str-convert.dtx}{iso88591}}%
+ \file{l3str-enc-iso88592.def} {\from{l3str-convert.dtx}{iso88592}}%
+ \file{l3str-enc-iso88593.def} {\from{l3str-convert.dtx}{iso88593}}%
+ \file{l3str-enc-iso88594.def} {\from{l3str-convert.dtx}{iso88594}}%
+ \file{l3str-enc-iso88595.def} {\from{l3str-convert.dtx}{iso88595}}%
+ \file{l3str-enc-iso88596.def} {\from{l3str-convert.dtx}{iso88596}}%
+ \file{l3str-enc-iso88597.def} {\from{l3str-convert.dtx}{iso88597}}%
+ \file{l3str-enc-iso88598.def} {\from{l3str-convert.dtx}{iso88598}}%
+ \file{l3str-enc-iso88599.def} {\from{l3str-convert.dtx}{iso88599}}%
+ \file{l3str-enc-iso885910.def} {\from{l3str-convert.dtx}{iso885910}}%
+ \file{l3str-enc-iso885911.def} {\from{l3str-convert.dtx}{iso885911}}%
+ \file{l3str-enc-iso885913.def} {\from{l3str-convert.dtx}{iso885913}}%
+ \file{l3str-enc-iso885914.def} {\from{l3str-convert.dtx}{iso885914}}%
+ \file{l3str-enc-iso885915.def} {\from{l3str-convert.dtx}{iso885915}}%
+ \file{l3str-enc-iso885916.def} {\from{l3str-convert.dtx}{iso885916}}%
}
\endbatchfile
diff --git a/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx b/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx
index 4ceef260a99..b9e5bbd087e 100644
--- a/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/l3str/l3tl-analysis.dtx
@@ -126,7 +126,7 @@
% information about individual tokens (category code, character code),
% as well as reconstruct the token list quickly. This internal format is
% used in \pkg{l3regex} where we need to support arbitrary tokens, and
-% it is used in conversion functions in \pkg{l3str}, where we wish to
+% it is used in conversion functions in \pkg{l3str-convert}, where we wish to
% support clusters of characters instead of single tokens.
%
% We thus need a way to encode any \meta{token} (even begin-group and
@@ -143,12 +143,12 @@
% The \meta{tokens} \texttt{o}- \emph{and} \texttt{x}-expand to the
% original token in the token list or to the cluster of tokens
% corresponding to one Unicode character in the given encoding (for
-% \pkg{l3str}). The \meta{catcode} is given as a single hexadecimal
+% \pkg{l3str-convert}). The \meta{catcode} is given as a single hexadecimal
% digit, $0$ for control sequences. The \meta{char code} is given as a
% decimal number, $-1$ for control sequences.
%
% Using delimited arguments lets us build the \meta{tokens}
-% progressively when doing an encoding conversion in \pkg{l3str}. On the
+% progressively when doing an encoding conversion in \pkg{l3str-convert}. On the
% other hand, the delimiter \cs{s__tl} may not appear unbraced in
% \meta{tokens}. This is not a problem because we are careful to wrap
% control sequences in braces (as an argument to \cs{exp_not:n}) when
@@ -423,7 +423,7 @@
\cs_new_protected:Npn \@@_disable_loop:N #1
{
\tex_lccode:D \c_zero `#1 ~
- \tl_to_lowercase:n { \tex_let:D ^^@ } \c_undefined:D
+ \tl_to_lowercase:n { \tex_let:D ^^@ } \tex_undefined:D
\@@_disable_loop:N
}
\group_end:
@@ -807,7 +807,7 @@
{
\cs_new:Npn \@@_b_char:Nww #1
{
- \if_meaning:w #1 \c_undefined:D ? \else:
+ \if_meaning:w #1 \tex_undefined:D ? \else:
\if_catcode:w #1 \c_catcode_other_token C \else:
\if_catcode:w #1 \c_catcode_letter_token B \else:
\if_catcode:w #1 \c_math_toggle_token 3 \else:
@@ -1073,7 +1073,7 @@
{ \str_count:n { #1 ~ ( #4 #2 #3 ) } }
> { \l_iow_line_count_int - \c_three }
{
- \str_substr:nnn { #1 ~ ( #4 #2 #3 ) } \c_one
+ \str_range:nnn { #1 ~ ( #4 #2 #3 ) } \c_one
{
\l_iow_line_count_int - \c_three
- \str_count:N \c_@@_show_etc_str
diff --git a/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx b/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx
index e2407f043a7..60ebd14993f 100644
--- a/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx
+++ b/Master/texmf-dist/source/latex/l3experimental/xgalley/l3galley.dtx
@@ -37,7 +37,7 @@
%
%<*driver|package>
\RequirePackage{xparse}
-\GetIdInfo$Id: l3galley.dtx 4388 2012-12-20 22:15:35Z joseph $
+\GetIdInfo$Id: l3galley.dtx 4402 2013-01-08 08:59:44Z bruno $
{L3 Experimental galley code}
%</driver|package>
%<*driver>
@@ -279,7 +279,7 @@
% \end{syntax}
% Adds a cutout section to the active paragraph shape, leaving
% \meta{unaltered lines} unchanged and then applying the \meta{indents}
-% (a comma list). The cutout will be places on the left or right as indicated
+% (a comma list). The cutout will be placed on the left or right as indicated
% by the function name, and will apply to exactly the number of lines
% specified (the total of the \meta{unaltered lines} and the number of
% entries in the \meta{indents} list). Several cutouts may be applied
diff --git a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
index 8ea41c4eb2d..b7a91c8d848 100644
--- a/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/expl3.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: expl3.dtx Copyright (C) 1990-2012 The LaTeX3 Project
+%% File: expl3.dtx Copyright (C) 1990-2013 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
@@ -49,8 +49,8 @@
%<*driver|package>
\def\ExplFileName{expl3}
\def\ExplFileDescription{L3 Experimental code bundle wrapper}
-\def\ExplFileDate{2012/12/21}
-\def\ExplFileVersion{4390}
+\def\ExplFileDate{2013/03/12}
+\def\ExplFileVersion{4467}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3.ins b/Master/texmf-dist/source/latex/l3kernel/l3.ins
new file mode 100644
index 00000000000..b869a70fee5
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3kernel/l3.ins
@@ -0,0 +1,93 @@
+\iffalse meta-comment
+
+File l3.ins Copyright (C) 2011,2012 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 "l3kernel 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.
+
+\fi
+
+\let\jobname\relax
+\input l3docstrip.dtx
+\askforoverwritefalse
+
+\preamble
+
+EXPERIMENTAL CODE
+
+Do not distribute this file without also distributing the
+source files specified above.
+
+Do not distribute a modified version of this file.
+
+\endpreamble
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+
+\keepsilent
+
+% ===== PACKAGE ONLY ======
+\generate{\file{expl3.sty} {\from{expl3.dtx} {package}}}
+% ========================
+\generate{\file{l3bootstrap.sty} {\from{l3bootstrap.dtx}{package}}}
+\generate{\file{l3names.sty} {\from{l3names.dtx} {package}}}
+\generate{\file{l3basics.sty} {\from{l3basics.dtx} {package}}}
+\generate{\file{l3expan.sty} {\from{l3expan.dtx} {package}}}
+\generate{\file{l3tl.sty} {\from{l3tl.dtx} {package}}}
+\generate{\file{l3seq.sty} {\from{l3seq.dtx} {package}}}
+\generate{\file{l3int.sty} {\from{l3int.dtx} {package}}}
+\generate{\file{l3quark.sty} {\from{l3quark.dtx} {package}}}
+\generate{\file{l3prg.sty} {\from{l3prg.dtx} {package}}}
+\generate{\file{l3clist.sty} {\from{l3clist.dtx} {package}}}
+\generate{\file{l3token.sty} {\from{l3token.dtx} {package}}}
+\generate{\file{l3prop.sty} {\from{l3prop.dtx} {package}}}
+\generate{\file{l3msg.sty} {\from{l3msg.dtx} {package}}}
+\generate{\file{l3file.sty} {\from{l3file.dtx} {package}}}
+\generate{\file{l3skip.sty} {\from{l3skip.dtx} {package}}}
+\generate{\file{l3keys.sty} {\from{l3keys.dtx} {package}}}
+\generate
+ {%
+ \file{l3fp.sty}
+ {%
+ \from{l3fp.dtx} {package}
+ \from{l3fp-aux.dtx} {package}
+ \from{l3fp-traps.dtx} {package}
+ \from{l3fp-round.dtx} {package}
+ \from{l3fp-parse.dtx} {package}
+ \from{l3fp-logic.dtx} {package}
+ \from{l3fp-basics.dtx} {package}
+ \from{l3fp-extended.dtx}{package}
+ \from{l3fp-expo.dtx} {package}
+ \from{l3fp-trig.dtx} {package}
+ \from{l3fp-convert.dtx} {package}
+ \from{l3fp-assign.dtx} {package}
+ \from{l3fp-old.dtx} {package}
+ }%
+ }
+\generate{\file{l3box.sty} {\from{l3box.dtx} {package}}}
+\generate{\file{l3coffins.sty} {\from{l3coffins.dtx} {package}}}
+\generate{\file{l3color.sty} {\from{l3color.dtx} {package}}}
+\generate{\file{l3luatex.sty} {\from{l3luatex.dtx} {package}}}
+\generate{\file{l3candidates.sty}{\from{l3candidates.dtx}{package}}}
+
+\generate{\file{l3doc.cls} {\from{l3doc.dtx} {class}}}
+\generate{\file{l3doc.ist} {\from{l3doc.dtx} {docist}}}
+
+\generate{\file{l3dvipdfmx.def} {\from{l3drivers.dtx} {package,dvipdfmx} }}
+\generate{\file{l3dvips.def} {\from{l3drivers.dtx} {package,dvips} }}
+\generate{\file{l3pdfmode.def} {\from{l3drivers.dtx} {package,pdfmode} }}
+\generate{\file{l3xdvipdfmx.def} {\from{l3drivers.dtx} {package,xdvipdfmx}}}
+
+\generate{\file{l3docstrip.tex} {\from{l3docstrip.dtx} {program}}}
+
+\endbatchfile
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx
index 733beefe452..98fe66d8b35 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3basics.dtx Copyright (C) 1990-2012 The LaTeX3 project
+%% File: l3basics.dtx Copyright (C) 1990-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3basics.dtx 4339 2012-11-24 19:16:43Z joseph $
+\GetIdInfo$Id: l3basics.dtx 4428 2013-01-10 13:23:29Z bruno $
{L3 Basic definitions}
%</driver|package>
%<*driver>
@@ -183,8 +183,28 @@
% \cs{par} tokens but the function will not expand within an
% \texttt{x}-type expansion.
% \end{description}
+%
+% Finally, the functions in
+% Subsections~\ref{sec:defining-new-function-1}~and
+% \ref{sec:defining-new-function-2} are primarily meant to define
+% \emph{base functions} only. Base functions can only have the following
+% argument specifiers:
+% \begin{description}
+% \item[|N| and |n|] No manipulation.
+% \item[|T| and |F|] Functionally equivalent to |n| (you are actually
+% encouraged to use the family of |\prg_new_conditional:| functions
+% described in Section~\ref{sec:new-conditional-functions}).
+% \item[|p| and |w|] These are special cases.
+% \end{description}
+%
+% The |\cs_new:| functions below (and friends) do not stop you from using
+% other argument specifiers in your function names, but they do not handle
+% expansion for you. You should define the base function and then use
+% \cs{cs_generate_variant:Nn} to generate custom variants as described in
+% Section~\ref{sec:defining-variants}.
%
% \subsection{Defining new functions using parameter text}
+% \label{sec:defining-new-function-1}
%
% \begin{function}{\cs_new:Npn, \cs_new:cpn, \cs_new:Npx, \cs_new:cpx}
% \begin{syntax}
@@ -373,6 +393,7 @@
% \end{function}
%
% \subsection{Defining new functions using the signature}
+% \label{sec:defining-new-function-2}
%
% \begin{function}
% {
@@ -777,7 +798,7 @@
%
% \begin{function}[EXP]{\cs_to_str:N}
% \begin{syntax}
-% \cs{cs_to_str:N} \Arg{control sequence}
+% \cs{cs_to_str:N} \meta{control sequence}
% \end{syntax}
% Converts the given \meta{control sequence} into a series of
% characters with category code $12$ (other), except spaces,
@@ -1131,7 +1152,7 @@
% ~~|}| \\
% ~~\Arg{else code}
% \end{syntax}
-% This function comapres the full expansion of the \meta{test string}
+% This function compares the full expansion of the \meta{test string}
% in turn with the full expansion of the \meta{string cases}. If the two
% full expansions are equal (as described for \cs{str_if_eq:nnTF} then the
% associated \meta{code} is left in the input stream. If none of the tests
@@ -1145,7 +1166,7 @@
%
% \begin{function}[updated = 2011-09-06,EXP,pTF]{\luatex_if_engine:}
% \begin{syntax}
-% \cs{luatex_if_luatex:TF} \Arg{true code} \Arg{false code}
+% \cs{luatex_if_engine:TF} \Arg{true code} \Arg{false code}
% \end{syntax}
% Detects is the document is being compiled using \LuaTeX{}.
% \end{function}
@@ -2608,7 +2629,7 @@
% \TeX{} conditionals in case |#1| is unbalanced in this matter.
% \begin{macrocode}
\cs_new_protected:Npn \cs_undefine:N #1
- { \cs_gset_eq:NN #1 \c_undefined:D }
+ { \cs_gset_eq:NN #1 \tex_undefined:D }
\cs_new_protected:Npn \cs_undefine:c #1
{
\if_cs_exist:w #1 \cs_end:
@@ -2616,7 +2637,7 @@
\else:
\exp_after:wN \use_none:n
\fi:
- { \cs_gset_eq:cN {#1} \c_undefined:D }
+ { \cs_gset_eq:cN {#1} \tex_undefined:D }
}
% \end{macrocode}
% \end{macro}
@@ -3226,16 +3247,20 @@
% \begin{macro}[pTF, EXP]{\str_if_eq:xx}
% Not really true \texttt{x}-type expansion
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \str_if_eq_p:xx \str_if_eq_x_p:nn
\cs_new_eq:NN \str_if_eq:xxT \str_if_eq_x:nnT
\cs_new_eq:NN \str_if_eq:xxF \str_if_eq_x:nnF
\cs_new_eq:NN \str_if_eq:xxTF \str_if_eq_x:nnTF
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\chk_if_free_cs:N}
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \chk_if_free_cs:N \__chk_if_free_cs:N
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx
index fc1ae68b7c2..9ce55b15be3 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3bootstrap.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3bootstrap.dtx Copyright (C) 2011-2012 The LaTeX3 project
+%% File: l3bootstrap.dtx Copyright (C) 2011-2013 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
@@ -119,7 +119,7 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
-\GetIdInfo$Id: l3bootstrap.dtx 3991 2012-07-16 19:00:35Z joseph $
+\GetIdInfo$Id: l3bootstrap.dtx 4420 2013-01-08 20:00:04Z joseph $
{L3 Bootstrap code}
%</driver|package>
%<*driver>
@@ -672,6 +672,7 @@
% package or format itself. Using an \tn{edef} here makes the
% definitions that bit clearer later.
% \begin{macrocode}
+%<*deprecated>
\protected\edef\ExplSyntaxNamesOn
{%
\expandafter\noexpand
@@ -686,6 +687,7 @@
\expandafter\noexpand
\csname\detokenize{char_set_catcode_math_subscript:n}\endcsname{95}%
}
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
index c6ccdfb12a9..b6e89bde0be 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3box.dtx 4347 2012-12-08 09:11:29Z joseph $
+\GetIdInfo$Id: l3box.dtx 4411 2013-01-08 12:21:52Z bruno $
{L3 Experimental boxes}
%</driver|package>
%<*driver>
@@ -760,14 +760,8 @@
% \begin{macro}[pTF]{\box_if_exist:N, \box_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \box_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \box_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \box_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \box_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \box_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \box_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \box_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \box_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \box_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \box_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
index 4aa22e27714..88a4d9898b5 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3candidates.dtx
@@ -36,7 +36,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3candidates.dtx 4383 2012-12-20 15:10:48Z bruno $
+\GetIdInfo$Id: l3candidates.dtx 4466 2013-03-09 14:58:43Z joseph $
{L3 Experimental additions to l3kernel}
%</driver|package>
%<*driver>
@@ -406,7 +406,7 @@
% \cs{ior_str_map_inline:Nn} \Arg{stream} \Arg{inline function}
% \end{syntax}
% Applies the \meta{inline function} to every \meta{line}
-% in the \meta{sream}. The material is read from the \meta{stream}
+% in the \meta{stream}. The material is read from the \meta{stream}
% as a series of tokens with category code $12$ (other), with the
% exception of space characters which are given category code $10$
% (space). The \meta{inline function} should consist of code which
@@ -2243,12 +2243,14 @@
\cs_new:Npn \prop_map_tokens:Nn #1#2
{
\exp_last_unbraced:Nno \@@_map_tokens:nwn {#2} #1
- \q_recursion_tail \q__prop { }
+ \s_@@ \q_recursion_tail \s_@@ { }
\__prg_break_point:Nn \prop_map_break: { }
}
-\cs_new:Npn \@@_map_tokens:nwn #1 \q__prop #2 \q__prop #3
+\cs_new:Npn \@@_map_tokens:nwn #1 \s_@@ #2 \s_@@ #3
{
- \__quark_if_recursion_tail_break:NN #2 \prop_map_break:
+ \if_meaning:w \q_recursion_tail #2
+ \exp_after:wN \prop_map_break:
+ \fi:
\use:n {#1} {#2} {#3}
\@@_map_tokens:nwn {#1}
}
@@ -2271,10 +2273,10 @@
{
\exp_last_unbraced:Noo \@@_get_Nn:nwn
{ \tl_to_str:n {#2} } #1
- \tl_to_str:n {#2} \q__prop { }
+ \tl_to_str:n {#2} \q_@@ { }
\__prg_break_point:
}
-\cs_new:Npn \@@_get_Nn:nwn #1 \q__prop #2 \q__prop #3
+\cs_new:Npn \@@_get_Nn:nwn #1 \q_@@ #2 \q_@@ #3
{
\str_if_eq_x:nnTF {#1} {#2}
{ \__prg_break:n { \exp_not:n {#3} } }
@@ -2886,11 +2888,11 @@
\exp_after:wN \@@_false:w
\fi:
}
- \cs_new_protected_nopar:Npn \@@_N_type:w #1 OUTER #2 \q_mark #3
+ \cs_new_protected:Npn \@@_N_type:w #1 OUTER #2 \q_mark #3
{ #3 {#1} {#2} }
}
\group_end:
-\cs_new_protected_nopar:Npn \@@_N_type_aux:nnw #1 #2 #3 \fi:
+\cs_new_protected:Npn \@@_N_type_aux:nnw #1 #2 #3 \fi:
{
\fi:
\tl_if_in:noTF {#1} { \tl_to_str:n {ma} }
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
index 68c36d63a4a..333bbb9402a 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3clist.dtx
@@ -2,7 +2,7 @@
%
%% File: l3clist.dtx Copyright (C) 2004-2011 Frank Mittelbach,
%% The LaTeX3 project
-%% (C) 2012 The LaTeX3 Project
+%% (C) 2012,2013 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
@@ -37,7 +37,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3clist.dtx 4339 2012-11-24 19:16:43Z joseph $
+\GetIdInfo$Id: l3clist.dtx 4414 2013-01-08 12:32:12Z bruno $
{L3 Comma separated lists}
%</driver|package>
%<*driver>
@@ -690,14 +690,8 @@
% \begin{macro}[pTF]{\clist_if_exist:N, \clist_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \clist_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \clist_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \clist_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \clist_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \clist_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \clist_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \clist_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \clist_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \clist_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \clist_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
@@ -1454,10 +1448,12 @@
% {\clist_if_eq:NN, \clist_if_eq:Nc, \clist_if_eq:cN, \clist_if_eq:cc}
% Simple copies from the token list variable material.
% \begin{macrocode}
-\prg_new_eq_conditional:NNn \clist__if_eq:NN \tl_if_eq:NN { p , T , F , TF }
+%<*deprecated>
+\prg_new_eq_conditional:NNn \clist_if_eq:NN \tl_if_eq:NN { p , T , F , TF }
\prg_new_eq_conditional:NNn \clist_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF }
\prg_new_eq_conditional:NNn \clist_if_eq:cN \tl_if_eq:cN { p , T , F , TF }
\prg_new_eq_conditional:NNn \clist_if_eq:cc \tl_if_eq:cc { p , T , F , TF }
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -1465,9 +1461,11 @@
%
% \begin{macro}{\clist_length:N, \clist_length:c, \clist_length:n}
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \clist_length:N \clist_count:N
\cs_new_eq:NN \clist_length:n \clist_count:c
\cs_new_eq:NN \clist_length:c \clist_count:n
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -1475,8 +1473,10 @@
%
% \begin{macro}{\clist_use:N, \clist_use:c}
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \clist_use:N \tl_use:N
\cs_new_eq:NN \clist_use:c \tl_use:c
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx
index f6734d35f46..073a979140e 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3doc.dtx
@@ -78,7 +78,7 @@ Do not distribute a modified version of this file.
%</driver|class>
%
%<*driver|class>
-\GetIdInfo$Id: l3doc.dtx 4267 2012-11-04 19:42:13Z joseph $
+\GetIdInfo$Id: l3doc.dtx 4442 2013-01-13 08:56:27Z bruno $
{L3 Experimental documentation class}
%</driver|class>
%
@@ -1751,6 +1751,7 @@ Do not distribute a modified version of this file.
{
\seq_use:Nnnn \g_@@_tmpa_seq
{ \,~and~ } { \,,~ } { \,,~and~ }
+ \@.
}
{ \seq_item:Nn \g_@@_tmpa_seq {1}\,~and~others. }
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx
index d912433ee8d..739acab95e5 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3expan.dtx
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3expan.dtx 4149 2012-08-28 10:50:40Z bruno $
+\GetIdInfo$Id: l3expan.dtx 4458 2013-02-03 15:49:37Z bruno $
{L3 Argument expansion}
%</driver|package>
%<*driver>
@@ -78,6 +78,7 @@
% variants.
%
% \section{Defining new variants}
+% \label{sec:defining-variants}
%
% The definition of variant forms for base functions may be necessary
% when writing new functions or when applying a kernel function in a
@@ -193,22 +194,22 @@
% specific expansion steps are needed, such as when using delimited
% arguments, should the lower-level functions with |o| specifiers be employed.
%
-% The |f| type is so special that it deserves an example.
-% Let's pretend we want to set |\aaa| equal to the control sequence
-% stemming from turning |b \l_tmpa_tl b| into a control
-% sequence. Furthermore we want to store the execution of it in a
+% The |f| type is so special that it deserves an example. Let's pretend
+% we want to set the control sequence whose name is given by
+% |b \l_tmpa_tl b| equal to the list of tokens |\aaa a|. Furthermore we
+% want to store the execution of it in a
% \meta{tl~var}. In this example we assume |\l_tmpa_tl| contains
% the text string |lur|. The straightforward approach is
% \begin{quote}
-% |\tl_set:No \l_tmpb_tl { \cs_set_eq:Nc \aaa { b \l_tmpa_tl b } }|
+% |\tl_set:No \l_tmpb_tl { \tl_set:cn { b \l_tmpa_tl b } { \aaa a } }|
% \end{quote}
% Unfortunately this only puts
-% |\exp_args:NNc \cs_set_eq:NN \aaa {b \l_tmpa_tl b}| into |\l_tmpb_tl|
-% and not |\cs_set_eq:NN \aaa = \blurb| as we probably wanted. Using
-% \cs{tl_set:Nx} is not an option as that will die horribly. Instead
-% we can do a
+% |\exp_args:Nc \tl_set:Nn {b \l_tmpa_tl b} { \aaa a }| into
+% |\l_tmpb_tl| and not |\tl_set:Nn \blurb { \aaa a }| as we probably
+% wanted. Using \cs{tl_set:Nx} is not an option as that will die
+% horribly. Instead we can do a
% \begin{quote}
-% |\tl_set:Nf \l_tmpb_tl { \cs_set_eq:Nc \aaa { b \l_tmpa_tl b } }|
+% |\tl_set:Nf \l_tmpb_tl { \tl_set:cn { b \l_tmpa_tl b } { \aaa a } }|
% \end{quote}
% which puts the desired result in |\l_tmpb_tl|. It requires
% \cs{tl_set:Nf} to be defined as
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
index 416fc76cacb..67461fd01c9 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3file.dtx Copyright (C) 1990-2012 The LaTeX3 Project
+%% File: l3file.dtx Copyright (C) 1990-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3file.dtx 4377 2012-12-20 11:13:29Z bruno $
+\GetIdInfo$Id: l3file.dtx 4446 2013-01-14 00:03:17Z bruno $
{L3 File and I/O operations}
%</driver|package>
%<*driver>
@@ -192,6 +192,20 @@
% allocated to \meta{file name} until a \cs{ior_close:N} instruction
% is given or the \TeX{} run ends.
% \end{function}
+%
+% \begin{function}[added = 2013-01-12, TF]{\ior_open:Nn, \ior_open:cn}
+% \begin{syntax}
+% \cs{ior_open:NnTF} \meta{stream} \Arg{file name} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Opens \meta{file name} for reading using \meta{stream} as the
+% control sequence for file access. If the \meta{stream} was already
+% open it is closed before the new operation begins. The
+% \meta{stream} is available for access immediately and will remain
+% allocated to \meta{file name} until a \cs{ior_close:N} instruction
+% is given or the \TeX{} run ends. The \meta{true code} is then inserted
+% into the input stream. If the file is not found, no error is raised and
+% the \meta{false code} is inserted into the input stream.
+% \end{function}
%
% \begin{function}[updated = 2012-02-09]{\iow_open:Nn, \iow_open:cn}
% \begin{syntax}
@@ -645,11 +659,11 @@
{ \@@_name_sanitize:nn {#1} { \@@_add_path:nN } }
\cs_new_protected:Npn \@@_add_path:nN #1#2
{
- \__ior_open:Nn \g__file_internal_ior {#1}
- \ior_if_eof:NTF \g__file_internal_ior
+ \__ior_open:Nn \g_@@_internal_ior {#1}
+ \ior_if_eof:NTF \g_@@_internal_ior
{ \@@_add_path_search:nN {#1} #2 }
{ \tl_set:Nn #2 {#1} }
- \ior_close:N \g__file_internal_ior
+ \ior_close:N \g_@@_internal_ior
}
\cs_new_protected:Npn \@@_add_path_search:nN #1#2
{
@@ -665,8 +679,8 @@
%</package>
\seq_map_inline:Nn \l_@@_search_path_seq
{
- \__ior_open:Nn \g__file_internal_ior { ##1 #1 }
- \ior_if_eof:NF \g__file_internal_ior
+ \__ior_open:Nn \g_@@_internal_ior { ##1 #1 }
+ \ior_if_eof:NF \g_@@_internal_ior
{
\tl_set:Nx #2 { ##1 #1 }
\seq_map_break:
@@ -824,71 +838,41 @@
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\c_@@_streams_tl}
-% The list of streams available, by number.
+% \begin{variable}{\g_@@_streams_seq}
+% A list of the currently-available input streams to be used as a
+% stack. In format mode, all streams (from $0$ to~$15$) are
+% available, while the package requests streams to \LaTeXe{} as they
+% are needed (initially none are needed), so the starting point
+% varies!
% \begin{macrocode}
-\tl_const:Nn \c_@@_streams_tl
- {
- \c_zero
- \c_one
- \c_two
- \c_three
- \c_four
- \c_five
- \c_six
- \c_seven
- \c_eight
- \c_nine
- \c_ten
- \c_eleven
- \c_twelve
- \c_thirteen
- \c_fourteen
- \c_fifteen
- }
+\seq_new:N \g_@@_streams_seq
+%<*initex>
+\seq_gset_split:Nnn \g_@@_streams_seq { , }
+ { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 }
+%</initex>
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\g_@@_streams_prop}
-% The allocations for streams are stored in property lists, which
-% are set up to have a \enquote{full} set of allocations from the start.
-% In package mode, a few slots are always taken, so these are
-% blocked off from use.
+% \begin{variable}{\l_@@_stream_tl}
+% Used to recover the raw stream number from the stack.
% \begin{macrocode}
-\prop_new:N \g_@@_streams_prop
-%<*package>
-\prop_put:Nnn \g_@@_streams_prop { 0 } { LaTeX2e~reserved }
-%</package>
+\tl_new:N \l_@@_stream_tl
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\l_@@_stream_int}
-% Used to track the number allocated to the stream being created:
-% this is taken from the property list but does alter.
+% \begin{variable}{\g_@@_streams_prop}
+% The name of the file attached to each stream is tracked in a property
+% list.
% \begin{macrocode}
-\int_new:N \l_@@_stream_int
+\prop_new:N \g_@@_streams_prop
+%<*package>
+\prop_gput:Nnn \g_@@_streams_prop { 0 } { LaTeX2e~reserved }
+%</package>
% \end{macrocode}
% \end{variable}
%
% \subsubsection{Stream management}
%
-% \begin{macro}[int]{\@@_new:N, \@@_new:c}
-% The lowest level for stream management is actually creating raw \TeX{}
-% streams. As these are very limited (even with \eTeX{}), this should not
-% be addressed directly.
-% \begin{macrocode}
-%<*initex>
-\__alloc_setup_type:nnn { ior } \c_zero \c_sixteen
-\cs_new_protected:Npn \@@_new:N #1
- { \__alloc_reg:nNN { ior } \tex_chardef:D #1 }
-%</initex>
-%<*package>
-\cs_set_eq:NN \@@_new:N \newread
-%</package>
-\cs_generate_variant:Nn \@@_new:N { c }
-% \end{macrocode}
-% \end{macro}
-%
% \begin{macro}{\ior_new:N, \ior_new:c}
% Reserving a new stream is done by defining the name as equal to using the
% terminal.
@@ -897,27 +881,14 @@
\cs_generate_variant:Nn \ior_new:N { c }
% \end{macrocode}
% \end{macro}
-%
-% \begin{variable}{\g__file_internal_ior}
-% Delayed from the \texttt{file} section so that the mechanisms are in place.
-% \begin{macrocode}
-\ior_new:N \g__file_internal_ior
-% \end{macrocode}
-% \end{variable}
-%
+%
% \begin{macro}{\ior_open:Nn, \ior_open:cn}
-% \begin{macro}[TF]{\ior_open:Nn}
% \begin{macro}[aux]{\@@_open_aux:Nn}
-% \begin{macro}[aux]{\@@_open_aux:NnTF}
-% \begin{macro}[aux]{\@@_open:Nn, \@@_open:No}
-% Opening a stream starts with a call to the closing function: this is
-% safest. There is then a loop through the allocation number list to find
-% the first free stream number. When one is found the allocation can take
-% place, the information can be stored and finally the file can actually be
-% opened. Before any actual file operations there is a precaution against
-% special characters in file names. There is an intermediate auxiliary to
-% allow path addition, keeping the internal function fast and avoiding an
-% infinite loop.
+% Opening an input stream requires a bit of pre-processing. The file name
+% is sanitized to deal with active characters, before an auxiliary adds a
+% path and checks that the file really exists. If those two tests pass, then
+% pass the information on to the lower-level function which deals with
+% streams.
% \begin{macrocode}
\cs_new_protected:Npn \ior_open:Nn #1#2
{ \__file_name_sanitize:nn {#2} { \@@_open_aux:Nn #1 } }
@@ -929,8 +900,20 @@
{ \__msg_kernel_error:nnx { kernel } { file-not-found } {#2} }
{ \@@_open:No #1 \l__file_internal_name_tl }
}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[TF]{\ior_open:Nn, \ior_open:cn}
+% \begin{macro}[aux]{\@@_open_aux:NnTF}
+% Much the same idea for opening a read with a conditional, except the
+% auxiliary function does not issue an error if the file is not found.
+% \begin{macrocode}
\prg_new_protected_conditional:Npnn \ior_open:Nn #1#2 { T , F , TF }
- { \__file_name_sanitize:nn {#2} { \@@_open_aux:NnTF #1 } }
+ { \__file_name_sanitize:nn {#2} { \@@_open:NnTF #1 } }
+\cs_generate_variant:Nn \ior_open:NnT { c }
+\cs_generate_variant:Nn \ior_open:NnF { c }
+\cs_generate_variant:Nn \ior_open:NnTF { c }
\cs_new_protected:Npn \@@_open_aux:NnTF #1#2
{
\file_add_path:nN {#2} \l__file_internal_name_tl
@@ -941,115 +924,63 @@
\prg_return_true:
}
}
-\cs_generate_variant:Nn \ior_open:NnT { c }
-\cs_generate_variant:Nn \ior_open:NnF { c }
-\cs_generate_variant:Nn \ior_open:NnTF { c }
-\cs_new_protected:Npn \@@_open:Nn #1#2
- {
- \ior_close:N #1
- \int_set_eq:NN \l_@@_stream_int \c_sixteen
- \tl_map_function:NN \c_@@_streams_tl \@@_alloc:n
- \int_compare:nNnTF \l_@@_stream_int = \c_sixteen
- { \__msg_kernel_fatal:nn { kernel } { input-streams-exhausted } }
- {
- \@@_alloc:N #1
- \prop_gput:NVn \g_@@_streams_prop \l_@@_stream_int {#2}
- \tex_openin:D #1#2 \scan_stop:
- }
- }
-\cs_generate_variant:Nn \@@_open:Nn { No }
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[aux]{\@@_alloc:n}
-% See if a particular stream is available: the property list contains file
-% names for streams in use, so any unused ones are for the taking.
+%
+% \begin{macro}[int]{\@@_open:Nn, \@@_open:No}
+% \begin{macro}[aux]{\@@_open_stream:Nn}
+% The stream allocation itself uses the fact that there is a list of all of
+% those available, so allocation is simply a question of using the number at
+% the top of the list. In package mode, life gets more complex as it's
+% important to keep things in sync. That is done using a two-part approach:
+% any streams that have already been taken up by \pkg{ior} but are now free
+% are tracked, so we first try those. If that fails, ask \LaTeXe{} for a new
+% stream and use that number (after a bit of conversion).
% \begin{macrocode}
-\cs_new_protected:Npn \@@_alloc:n #1
- {
- \prop_if_in:NnF \g_@@_streams_prop {#1}
- {
- \int_set:Nn \l_@@_stream_int {#1}
- \tl_map_break:
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[aux]{\@@_alloc:N}
-% \begin{macro}[aux]{\@@_alloc:}
-% \begin{variable}{\g_@@_internal_ior}
-% Allocating a raw stream is much easier in \IniTeX{} mode than for the
-% package. For the format, all streams will be allocated by \pkg{l3file} and
-% so there is a simple check to see if a raw stream is actually available. On
-% the other hand, for the package there will be non-managed streams. So if
-% the managed one is not open, a check is made to see if some other managed
-% stream is available before deciding to open a new one. If a new one is
-% needed, we get the number allocated by \LaTeXe{} to get \enquote{back on
-% track} with allocation.
-% \begin{macrocode}
-\ior_new:N \g_@@_internal_ior
-\cs_new_protected:Npn \@@_alloc:N #1
+\cs_new_protected:Npn \@@_open:Nn #1#2
{
- \cs_if_exist:cF { g_ior_ \int_use:N \l_@@_stream_int _ior }
- {
-%<*package>
- \@@_alloc:
- \int_compare:nNnT \l_@@_stream_int = \c_sixteen
- {
- \@@_new:N \g_@@_internal_ior
- \int_set:Nn \l_@@_stream_int { \g_@@_internal_ior }
- \cs_gset_eq:cN
- { g_ior_ \int_use:N \l_@@_stream_int _ior } \g_@@_internal_ior
- }
-%</package>
+ \ior_close:N #1
+ \seq_gpop:NNTF \g_@@_streams_seq \l_@@_stream_tl
+ { \@@_open_stream:Nn #1 {#2} }
%<*initex>
- \@@_new:c { g_ior_ \int_use:N \l_@@_stream_int _ior }
+ { \__msg_kernel_fatal:nn { kernel } { input-streams-exhausted } }
%</initex>
- }
- \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_@@_stream_int _ior }
- }
%<*package>
-\cs_new_protected_nopar:Npn \@@_alloc:
- {
- \int_incr:N \l_@@_stream_int
- \int_compare:nNnT \l_@@_stream_int < \c_sixteen
{
- \cs_if_exist:cTF { g_ior_ \int_use:N \l_@@_stream_int _ior }
- {
- \prop_if_in:NVT \g_@@_streams_prop \l_@@_stream_int
- { \@@_alloc: }
- }
- { \@@_alloc: }
+ \newread #1
+ \tl_set:Nx \l_@@_stream_tl { \int_eval:n {#1} }
+ \@@_open_stream:Nn #1 {#2}
}
- }
%</package>
+ }
+\cs_generate_variant:Nn \@@_open:Nn { No }
+\cs_new_protected:Npn \@@_open_stream:Nn #1#2
+ {
+ \tex_global:D \tex_chardef:D #1 = \l_@@_stream_tl \scan_stop:
+ \prop_gput:NVn \g_@@_streams_prop #1 {#2}
+ \tex_openin:D #1 #2 \scan_stop:
+ }
% \end{macrocode}
-% \end{variable}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\ior_close:N, \ior_close:c}
-% Closing a stream is not quite the reverse of opening one. First,
-% the close operation is easier than the open one, and second as the
-% stream is actually a number we can use it directly to show that the
-% slot has been freed up.
+% Closing a stream means getting rid of it at the \TeX{} level and
+% removing from the various data structures. Unless the name passed
+% is an invalid stream number (outside the range $[0,15]$), it can be
+% closed. On the other hand, it only gets added to the stack if it
+% was not already there, to avoid duplicates building up.
% \begin{macrocode}
\cs_new_protected:Npn \ior_close:N #1
{
- \__chk_if_exist_cs:N #1
- \int_compare:nNnF #1 < \c_zero
+ \int_compare:nT { \c_minus_one < #1 < \c_sixteen }
{
- \int_compare:nNnF #1 > \c_fifteen
- {
- \tex_closein:D #1
- \prop_gremove:NV \g_@@_streams_prop #1
- \cs_gset_eq:NN #1 \c_term_ior
- }
+ \tex_closein:D #1
+ \prop_gremove:NV \g_@@_streams_prop #1
+ \seq_if_in:NVF \g_@@_streams_seq #1
+ { \seq_gpush:NV \g_@@_streams_seq #1 }
+ \cs_gset_eq:NN #1 \c_term_ior
}
}
\cs_generate_variant:Nn \ior_close:N { c }
@@ -1135,6 +1066,13 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{variable}{\g__file_internal_ior}
+% Needed by the higher-level code, but cannot be created until here.
+% \begin{macrocode}
+\ior_new:N \g__file_internal_ior
+% \end{macrocode}
+% \end{variable}
+%
% \subsection{Output operations}
%
% \begin{macrocode}
@@ -1142,7 +1080,8 @@
% \end{macrocode}
%
% There is a lot of similarity here to the input operations, at least for
-% many of the basics. Thus quite a bit is copied from the earlier material.
+% many of the basics. Thus quite a bit is copied from the earlier material
+% with minor alterations.
%
% \subsubsection{Variables and constants}
%
@@ -1156,11 +1095,22 @@
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\c_@@_streams_tl}
-% The list of streams available, by number: copied from the input
-% operations.
+% \begin{variable}{\g_@@_streams_seq}
+% A list of the currently-available input streams to be used as a stack.
+% Things are done differently in format and package mode, so the starting
+% point varies!
% \begin{macrocode}
-\cs_new_eq:NN \c_@@_streams_tl \c__ior_streams_tl
+\seq_new:N \g_@@_streams_seq
+%<*initex>
+\seq_gset_eq:NN \g_@@_streams_seq \g__ior_streams_seq
+%</initex>
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_stream_tl}
+% Used to recover the raw stream number from the stack.
+% \begin{macrocode}
+\tl_new:N \l_@@_stream_tl
% \end{macrocode}
% \end{variable}
%
@@ -1176,32 +1126,8 @@
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\l_@@_stream_int}
-% Used to track the number allocated to the stream being created:
-% this is taken from the property list but does alter. The two allocation
-% routines only need one register, so we save one here.
-% \begin{macrocode}
-\cs_new_eq:NN \l_@@_stream_int \l__ior_stream_int
-% \end{macrocode}
-% \end{variable}
-%
% \subsection{Stream management}
%
-% \begin{macro}[aux]{\@@_new:N, \@@_new:c}
-% The same idea as for input, but with a separate set of functions.
-% \begin{macrocode}
-%<*initex>
-\__alloc_setup_type:nnn { iow } \c_zero \c_sixteen
-\cs_new_protected:Npn \@@_new:N #1
- { \__alloc_reg:nNN { iow } \tex_chardef:D #1 }
-%</initex>
-%<*package>
-\cs_set_eq:NN \@@_new:N \newwrite
-%</package>
-\cs_generate_variant:Nn \@@_new:N { c }
-% \end{macrocode}
-% \end{macro}
-%
% \begin{macro}{\iow_new:N, \iow_new:c}
% Reserving a new stream is done by defining the name as equal to writing
% to the terminal: odd but at least consistent.
@@ -1212,8 +1138,10 @@
% \end{macro}
%
% \begin{macro}{\iow_open:Nn, \iow_open:cn}
-% \begin{macro}[aux]{\@@_open:Nn}
-% The same idea as for reading, but without the path.
+% \begin{macro}[int]{\@@_open:Nn}
+% \begin{macro}[aux]{\@@_open_stream:Nn}
+% The same idea as for reading, but without the path and without the need
+% to allow for a conditional version.
% \begin{macrocode}
\cs_new_protected:Npn \iow_open:Nn #1#2
{ \__file_name_sanitize:nn {#2} { \@@_open:Nn #1 } }
@@ -1221,78 +1149,28 @@
\cs_new_protected:Npn \@@_open:Nn #1#2
{
\iow_close:N #1
- \int_set_eq:NN \l_@@_stream_int \c_sixteen
- \tl_map_function:NN \c_@@_streams_tl \@@_alloc:n
- \int_compare:nNnTF \l_@@_stream_int = \c_sixteen
+ \seq_gpop:NNTF \g_@@_streams_seq \l_@@_stream_tl
+ { \@@_open_stream:Nn #1 {#2} }
+%<*initex>
{ \__msg_kernel_fatal:nn { kernel } { output-streams-exhausted } }
+%</initex>
+%<*package>
{
- \@@_alloc:N #1
- \prop_gput:NVn \g_@@_streams_prop \l_@@_stream_int {#2}
- \tex_immediate:D \tex_openout:D #1#2 \scan_stop:
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[aux]{\@@_alloc:n}
-% Identical to the input routine, but with the appropriate names used
-% (when \pkg{l3docstrip} has done it's job!).
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_alloc:n #1
- {
- \prop_if_in:NnF \g_@@_streams_prop {#1}
- {
- \int_set:Nn \l_@@_stream_int {#1}
- \tl_map_break:
+ \newwrite #1
+ \tl_set:Nx \l_@@_stream_tl { \int_eval:n {#1} }
+ \@@_open_stream:Nn #1 {#2}
}
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[aux]{\@@_alloc:N}
-% \begin{macro}[aux]{\@@_alloc:}
-% \begin{variable}{\g_@@_internal_iow}
-% Exactly the same as for reading!
-% \begin{macrocode}
-\iow_new:N \g_@@_internal_iow
-\cs_new_protected:Npn \@@_alloc:N #1
- {
- \cs_if_exist:cF { g_iow_ \int_use:N \l_@@_stream_int _iow }
- {
-%<*package>
- \@@_alloc:
- \int_compare:nNnT \l_@@_stream_int = \c_sixteen
- {
- \@@_new:N \g_@@_internal_iow
- \int_set:Nn \l_@@_stream_int { \g_@@_internal_iow }
- \cs_gset_eq:cN
- { g_iow_ \int_use:N \l_@@_stream_int _iow } \g_@@_internal_iow
- }
%</package>
-%<*initex>
- \@@_new:c { g_iow_ \int_use:N \l_@@_stream_int _iow }
-%</initex>
- }
- \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_@@_stream_int _iow }
}
-%<*package>
-\cs_new_protected_nopar:Npn \@@_alloc:
+\cs_generate_variant:Nn \@@_open:Nn { No }
+\cs_new_protected:Npn \@@_open_stream:Nn #1#2
{
- \int_incr:N \l_@@_stream_int
- \int_compare:nNnT \l_@@_stream_int < \c_sixteen
- {
- \cs_if_exist:cTF { g_iow_ \int_use:N \l_@@_stream_int _iow }
- {
- \prop_if_in:NVT \g_@@_streams_prop \l_@@_stream_int
- { \@@_alloc: }
- }
- { \@@_alloc: }
- }
+ \tex_global:D \tex_chardef:D #1 = \l_@@_stream_tl \scan_stop:
+ \prop_gput:NVn \g_@@_streams_prop #1 {#2}
+ \tex_immediate:D \tex_openout:D #1 #2 \scan_stop:
}
-%</package>
% \end{macrocode}
-% \end{variable}
+% \end{macro}
% \end{macro}
% \end{macro}
%
@@ -1304,15 +1182,13 @@
% \begin{macrocode}
\cs_new_protected:Npn \iow_close:N #1
{
- \__chk_if_exist_cs:N #1
- \int_compare:nNnF #1 < \c_zero
+ \int_compare:nT { \c_minus_one < #1 < \c_sixteen }
{
- \int_compare:nNnF #1 > \c_fifteen
- {
- \tex_immediate:D \tex_closeout:D #1
- \prop_gremove:NV \g_@@_streams_prop #1
- \cs_gset_eq:NN #1 \c_term_iow
- }
+ \tex_immediate:D \tex_closeout:D #1
+ \prop_gremove:NV \g_@@_streams_prop #1
+ \seq_if_in:NVF \g_@@_streams_seq #1
+ { \seq_gpush:NV \g_@@_streams_seq #1 }
+ \cs_gset_eq:NN #1 \c_term_ior
}
}
\cs_generate_variant:Nn \iow_close:N { c }
@@ -1809,8 +1685,10 @@
% \begin{macro}{\iow_wrap:xnnnN}
% This was renamed and one unneed argument was removed.
% \begin{macrocode}
+%<*deprecated>
\cs_new_protected:Npn \iow_wrap:xnnnN #1#2#3#4#5
{ \iow_wrap:nnnN {#1} {#2} {#4} #5 }
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -1819,7 +1697,9 @@
% \begin{variable}{\l_iow_line_length_int}
% Simple rename. Here we copy the \TeX{} register.
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \l_iow_line_length_int \l_iow_line_count_int
+%</deprecated>
% \end{macrocode}
% \end{variable}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3format.ins b/Master/texmf-dist/source/latex/l3kernel/l3format.ins
new file mode 100644
index 00000000000..76fe0ee3e76
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3kernel/l3format.ins
@@ -0,0 +1,92 @@
+\iffalse meta-comment
+
+File l3format.ins Copyright (C) 2011,2012 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 "l3kernel 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.
+
+\fi
+
+\let\jobname\relax
+\input l3docstrip.dtx
+\askforoverwritefalse
+
+\preamble
+
+EXPERIMENTAL CODE
+
+Do not distribute this file without also distributing the
+source files specified above.
+
+Do not distribute a modified version of this file.
+
+\endpreamble
+% stop docstrip adding \endinput
+\postamble
+\endpostamble
+
+\keepsilent
+
+\generate
+ {
+ \file{l3format.ltx}
+ {
+ \from{l3bootstrap.dtx} {initex}
+ \from{l3names.dtx} {initex}
+ \from{l3basics.dtx} {initex}
+ \from{l3expan.dtx} {initex}
+ \from{l3tl.dtx} {initex}
+ \from{l3seq.dtx} {initex}
+ % ===== ===FORMAT ONLY =========
+ \from{l3alloc.dtx} {initex}
+ % ==============================
+ \from{l3int.dtx} {initex}
+ \from{l3quark.dtx} {initex}
+ \from{l3prg.dtx} {initex}
+ \from{l3clist.dtx} {initex}
+ \from{l3token.dtx} {initex}
+ \from{l3prop.dtx} {initex}
+ \from{l3msg.dtx} {initex}
+ \from{l3file.dtx} {initex}
+ \from{l3skip.dtx} {initex}
+ \from{l3keys.dtx} {initex}
+ \from{l3fp.dtx} {initex}
+ \from{l3fp-aux.dtx} {initex}
+ \from{l3fp-traps.dtx} {initex}
+ \from{l3fp-round.dtx} {initex}
+ \from{l3fp-parse.dtx} {initex}
+ \from{l3fp-logic.dtx} {initex}
+ \from{l3fp-basics.dtx} {initex}
+ \from{l3fp-extended.dtx}{initex}
+ \from{l3fp-expo.dtx} {initex}
+ \from{l3fp-trig.dtx} {initex}
+ \from{l3fp-convert.dtx} {initex}
+ \from{l3fp-assign.dtx} {initex}
+ \from{l3fp-old.dtx} {initex}
+ \from{l3box.dtx} {initex}
+ \from{l3coffins.dtx} {initex}
+ \from{l3color.dtx} {initex}
+ \from{l3luatex.dtx} {initex}
+ \from{l3candidates.dtx} {initex}
+ % ======== FORMAT ONLY =========
+ \from{l3final.dtx} {initex}
+ % ==============================
+ }
+ }
+
+\generate{\file{l3dvips.ltx} {\from{l3drivers.dtx}{initex,dvips} }}
+\generate{\file{l3pdfmode.ltx} {\from{l3drivers.dtx}{initex,pdfmode} }}
+\generate{\file{l3xdvipdfmx.ltx}{\from{l3drivers.dtx}{initex,xdvipdfmx}}}
+
+\generate{\file{l3docstrip.tex}{\from{l3docstrip.dtx}{program}}}
+
+\endbatchfile \ No newline at end of file
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
index edbe34ee82c..6c7991c4027 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-logic.dtx
@@ -96,14 +96,8 @@
% \begin{macro}[pTF]{\fp_if_exist:N, \fp_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \fp_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \fp_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \fp_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \fp_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \fp_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \fp_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \fp_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \fp_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \fp_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \fp_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
index ceb2840a810..1e00baa38da 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp-traps.dtx
@@ -36,7 +36,7 @@
%
%<*driver>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp-traps.dtx 4179 2012-08-31 15:54:18Z bruno $
+\GetIdInfo$Id: l3fp-traps.dtx 4428 2013-01-10 13:23:29Z bruno $
{L3 Floating-point exception trapping}
\documentclass[full]{l3doc}
\begin{document}
@@ -91,7 +91,7 @@
% Function to turn a flag off. Simply undefine it.
% \begin{macrocode}
\cs_new_protected:Npn \fp_flag_off:n #1
- { \cs_set_eq:cN { l_@@_ #1 _flag_token } \c_undefined:D }
+ { \cs_set_eq:cN { l_@@_ #1 _flag_token } \tex_undefined:D }
% \end{macrocode}
% \end{macro}
%
@@ -128,10 +128,10 @@
% The \textsc{ieee} standard defines five exceptions. We currently
% don't support the \enquote{inexact} exception.
% \begin{macrocode}
-\cs_new_eq:NN \l_@@_invalid_operation_flag_token \c_undefined:D
-\cs_new_eq:NN \l_@@_division_by_zero_flag_token \c_undefined:D
-\cs_new_eq:NN \l_@@_overflow_flag_token \c_undefined:D
-\cs_new_eq:NN \l_@@_underflow_flag_token \c_undefined:D
+\cs_new_eq:NN \l_@@_invalid_operation_flag_token \tex_undefined:D
+\cs_new_eq:NN \l_@@_division_by_zero_flag_token \tex_undefined:D
+\cs_new_eq:NN \l_@@_overflow_flag_token \tex_undefined:D
+\cs_new_eq:NN \l_@@_underflow_flag_token \tex_undefined:D
% \end{macrocode}
% \end{variable}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
index e531e62e54e..09efdfdd58f 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3fp.dtx
@@ -36,7 +36,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3fp.dtx 4305 2012-11-10 08:40:25Z joseph $
+\GetIdInfo$Id: l3fp.dtx 4449 2013-01-19 23:55:05Z bruno $
{L3 Floating points}
%</driver|package>
%<*driver>
@@ -362,16 +362,18 @@
% case occurs exactly when one of the operands is \nan{}, and
% this relations is denoted by the symbol |?|. The \texttt{nNn}
% functions support the \meta{relations} |<|, |=|, |>|, and |?|. The
-% \texttt{n} functions support as a \meta{relation} any combination of
-% those four symbols, plus an optional leading |!| (which negates the
+% \texttt{n} functions support as a \meta{relation} any non-empty string of
+% those four symbols, plus optional leading |!| (which negate the
% \meta{relation}), with the restriction that the \meta{relation} may
% not start with |?|. Common choices of \meta{relation} include |>=|
% (greater or equal), |!=| (not equal), |!?| (comparable). Note that
% a \nan{} is distinct from any value, even another
-% \nan{}, hence $x=x$ is not true for a \nan{}. Thus to
-% test if a value is \nan{}, use
+% \nan{}, hence $x=x$ is not true for a \nan{}.
+% Since a \nan{} is not comparable to any floating point, to test if a
+% value is \nan{}, one can use the following, where~$0$ is an
+% arbitrary floating point.
% \begin{verbatim}
-% \fp_compare:nNnTF { <value> } != { <value> }
+% \fp_compare:nNnTF { <value> } ? { 0 }
% { } % <value> is nan
% { } % <value> is not nan
% \end{verbatim}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
index e67616a2f7d..dcea709ebbc 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3int.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3int.dtx Copyright (C) 1990-2012 The LaTeX3 Project
+%% File: l3int.dtx Copyright (C) 1990-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3int.dtx 4237 2012-09-26 10:18:58Z bruno $
+\GetIdInfo$Id: l3int.dtx 4444 2013-01-13 20:27:20Z bruno $
{L3 Integers}
%</driver|package>
%<*driver>
@@ -300,16 +300,36 @@
% \end{center}
% \end{function}
%
-% \begin{function}[EXP,pTF]{\int_compare:n}
+% \begin{function}[updated = 2013-01-13, EXP, pTF]{\int_compare:n}
% \begin{syntax}
-% \cs{int_compare_p:n} \{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \\
+% \cs{int_compare_p:n} \\
+% ~~\{ \\
+% ~~~~\meta{intexpr_1} \meta{relation_1} \\
+% ~~~~\ldots{} \\
+% ~~~~\meta{intexpr_N} \meta{relation_N} \\
+% ~~~~\meta{intexpr_{N+1}} \\
+% ~~\} \\
% \cs{int_compare:nTF}
-% ~~\{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \}
+% ~~\{ \\
+% ~~~~\meta{intexpr_1} \meta{relation_1} \\
+% ~~~~\ldots{} \\
+% ~~~~\meta{intexpr_N} \meta{relation_N} \\
+% ~~~~\meta{intexpr_{N+1}} \\
+% ~~\} \\
% ~~\Arg{true code} \Arg{false code}
% \end{syntax}
-% This function first evaluates each of the \meta{integer expressions}
-% as described for \cs{int_eval:n}. The two results are then
-% compared using the \meta{relation}:
+% This function evaluates the \meta{integer expressions} as described
+% for \cs{int_eval:n} and compares consecutive result using the
+% corresponding \meta{relation}, namely it compares \meta{intexpr_1}
+% and \meta{intexpr_2} using the \meta{relation_1}, then
+% \meta{intexpr_2} and \meta{intexpr_3} using the \meta{relation_2},
+% until finally comparing \meta{intexpr_N} and \meta{intexpr_{N+1}}
+% using the \meta{relation_N}. The test yields \texttt{true} if all
+% comparisons are \texttt{true}. Each \meta{integer expression} is
+% evaluated only once, and the evaluation is lazy, in the sense that
+% if one comparison is \texttt{false}, then no other \meta{integer
+% expression} is evaluated and no other comparison is performed.
+% The \meta{relations} can be any of the following:
% \begin{center}
% \begin{tabular}{ll}
% Equal & |=| or |==| \\
@@ -413,35 +433,35 @@
% \texttt{false}.
% \end{function}
%
-% \begin{function}[rEXP]{\int_do_until:nn}
+% \begin{function}[updated = 2013-01-13, rEXP]{\int_do_until:nn}
% \begin{syntax}
-% \cs{int_do_until:nn} \{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \Arg{code}
+% \cs{int_do_until:nn} \Arg{integer relation} \Arg{code}
% \end{syntax}
% Places the \meta{code} in the input stream for \TeX{} to process, and
-% then evaluates the relationship between the two
-% \meta{integer expressions} as described for \cs{int_compare:nTF}.
+% then evaluates the \meta{integer relation}
+% as described for \cs{int_compare:nTF}.
% If the test is \texttt{false} then the \meta{code} will be inserted
% into the input stream again and a loop will occur until the
% \meta{relation} is \texttt{true}.
% \end{function}
%
-% \begin{function}[rEXP]{\int_do_while:nn}
+% \begin{function}[updated = 2013-01-13, rEXP]{\int_do_while:nn}
% \begin{syntax}
-% \cs{int_do_while:nn} \{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \Arg{code}
+% \cs{int_do_while:nn} \Arg{integer relation} \Arg{code}
% \end{syntax}
% Places the \meta{code} in the input stream for \TeX{} to process, and
-% then evaluates the relationship between the two
-% \meta{integer expressions} as described for \cs{int_compare:nTF}.
+% then evaluates the \meta{integer relation}
+% as described for \cs{int_compare:nTF}.
% If the test is \texttt{true} then the \meta{code} will be inserted
% into the input stream again and a loop will occur until the
% \meta{relation} is \texttt{false}.
% \end{function}
%
-% \begin{function}[rEXP]{\int_until_do:nn}
+% \begin{function}[updated = 2013-01-13, rEXP]{\int_until_do:nn}
% \begin{syntax}
-% \cs{int_until_do:nn} \{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \Arg{code}
+% \cs{int_until_do:nn} \Arg{integer_relation} \Arg{code}
% \end{syntax}
-% Evaluates the relationship between the two \meta{integer expressions}
+% Evaluates the \meta{integer relation}
% as described for \cs{int_compare:nTF}, and then places the
% \meta{code} in the input stream if the \meta{relation} is
% \texttt{false}. After the \meta{code} has been processed by \TeX{} the
@@ -449,11 +469,11 @@
% \texttt{true}.
% \end{function}
%
-% \begin{function}[rEXP]{\int_while_do:nn}
+% \begin{function}[updated = 2013-01-13, rEXP]{\int_while_do:nn}
% \begin{syntax}
-% \cs{int_while_do:nn} \{ \meta{intexpr_1} \meta{relation} \meta{intexpr_2} \} \Arg{code}
+% \cs{int_while_do:nn} \Arg{integer relation} \Arg{code}
% \end{syntax}
-% Evaluates the relationship between the two \meta{integer expressions}
+% Evaluates the \meta{integer relation}
% as described for \cs{int_compare:nTF}, and then places the
% \meta{code} in the input stream if the \meta{relation} is
% \texttt{true}. After the \meta{code} has been processed by \TeX{} the
@@ -591,7 +611,7 @@
%
% \begin{function}[updated = 2011-09-17, EXP]{\int_to_hexadecimal:n}
% \begin{syntax}
-% \cs{int_to_binary:n} \Arg{integer expression}
+% \cs{int_to_hexadecimal:n} \Arg{integer expression}
% \end{syntax}
% Calculates the value of the \meta{integer expression} and places
% the hexadecimal (base~$16$) representation of the result in the
@@ -1167,14 +1187,8 @@
% \begin{macro}[pTF]{\int_if_exist:N, \int_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \int_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \int_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \int_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \int_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \int_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \int_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \int_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \int_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \int_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \int_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
@@ -1288,8 +1302,10 @@
\__prg_compare_error:
}
\cs_new:Npn \__prg_compare_error:Nw
- #1#2 \prg_return_true: \else: \prg_return_false: \fi:
+ #1#2 \q_stop
{
+ { }
+ \c_zero \fi:
\__msg_kernel_expandable_error:nnn
{ kernel } { unknown-comparison } {#1}
\prg_return_false:
@@ -1298,9 +1314,11 @@
% \end{macro}
%
% \begin{macro}[pTF, EXP]{\int_compare:n}
-% \begin{macro}[aux, EXP]{\@@_compare_aux:Nw, \@@_compare_aux:NNw}
+% \begin{macro}[aux, EXP]
+% {\@@_compare:w, \@@_compare:Nw, \@@_compare:NNw, \@@_compare:nnN}
% \begin{macro}[aux, EXP]
% {
+% \@@_compare_end_=:NNw,
% \@@_compare_=:NNw,
% \@@_compare_<:NNw,
% \@@_compare_>:NNw,
@@ -1310,67 +1328,122 @@
% \@@_compare_>=:NNw
% }
% Comparison tests using a simple syntax where only one set of braces
-% is required and additional operators such as |!=| and |>=| are
-% supported. We can start evaluating from the left using
-% \cs{@@_eval:w}, and we know that since the relation symbols |<|,
-% |>|, |=| and |!| are not allowed in such expressions, they will
-% terminate the expression. Therefore, we first let \TeX{} evaluate
-% this left hand side of the (in)equality. We also insert at that
-% stage the end of the test: \cs{@@_eval_end:} will end the
-% evaluation of the right-hand side.
+% is required, additional operators such as |!=| and |>=| are
+% supported, and multiple comparisons can be performed at once, for
+% instance |0 < 5 <= 1|. The idea is to loop through the argument,
+% finding one operand at a time, and comparing it to the previous one.
+% The looping auxiliary \cs{@@_compare:Nw} reads one \meta{operand}
+% and one \meta{comparison} symbol, and leaves roughly
+% \begin{quote}
+% \meta{operand} \cs{prg_return_false:} \cs{fi:} \\
+% \cs{reverse_if:N} \cs{if_int_compare:w} \meta{operand} \meta{comparison} \\
+% \cs{@@_compare:Nw}
+% \end{quote}
+% in the input stream. Each call to this auxiliary provides the
+% second operand of the last call's \cs{if_int_compare:w}. If one of
+% the \meta{comparisons} is \texttt{false}, the \texttt{true} branch
+% of the \TeX{} conditional is taken (because of \cs{reverse_if:N}),
+% immediately returning \texttt{false} as the result of the test.
+% There is no \TeX{} conditional waiting the first operand, so we add
+% an \cs{if_false:} and expand by hand with \cs{@@_value:w}, thus
+% skipping \cs{prg_return_false:} on the first iteration.
+%
+% Before starting the loop, the first step is to make sure that there
+% is at least one relation symbol. We first let \TeX{} evaluate this
+% left hand side of the (in)equality using \cs{@@_eval:w}. Since the
+% relation symbols |<|, |>|, |=| and |!| are not allowed in integer
+% expressions, they will terminate it. If the argument contains no
+% relation symbol, \cs{__prg_compare_error:} is expanded,
+% inserting~|=| and itself after an error. In all cases,
+% \cs{@@_compare:w} receives as its argument an integer, a relation
+% symbol, and some more tokens. We then setup the loop, which will be
+% ended by the two odd-looking items |e| and |{=nd_}|, with a trailing
+% \cs{q_stop} used to grab the entire argument when necessary.
% \begin{macrocode}
\prg_new_conditional:Npnn \int_compare:n #1 { p , T , F , TF }
{
- \exp_after:wN \@@_compare_aux:Nw \int_use:N \@@_eval:w #1
- \__prg_compare_error: \@@_eval_end:
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
+ \exp_after:wN \@@_compare:w
+ \int_use:N \@@_eval:w #1 \__prg_compare_error:
+ }
+\cs_new:Npn \@@_compare:w #1 \__prg_compare_error:
+ {
+ \exp_after:wN \if_false: \@@_value:w
+ \@@_compare:Nw #1 e { = nd_ } \q_stop
}
% \end{macrocode}
-% We have just evaluated the left-hand side. To access the relation
-% symbol, we remove the number by applying \cs{@@_to_roman:w}, after
-% making sure that the argument becomes non-positive: its roman
-% numeral representation is then empty. The \cs{@@_compare_aux:NNw}
-% auxiliary then probes the first two tokens to determine the relation
-% symbol, building a control sequence from it. All the extended forms
-% have an extra |=| hence the test for that as a second token. If the
-% relation symbol is unknown, then the control sequence is turned by
-% \TeX{} into \cs{scan_stop:}, and \cs{__prg_compare_error:Nw}
-% raises an error.
+% The goal here is to find an \meta{operand} and a \meta{comparison}.
+% The \meta{operand} is already evaluated, but we cannot yet grab it
+% as an argument. To access the following relation symbol, we remove
+% the number by applying \cs{@@_to_roman:w}, after making sure that
+% the argument becomes non-positive: its roman numeral representation
+% is then empty. Then probe the first two tokens with
+% \cs{@@_compare:NNw} to determine the relation symbol, building a
+% control sequence from it. All the extended forms have an extra |=|
+% hence the test for that as a second token. If the relation symbol
+% is unknown, then the control sequence is turned by \TeX{} into
+% \cs{scan_stop:}, ignored thanks to \tn{unexpanded}, and
+% \cs{__prg_compare_error:Nw} raises an error.
% \begin{macrocode}
-\cs_new:Npn \@@_compare_aux:Nw #1#2 \__prg_compare_error:
+\cs_new:Npn \@@_compare:Nw #1#2 \q_stop
{
- \exp_after:wN \@@_compare_aux:NNw
- \@@_to_roman:w - 0 #2 ?? \q_mark
- #1#2
+ \exp_after:wN \@@_compare:NNw
+ \@@_to_roman:w - 0 #2 \q_mark
+ #1#2 \q_stop
}
-\cs_new:Npn \@@_compare_aux:NNw #1#2#3 \q_mark
+\cs_new:Npn \@@_compare:NNw #1#2#3 \q_mark
{
+ \etex_unexpanded:D
\use:c { @@_compare_ #1 \if_meaning:w = #2 = \fi: :NNw }
\__prg_compare_error:Nw #1
}
% \end{macrocode}
+% When the last \meta{operand} is seen, \cs{@@_compare:NNw} receives
+% |e| and |=nd_| as arguments, hence calling
+% \cs{@@_compare_end_=:NNw} to end the loop: return the result of the
+% last comparison (involving the operand that we just found). When a
+% normal relation is found, the appropriate auxiliary calls
+% \cs{@@_compare:nnN} where |#1| is \cs{if_int_compare:w} or
+% \cs{reverse_if:N} \cs{if_int_compare:w}, |#2| is the \meta{operand},
+% and |#3| is one of |<|, |=|, or~|>|. As announced earlier, we leave
+% the \meta{operand} for the previous conditional. If this
+% conditional is true the result of the test is known, so we remove
+% all tokens and return \texttt{false}. Otherwise, we apply the
+% conditional |#1| to the \meta{operand} |#2| and the comparison |#3|,
+% and call \cs{@@_compare:Nw} to look for additional operands, after
+% evaluating the following expression.
+% \begin{macrocode}
+\cs_new:cpn { @@_compare_end_=:NNw } #1#2#3 e #4 \q_stop
+ {
+ {#3} \exp_stop_f:
+ \prg_return_false: \else: \prg_return_true: \fi:
+ }
+\cs_new:Npn \@@_compare:nnN #1#2#3
+ {
+ {#2} \exp_stop_f:
+ \prg_return_false: \exp_after:wN \use_none_delimit_by_q_stop:w
+ \fi:
+ #1 #2 #3 \exp_after:wN \@@_compare:Nw \@@_value:w \@@_eval:w
+ }
+% \end{macrocode}
% The actual comparisons are then simple function calls, using the
% relation as delimiter for a delimited argument and discarding
% \cs{__prg_compare_error:Nw} \meta{token} responsible for error
% detection.
% \begin{macrocode}
\cs_new:cpn { @@_compare_=:NNw } #1#2#3 =
- { \if_int_compare:w #3 = \@@_eval:w }
+ { \@@_compare:nnN { \reverse_if:N \if_int_compare:w } {#3} = }
\cs_new:cpn { @@_compare_<:NNw } #1#2#3 <
- { \if_int_compare:w #3 < \@@_eval:w }
+ { \@@_compare:nnN { \reverse_if:N \if_int_compare:w } {#3} < }
\cs_new:cpn { @@_compare_>:NNw } #1#2#3 >
- { \if_int_compare:w #3 > \@@_eval:w }
+ { \@@_compare:nnN { \reverse_if:N \if_int_compare:w } {#3} > }
\cs_new:cpn { @@_compare_==:NNw } #1#2#3 ==
- { \if_int_compare:w #3 = \@@_eval:w }
+ { \@@_compare:nnN { \reverse_if:N \if_int_compare:w } {#3} = }
\cs_new:cpn { @@_compare_!=:NNw } #1#2#3 !=
- { \reverse_if:N \if_int_compare:w #3 = \@@_eval:w }
+ { \@@_compare:nnN { \if_int_compare:w } {#3} = }
\cs_new:cpn { @@_compare_<=:NNw } #1#2#3 <=
- { \reverse_if:N \if_int_compare:w #3 > \@@_eval:w }
+ { \@@_compare:nnN { \if_int_compare:w } {#3} > }
\cs_new:cpn { @@_compare_>=:NNw } #1#2#3 >=
- { \reverse_if:N \if_int_compare:w #3 < \@@_eval:w }
+ { \@@_compare:nnN { \if_int_compare:w } {#3} < }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2335,29 +2408,37 @@
% \begin{macro}{\if_num:w}
% Deprecated 2012-05-30 for removal after 2012-11-30.
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \if_num:w \if_int_compare:w
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
% \begin{variable}{\l_tmpc_int}
% Deprecated 2012-07-04 for removal after 2012-12-31.
% \begin{macrocode}
+%<*deprecated>
\int_new:N \l_tmpc_int
+%</deprecated>
% \end{macrocode}
% \end{variable}
%
% \begin{macro}{\int_eval:w, \int_eval_end:}
% Deprecated 2012-07-13 for removal after 2012-12-31.
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \int_eval:w \@@_eval:w
\cs_new_eq:NN \int_eval_end: \@@_eval_end:
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\int_value:w}
% Deprecated 2012-07-14 for removal after 2012-12-31.
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \int_value:w \@@_value:w
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
index b6a4cafb577..3d38853224a 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3keys.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3keys.dtx Copyright (C) 2006-2012 The LaTeX3 Project
+%% File: l3keys.dtx Copyright (C) 2006-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3keys.dtx 4256 2012-11-02 08:47:41Z joseph $
+\GetIdInfo$Id: l3keys.dtx 4461 2013-02-24 18:55:17Z joseph $
{L3 Experimental key-value interfaces}
%</driver|package>
%<*driver>
@@ -863,8 +863,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_split_key:n #1
{
- \str_if_eq_x:nnTF
- { \exp_not:N \q_nil } { \exp_not:o { \use_none:nnn #1 \q_nil \q_nil } }
+ \quark_if_nil:oTF { \use_none:nnn #1 \q_nil \q_nil }
{ \tl_set:Nx \l_@@_key_tl { \exp_not:o { \use_ii:nnn #1 \q_nil } } }
{ \@@_split_key:w #1 \q_stop }
}
@@ -1977,7 +1976,9 @@
% Internal material for removal by 2012-12-31.
%
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \c_keys_code_root_tl \c__keys_code_root_tl
+%</deprecated>
% \end{macrocode}
%
% \begin{macrocode}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx
index 3d72db5db51..9a10e278f2d 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3msg.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3msg.dtx Copyright (C) 2009-2012 The LaTeX3 Project
+%% File: l3msg.dtx Copyright (C) 2009-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3msg.dtx 4212 2012-09-09 12:24:04Z bruno $
+\GetIdInfo$Id: l3msg.dtx 4412 2013-01-08 12:23:19Z joseph $
{L3 Messages}
%</driver|package>
%<*driver>
@@ -2206,8 +2206,10 @@
% \begin{macro}{\msg_newline:, \msg_two_newlines:}
% New lines are printed in the same way as for low-level file writing.
% \begin{macrocode}
+%<*deprecated>
\cs_new_nopar:Npn \msg_newline: { ^^J }
\cs_new_nopar:Npn \msg_two_newlines: { ^^J ^^J }
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -2215,9 +2217,11 @@
% \begin{macro}{\msg_interrupt:xxx}
% These were all misnamed.
% \begin{macrocode}
+%<*deprecated>
\cs_generate_variant:Nn \msg_log:n { x }
\cs_generate_variant:Nn \msg_term:n { x }
\cs_generate_variant:Nn \msg_interrupt:nnn { xxx }
+%</deprecated>
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2229,6 +2233,7 @@
% is cleared, and the various message functions are created
% to simply use the code stored for the message.
% \begin{macrocode}
+%<*deprecated>
\cs_new_protected:Npn \msg_class_set:nn #1#2
{
\cs_if_exist:cTF { @@_ #1 _code:nnnnnn }
@@ -2247,6 +2252,7 @@
\cs_set_protected:cpx { msg_ #1 :nn } ##1##2
{ \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} { } { } { } { } }
}
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
index 54db54f0f58..79fa7961ebd 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3prg.dtx Copyright (C) 2005-2012 The LaTeX3 Project
+%% File: l3prg.dtx Copyright (C) 2005-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3prg.dtx 4339 2012-11-24 19:16:43Z joseph $
+\GetIdInfo$Id: l3prg.dtx 4459 2013-02-13 09:21:15Z will $
{L3 Control structures}
%</driver|package>
%<*driver>
@@ -183,8 +183,8 @@
% |\foo_if_bar:NNT| but not |\foo_if_bar:NNF| (because |F| is missing
% from the \meta{conditions} list). The return statements take care of
% resolving the remaining \cs{else:} and \cs{fi:} before returning the
-% state. There must be a return statement for each branch, failing to do
-% so will result in an error if that branch is executed.
+% state. There must be a return statement for each branch; failing to do
+% so will result in erroneous output if that branch is executed.
%
% \begin{function}{\prg_new_eq_conditional:NNn, \prg_set_eq_conditional:NNn}
% \begin{syntax}
@@ -203,9 +203,18 @@
% \cs{prg_return_true:}
% \cs{prg_return_false:}
% \end{syntax}
-% These functions define the logical state at the end of a conditional.
-% As such, they should appear within the code for a conditional
-% statement generated by \cs{prg_set_conditional:Npnn}, \emph{etc}.
+% These `return' functions define the logical state of a conditional statement.
+% They appear within the code for a conditional
+% function generated by \cs{prg_set_conditional:Npnn}, \emph{etc}, to indicate
+% when a true or false branch has been taken.
+% While they may appear multiple times each within the code of such conditionals,
+% the execution of the conditional must result in the expansion of one of these
+% two functions \emph{exactly once}.
+%
+% The return functions trigger what is internally an f-expansion process to complete
+% the evaluation of the conditional. Therefore, after \cs{prg_return_true:} or \cs{prg_return_false:}
+% there must be no non-expandable material in the input stream for the remainder of
+% the expansion of the conditional code. This includes other instances of either of these functions.
% \end{function}
%
% \section{The boolean data type}
@@ -870,14 +879,8 @@
% \begin{macro}[pTF]{\bool_if_exist:N, \bool_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \bool_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \bool_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \bool_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \bool_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \bool_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \bool_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \bool_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \bool_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \bool_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \bool_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
@@ -1817,12 +1820,14 @@
% }
% Moved to more sensible modules.
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \prg_case_int:nnn \int_case:nnn
\cs_new_eq:NN \prg_case_str:nnn \str_case:nnn
\cs_new_eq:NN \prg_case_str:onn \str_case:onn
\cs_new_eq:NN \prg_case_str:xxn \str_case_x:nnn
\cs_new_eq:NN \prg_case_tl:Nnn \tl_case:Nnn
\cs_new_eq:NN \prg_case_tl:cnn \tl_case:cnn
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -1834,9 +1839,11 @@
% \prg_stepwise_variable:nnnNn
% }
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \prg_stepwise_function:nnnN \int_step_function:nnnN
\cs_new_eq:NN \prg_stepwise_inline:nnnn \int_step_inline:nnnn
\cs_new_eq:NN \prg_stepwise_variable:nnnNn \int_step_variable:nnnNn
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
index d8bec5ee50d..3046ae59e8b 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3prop.dtx Copyright (C) 1990-2012 The LaTeX3 Project
+%% File: l3prop.dtx Copyright (C) 1990-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3prop.dtx 4212 2012-09-09 12:24:04Z bruno $
+\GetIdInfo$Id: l3prop.dtx 4423 2013-01-09 00:05:30Z bruno $
{L3 Property lists}
%</driver|package>
%<*driver>
@@ -245,7 +245,7 @@
% check that the \meta{property list} really is a property list variable.
% \end{function}
%
-% \begin{function}[EXP,pTF]{\prop_if_empty:N, \prop_if_empty:c}
+% \begin{function}[EXP, pTF]{\prop_if_empty:N, \prop_if_empty:c}
% \begin{syntax}
% \cs{prop_if_empty_p:N} \meta{property list}
% \cs{prop_if_empty:NTF} \meta{property list} \Arg{true code} \Arg{false code}
@@ -331,7 +331,7 @@
%
% \section{Mapping to property lists}
%
-% \begin{function}[updated = 2012-06-29, rEXP]
+% \begin{function}[updated = 2013-01-08, rEXP]
% {\prop_map_function:NN, \prop_map_function:cN}
% \begin{syntax}
% \cs{prop_map_function:NN} \meta{property list} \meta{function}
@@ -343,7 +343,7 @@
% should not be relied upon.
% \end{function}
%
-% \begin{function}[updated = 2012-06-29]
+% \begin{function}[updated = 2013-01-08]
% {\prop_map_inline:Nn, \prop_map_inline:cn}
% \begin{syntax}
% \cs{prop_map_inline:Nn} \meta{property list} \Arg{inline function}
@@ -432,29 +432,39 @@
%
% \section{Internal property list functions}
%
-% \begin{variable}{\q__prop}
-% The internal token used to separate out property list entries, separating
-% both the \meta{key} from the \meta{value} and also one entry from another.
+% \begin{variable}{\s__prop}
+% The internal token used to separate out property list entries,
+% surrounding each \meta{key}.
% \end{variable}
%
-% \begin{function}{\__prop_split:NnTF}
+% \begin{variable}{\l__prop_internal_tl}
+% Token list used to store new key--value pairs to be inserted by
+% functions of the \cs{prop_put:Nnn} family.
+% \end{variable}
+%
+% \begin{function}[updated = 2013-01-08]{\__prop_split:NnTF}
% \begin{syntax}
% \cs{__prop_split:NnTF} \meta{property list} \Arg{key} \Arg{true code} \Arg{false code}
% \end{syntax}
% Splits the \meta{property list} at the \meta{key}, giving three
-% groups: the \meta{extract} of \meta{property list} before the
+% token lists: the \meta{extract} of \meta{property list} before the
% \meta{key}, the \meta{value} associated with the \meta{key} and the
% \meta{extract} of the \meta{property list} after the \meta{value}.
-% The first \meta{extract} retains the internal structure of a property
-% list. The second is only missing the leading separator \cs{q__prop}.
-% This ensures that the concatenation of the two \meta{extracts} is a
+% Both \meta{extracts} retain the internal structure of a property
+% list, and the concatenation of the two \meta{extracts} is a
% property list.
% If the \meta{key} is present in the \meta{property list} then the
-% \meta{true code} is left in the input stream, followed by the three
-% groups: thus the \meta{true code} should properly absorb three arguments.
+% \meta{true code} is left in the input stream, with |#1|, |#2|, and
+% |#3| replaced by the first \meta{extract}, the \meta{value}, and the
+% second extract.
% If the \meta{key} is not present in the \meta{property list} then
% the \meta{false code} is left in the input stream, with no trailing
% material.
+% Both \meta{true code} and \meta{false code} are used in the
+% replacement text of a macro defined internally, hence macro
+% parameter characters should be doubled, except |#1|, |#2|, and |#3|
+% which stand in the \meta{true code} for the three extracts from the
+% property list.
% The \meta{key} comparison takes place as described for \cs{str_if_eq:nn}.
% \end{function}
%
@@ -484,47 +494,51 @@
%
% A property list is a macro whose top-level expansion is for the form
% \begin{quote}
-% \cs{q_@@} \meta{key_1} \cs{q_@@} \Arg{value_1} \\
+% \cs{s_@@} \meta{key_1} \cs{s_@@} \Arg{value_1} \\
% \ldots{} \\
-% \cs{q_@@} \meta{key_n} \cs{q_@@} \Arg{value_n} \\
-% \cs{q_@@}
+% \cs{s_@@} \meta{key_n} \cs{s_@@} \Arg{value_n} \\
% \end{quote}
-% where the trailing \cs{q_@@} is always present for performance
-% reasons: this means that empty property lists are not actually empty.
%
-% \begin{macro}[int]{\q_@@}
-% A private quark is used as a marker between entries.
+% \begin{macro}[int]{\s_@@}
+% A private scan mark is used as a marker surrounding each key.
% \begin{macrocode}
-\quark_new:N \q_@@
+\__scan_new:N \s_@@
% \end{macrocode}
% \end{macro}
%
+% \begin{variable}{\l_@@_internal_tl}
+% Token list used to store the new key--value pair inserted by
+% \cs{prop_put:Nnn} and friends.
+% \begin{macrocode}
+\tl_new:N \l_@@_internal_tl
+% \end{macrocode}
+% \end{variable}
+%
% \begin{variable}[tested = m3prop004]{\c_empty_prop}
-% An empty prop contains exactly one \cs{q_@@}.
+% An empty prop is an empty token list.
% \begin{macrocode}
-\tl_const:Nn \c_empty_prop { \q_@@ }
+\cs_new_eq:NN \c_empty_prop \c_empty_tl
% \end{macrocode}
% \end{variable}
%
% \subsection{Allocation and initialisation}
%
-% \begin{macro}[tested = m3prop001]{\prop_new:N,\prop_new:c}
-% Internally, property lists are token lists, but an empty prop
-% is not an empty tl, so we need to do things by hand.
+% \begin{macro}[tested = m3prop001]{\prop_new:N, \prop_new:c}
+% Internally, property lists are just token lists.
% \begin{macrocode}
-\cs_new_protected:Npn \prop_new:N #1 { \cs_new_eq:NN #1 \c_empty_prop }
-\cs_new_protected:Npn \prop_new:c #1 { \cs_new_eq:cN {#1} \c_empty_prop }
+\cs_new_eq:NN \prop_new:N \tl_new:N
+\cs_new_eq:NN \prop_new:c \tl_new:c
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[tested = m3prop001]{\prop_clear:N, \prop_clear:c}
% \begin{macro}[tested = m3prop001]{\prop_gclear:N, \prop_gclear:c}
-% The same idea for clearing
+% The same idea for clearing.
% \begin{macrocode}
-\cs_new_protected:Npn \prop_clear:N #1 { \cs_set_eq:NN #1 \c_empty_prop }
-\cs_generate_variant:Nn \prop_clear:N { c }
-\cs_new_protected:Npn \prop_gclear:N #1 { \cs_gset_eq:NN #1 \c_empty_prop }
-\cs_generate_variant:Nn \prop_gclear:N { c }
+\cs_new_eq:NN \prop_clear:N \tl_clear:N
+\cs_new_eq:NN \prop_clear:c \tl_clear:c
+\cs_new_eq:NN \prop_gclear:N \tl_gclear:N
+\cs_new_eq:NN \prop_gclear:c \tl_gclear:c
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -533,12 +547,10 @@
% \begin{macro}[tested = m3prop001]{\prop_gclear_new:N, \prop_gclear_new:c}
% Once again a simple copy from the token list functions.
% \begin{macrocode}
-\cs_new_protected:Npn \prop_clear_new:N #1
- { \prop_if_exist:NTF #1 { \prop_clear:N #1 } { \prop_new:N #1 } }
-\cs_generate_variant:Nn \prop_clear_new:N { c }
-\cs_new_protected:Npn \prop_gclear_new:N #1
- { \prop_if_exist:NTF #1 { \prop_gclear:N #1 } { \prop_new:N #1 } }
-\cs_generate_variant:Nn \prop_gclear_new:N { c }
+\cs_new_eq:NN \prop_clear_new:N \tl_clear_new:N
+\cs_new_eq:NN \prop_clear_new:c \tl_clear_new:c
+\cs_new_eq:NN \prop_gclear_new:N \tl_gclear_new:N
+\cs_new_eq:NN \prop_gclear_new:c \tl_gclear_new:c
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -577,67 +589,69 @@
%
% \begin{macro}[int]{\@@_split:NnTF}
% \begin{macro}[aux]{\@@_split_aux:NnTF}
-% \begin{macro}[aux]{\@@_split_aux:nnnn}
-% \begin{macro}[aux]{\@@_split_aux:w}
+% \begin{macro}[aux, EXP]{\@@_split_aux:w}
% This function is used by most of the module, and hence must be fast.
-% The aim here is to split a property list at a given key into the part
-% before the key--value pair, the value associated with the key and the part
-% after the key--value pair. To do this, the key is first detokenized (to
-% avoid repeatedly doing this), then a delimited function is constructed to
-% match the key. It will match \cs{q_@@} \meta{detokenized key} \cs{q_@@}
-% \Arg{value} \meta{extra argument}, effectively separating an
-% \meta{extract_1} before the key in the property list and an \meta{extract_2}
-% after the key.
-%
-% If the key is present in the property list, then \meta{extra argument}
-% is simply \cs{q_@@}, and \cs{@@_split_aux:nnnn} will gobble this
-% and the false branch (|#4|), leaving the correct code on the input
-% stream. More precisely, it leaves the user code (true branch), followed
-% by three groups, \Arg{extract_1} \Arg{value} \Arg{extract_2}.
-% In order for \meta{extract_1}\meta{extract_2} to be a well-formed
-% property list, \meta{extract_1} has a leading and trailing \cs{q_@@},
-% retaining exactly the structure of a property list, while \meta{extract_2}
-% omits the leading \cs{q_@@}.
-%
-% If the key is not there, then \meta{extra argument} is |?|
-% \cs{use_ii:nn} |{ }|, and \cs{@@_split_aux:nnnn} |?| \cs{use_ii:nn}
-% |{ }| removes the three brace groups that just follow. Then
-% \cs{use_ii:nn} removes the true branch, leaving the false branch,
-% with no trailing material.
+% It receives a \meta{property list}, a \meta{key}, a \meta{true code}
+% and a \meta{false code}. The aim is to split the \meta{property
+% list} at the given \meta{key} into the \meta{extract_1} before the
+% key--value pair, the \meta{value} associated with the \meta{key} and
+% the \meta{extract_2} after the key--value pair. This is done using
+% a delimited function, whose definition is as follows, where the
+% \meta{key} is turned into a string.
+% \begin{quote}
+% \cs{cs_set:Npn} \cs{@@_split_aux:w} |#1| \\
+% \quad \cs{s_@@} \meta{key} \cs{s_@@} |#2| \\
+% \quad |#3| \cs{q_mark} |#4| |#5| \cs{q_stop} \\
+% \quad |{| |#4| \Arg{true code} \Arg{false code} |}|
+% \end{quote}
+%
+% If the \meta{key} is present in the property list,
+% \cs{@@_split_aux:w}'s |#1| is the part before the \meta{key}, |#2|
+% is the \meta{value}, |#3| is the part after the \meta{key}, |#4| is
+% \cs{use_i:nn}, and |#5| is additional tokens that we do not care
+% about. The \meta{true code} is left in the input stream, and can
+% use the parameters |#1|, |#2|, |#3| for the three parts of the
+% property list as desired.
+%
+% If the \meta{key} is not there, then the \meta{function} is
+% \cs{use_ii:nn}, which keeps the \meta{false code}.
% \begin{macrocode}
\cs_new_protected:Npn \@@_split:NnTF #1#2
{ \exp_args:NNo \@@_split_aux:NnTF #1 { \tl_to_str:n {#2} } }
-\cs_new_protected:Npn \@@_split_aux:NnTF #1#2
+\cs_new_protected:Npn \@@_split_aux:NnTF #1#2#3#4
{
- \cs_set_protected:Npn \@@_split_aux:w
- ##1 \q_@@ #2 \q_@@ ##2 ##3 ##4 \q_mark ##5 \q_stop
- { \@@_split_aux:nnnn ##3 { {##1 \q_@@ } {##2} {##4} } }
- \exp_after:wN \@@_split_aux:w #1 \q_mark
- \q_@@ #2 \q_@@ { } { ? \use_ii:nn { } } \q_mark \q_stop
+ \cs_set:Npn \@@_split_aux:w ##1
+ \s_@@ #2 \s_@@ ##2 ##3 \q_mark ##4 ##5 \q_stop
+ { ##4 {#3} {#4} }
+ \exp_after:wN \@@_split_aux:w #1 \q_mark \use_i:nn
+ \s_@@ #2 \s_@@ { } \q_mark \use_ii:nn \q_stop
}
-\cs_new:Npn \@@_split_aux:nnnn #1#2#3#4 { #3 #2 }
-\cs_new_protected:Npn \@@_split_aux:w { }
+\cs_new:Npn \@@_split_aux:w { }
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[tested = m3prop002]
% {\prop_remove:Nn, \prop_remove:NV, \prop_remove:cn, \prop_remove:cV}
% \begin{macro}[tested = m3prop002]
% {\prop_gremove:Nn, \prop_gremove:NV, \prop_gremove:cn, \prop_gremove:cV}
-% \begin{macro}[aux]{\@@_remove:NNnnn}
% Deleting from a property starts by splitting the list.
% If the key is present in the property list, the returned value is ignored.
% If the key is missing, nothing happens.
% \begin{macrocode}
\cs_new_protected:Npn \prop_remove:Nn #1#2
- { \@@_split:NnTF #1 {#2} { \@@_remove:NNnnn \tl_set:Nn #1 } { } }
+ {
+ \@@_split:NnTF #1 {#2}
+ { \tl_set:Nn #1 { ##1 ##3 } }
+ { }
+ }
\cs_new_protected:Npn \prop_gremove:Nn #1#2
- { \@@_split:NnTF #1 {#2} { \@@_remove:NNnnn \tl_gset:Nn #1 } { } }
-\cs_new_protected:Npn \@@_remove:NNnnn #1#2#3#4#5
- { #1 #2 { #3 #5 } }
+ {
+ \@@_split:NnTF #1 {#2}
+ { \tl_gset:Nn #1 { ##1 ##3 } }
+ { }
+ }
\cs_generate_variant:Nn \prop_remove:Nn { NV }
\cs_generate_variant:Nn \prop_remove:Nn { c , cV }
\cs_generate_variant:Nn \prop_gremove:Nn { NV }
@@ -645,14 +659,12 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[tested = m3prop002]
% {
% \prop_get:NnN, \prop_get:NVN, \prop_get:NoN,
% \prop_get:cnN, \prop_get:cVN, \prop_get:coN
% }
-% \begin{macro}[aux]{\@@_get:Nnnn}
% Getting an item from a list is very easy: after splitting,
% if the key is in the property list, just set the token list variable
% to the return value, otherwise to \cs{q_no_value}.
@@ -660,22 +672,18 @@
\cs_new_protected:Npn \prop_get:NnN #1#2#3
{
\@@_split:NnTF #1 {#2}
- { \@@_get:Nnnn #3 }
+ { \tl_set:Nn #3 {##2} }
{ \tl_set:Nn #3 { \q_no_value } }
}
-\cs_new_protected:Npn \@@_get:Nnnn #1#2#3#4
- { \tl_set:Nn #1 {#3} }
\cs_generate_variant:Nn \prop_get:NnN { NV , No }
\cs_generate_variant:Nn \prop_get:NnN { c , cV , co }
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[tested = m3prop002]
% {\prop_pop:NnN, \prop_pop:NoN, \prop_pop:cnN, \prop_pop:coN}
% \begin{macro}[tested = m3prop002]
% {\prop_gpop:NnN, \prop_gpop:NoN, \prop_gpop:cnN, \prop_gpop:coN}
-% \begin{macro}[aux]{\@@_pop:NNNnnn}
% Popping a value also starts by doing the split.
% If the key is present, save the value in the token list and update the
% property list as when deleting.
@@ -684,20 +692,21 @@
\cs_new_protected:Npn \prop_pop:NnN #1#2#3
{
\@@_split:NnTF #1 {#2}
- { \@@_pop:NNNnnn \tl_set:Nn #1 #3 }
+ {
+ \tl_set:Nn #3 {##2}
+ \tl_set:Nn #1 { ##1 ##3 }
+ }
{ \tl_set:Nn #3 { \q_no_value } }
}
\cs_new_protected:Npn \prop_gpop:NnN #1#2#3
{
\@@_split:NnTF #1 {#2}
- { \@@_pop:NNNnnn \tl_gset:Nn #1 #3 }
+ {
+ \tl_set:Nn #3 {##2}
+ \tl_gset:Nn #1 { ##1 ##3 }
+ }
{ \tl_set:Nn #3 { \q_no_value } }
}
-\cs_new_protected:Npn \@@_pop:NNNnnn #1#2#3#4#5#6
- {
- \tl_set:Nn #3 {#5}
- #1 #2 { #4 #6 }
- }
\cs_generate_variant:Nn \prop_pop:NnN { No }
\cs_generate_variant:Nn \prop_pop:NnN { c , co }
\cs_generate_variant:Nn \prop_gpop:NnN { No }
@@ -705,11 +714,9 @@
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[TF, tested = m3prop004]
% {\prop_pop:NnN, \prop_pop:cnN, \prop_gpop:NnN, \prop_gpop:cnN}
-% \begin{macro}[aux]{\@@_pop_true:NNNnnn}
% Popping an item from a property list, keeping track of whether
% the key was present or not, is implemented as a conditional.
% If the key was missing, neither the property list, nor the token
@@ -719,21 +726,23 @@
\prg_new_protected_conditional:Npnn \prop_pop:NnN #1#2#3 { T , F , TF }
{
\@@_split:NnTF #1 {#2}
- { \@@_pop_true:NNNnnn \tl_set:Nn #1 #3 }
+ {
+ \tl_set:Nn #3 {##2}
+ \tl_set:Nn #1 { ##1 ##3 }
+ \prg_return_true:
+ }
{ \prg_return_false: }
}
\prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 { T , F , TF }
{
\@@_split:NnTF #1 {#2}
- { \@@_pop_true:NNNnnn \tl_gset:Nn #1 #3 }
+ {
+ \tl_set:Nn #3 {##2}
+ \tl_gset:Nn #1 { ##1 ##3 }
+ \prg_return_true:
+ }
{ \prg_return_false: }
}
-\cs_new_protected:Npn \@@_pop_true:NNNnnn #1#2#3#4#5#6
- {
- \tl_set:Nn #3 {#5}
- #1 #2 { #4 #6 }
- \prg_return_true:
- }
\cs_generate_variant:Nn \prop_pop:NnNT { c }
\cs_generate_variant:Nn \prop_pop:NnNF { c }
\cs_generate_variant:Nn \prop_pop:NnNTF { c }
@@ -742,7 +751,6 @@
\cs_generate_variant:Nn \prop_gpop:NnNTF { c }
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[tested = m3prop002]
% {
@@ -758,32 +766,31 @@
% \prop_gput:cnn, \prop_gput:cnV, \prop_gput:cno, \prop_gput:cnx,
% \prop_gput:cVn, \prop_gput:cVV, \prop_gput:con, \prop_gput:coo
% }
-% \begin{macro}[aux]{\@@_put:NNNnn, \@@_put:NNnnnnn}
-% Putting a key--value pair in a property list starts by splitting to
-% remove any existing value. If the \meta{key} was absent, append the
-% new key--value pair. Otherwise, the property list is reconstructed
-% from the two remaining parts |#5| and |#7|, and the updated entry.
-% The updated entry is placed at the same spot as the original
-% \meta{key} in the property list, preserving the order of entries.
+% \begin{macro}[aux]{\@@_put:NNNnn}
+% Since the branches of \cs{@@_split:NnTF} are used as the replacement
+% text of an internal macro, and since the \meta{key} and new
+% \meta{value} may contain arbitrary tokens, it is not safe to include
+% them in the argument of \cs{@@_split:NnTF}. We thus start by
+% storing in \cs{l_@@_internal_tl} tokens which (after
+% \texttt{x}-expansion) encode the key--value pair. This variable can
+% safely be used in \cs{@@_split:NnTF}. If the \meta{key} was absent,
+% append the new key--value to the list. Otherwise concatenate the
+% extracts |##1| and |##3| with the new key--value pair
+% \cs{l_@@_internal_tl}. The updated entry is placed at the same spot
+% as the original \meta{key} in the property list, preserving the
+% order of entries.
% \begin{macrocode}
-\cs_new_protected:Npn \prop_put:Nnn
+\cs_new_protected_nopar:Npn \prop_put:Nnn
{ \@@_put:NNNnn \tl_set:Nx \tl_put_right:Nx }
-\cs_new_protected:Npn \prop_gput:Nnn
+\cs_new_protected_nopar:Npn \prop_gput:Nnn
{ \@@_put:NNNnn \tl_gset:Nx \tl_gput_right:Nx }
\cs_new_protected:Npn \@@_put:NNNnn #1#2#3#4#5
{
+ \tl_set:Nn \l_@@_internal_tl
+ { \s_@@ \tl_to_str:n {#4} \s_@@ { \exp_not:n {#5} } }
\@@_split:NnTF #3 {#4}
- { \@@_put:NNnnnnn #1 #3 {#4} {#5} }
- { #2 #3 { \tl_to_str:n {#4} \exp_not:n { \q_@@ {#5} \q_@@ } } }
- }
-\cs_new_protected:Npn \@@_put:NNnnnnn #1#2#3#4#5#6#7
- {
- #1 #2
- {
- \exp_not:n {#5}
- \tl_to_str:n {#3} \exp_not:n { \q_@@ {#4} \q_@@ }
- \exp_not:n {#7}
- }
+ { #1 #3 { \exp_not:n {##1} \l_@@_internal_tl \exp_not:n {##3} } }
+ { #2 #3 { \l_@@_internal_tl } }
}
\cs_generate_variant:Nn \prop_put:Nnn
{ NnV , Nno , Nnx , NV , NVV , No , Noo }
@@ -814,12 +821,11 @@
{ \@@_put_if_new:NNnn \tl_gput_right:Nx }
\cs_new_protected:Npn \@@_put_if_new:NNnn #1#2#3#4
{
+ \tl_set:Nn \l_@@_internal_tl
+ { \s_@@ \tl_to_str:n {#3} \s_@@ \exp_not:n { {#4} } }
\@@_split:NnTF #2 {#3}
- { \use_none:nnn }
- {
- #1 #2
- { \tl_to_str:n {#3} \exp_not:n { \q_@@ {#4} \q_@@ } }
- }
+ { }
+ { #1 #2 { \l_@@_internal_tl } }
}
\cs_generate_variant:Nn \prop_put_if_new:Nnn { c }
\cs_generate_variant:Nn \prop_gput_if_new:Nnn { c }
@@ -833,32 +839,18 @@
% \begin{macro}[pTF, tested = m3prop004]{\prop_if_exist:N, \prop_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \prop_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \prop_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \prop_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \prop_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \prop_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \prop_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \prop_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \prop_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \prop_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \prop_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF, tested = m3prop003]{\prop_if_empty:N, \prop_if_empty:c}
-% The test here uses \cs{c_empty_prop} as it is not really empty!
+% Same test as for token lists.
% \begin{macrocode}
-\prg_new_conditional:Npnn \prop_if_empty:N #1 { p, T , F , TF }
- {
- \if_meaning:w #1 \c_empty_prop
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
- }
-\cs_generate_variant:Nn \prop_if_empty_p:N {c}
-\cs_generate_variant:Nn \prop_if_empty:NTF {c}
-\cs_generate_variant:Nn \prop_if_empty:NT {c}
-\cs_generate_variant:Nn \prop_if_empty:NF {c}
+\prg_new_eq_conditional:NNn \prop_if_empty:N \tl_if_empty:N
+ { p , T , F , TF }
+\prg_new_eq_conditional:NNn \prop_if_empty:c \tl_if_empty:c
+ { p , T , F , TF }
% \end{macrocode}
% \end{macro}
%
@@ -885,12 +877,12 @@
% but \cs{@@_split:NnTF} is non-expandable.
%
% Instead, the key is compared to each key in turn using \cs{str_if_eq_x:nn},
-% which is expandable. To terminate the mapping, we add the key that
-% is search for at the end of the property list. This second
+% which is expandable. To terminate the mapping, we append to the property
+% list the key that is searched for. This second
% \cs{tl_to_str:n} is not expanded at the start, but only when included
% in the \cs{str_if_eq_x:nn}. It cannot make the breaking mechanism choke,
% because the arbitrary token list material is enclosed in braces.
-% When ending, we test the next token: it is either \cs{q_@@}
+% When ending, we test the next token: it is either \cs{s_@@}
% or \cs{q_recursion_tail} in the case of a missing key.
% Here, \cs{prop_map_function:NN} is not sufficient for the mapping,
% since it can only map a single token, and cannot carry the key that
@@ -900,11 +892,11 @@
{
\exp_last_unbraced:Noo \@@_if_in:nwn
{ \tl_to_str:n {#2} } #1
- \tl_to_str:n {#2} \q_@@ { }
- \q_recursion_tail % could be any cs != \q_@@
+ \s_@@ \tl_to_str:n {#2} \s_@@ { }
+ \q_recursion_tail
\__prg_break_point:
}
-\cs_new:Npn \@@_if_in:nwn #1 \q_@@ #2 \q_@@ #3
+\cs_new:Npn \@@_if_in:nwn #1 \s_@@ #2 \s_@@ #3
{
\str_if_eq_x:nnTF {#1} {#2}
{ \@@_if_in:N }
@@ -912,7 +904,7 @@
}
\cs_new:Npn \@@_if_in:N #1
{
- \if_meaning:w \q_@@ #1
+ \if_meaning:w \s_@@ #1
\prg_return_true:
\else:
\prg_return_false:
@@ -938,7 +930,6 @@
% \prop_get:NnN, \prop_get:NVN, \prop_get:NoN,
% \prop_get:cnN, \prop_get:cVN, \prop_get:coN
% }
-% \begin{macro}[aux]{\@@_get_true:Nnnn}
% Getting the value corresponding to a key, keeping track of whether
% the key was present or not, is implemented as a conditional (with
% side effects). If the key was absent, the token list is not altered.
@@ -946,14 +937,12 @@
\prg_new_protected_conditional:Npnn \prop_get:NnN #1#2#3 { T , F , TF }
{
\@@_split:NnTF #1 {#2}
- { \@@_get_true:Nnnn #3 }
+ {
+ \tl_set:Nn #3 {##2}
+ \prg_return_true:
+ }
{ \prg_return_false: }
}
-\cs_new_protected:Npn \@@_get_true:Nnnn #1#2#3#4
- {
- \tl_set:Nn #1 {#3}
- \prg_return_true:
- }
\cs_generate_variant:Nn \prop_get:NnNT { NV , No }
\cs_generate_variant:Nn \prop_get:NnNF { NV , No }
\cs_generate_variant:Nn \prop_get:NnNTF { NV , No }
@@ -962,7 +951,6 @@
\cs_generate_variant:Nn \prop_get:NnNTF { c , cV , co }
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
% \subsection{Mapping to property lists}
%
@@ -972,19 +960,24 @@
% \prop_map_function:cN, \prop_map_function:cc
% }
% \begin{macro}[aux]{\@@_map_function:Nwn}
-% The fastest way to do a recursion here would be to use an
+% The fastest way to do a recursion here is to use an
% \cs{if_meaning:w} test: the keys are strings, and thus
% cannot match the marker \cs{q_recursion_tail}.
+% A special case to note is when the key |#2| is empty:
+% then \cs{q_recursion_tail} is compared to \cs{exp_after:wN},
+% also different.
% \begin{macrocode}
\cs_new:Npn \prop_map_function:NN #1#2
{
\exp_last_unbraced:NNo \@@_map_function:Nwn #2
- #1 \q_recursion_tail \q_@@ { }
+ #1 \s_@@ \q_recursion_tail \s_@@ { }
\__prg_break_point:Nn \prop_map_break: { }
}
-\cs_new:Npn \@@_map_function:Nwn #1 \q_@@ #2 \q_@@ #3
+\cs_new:Npn \@@_map_function:Nwn #1 \s_@@ #2 \s_@@ #3
{
- \__quark_if_recursion_tail_break:nN {#2} \prop_map_break:
+ \if_meaning:w \q_recursion_tail #2
+ \exp_after:wN \prop_map_break:
+ \fi:
#1 {#2} {#3}
\@@_map_function:Nwn #1
}
@@ -1004,7 +997,7 @@
\exp_last_unbraced:Nco \@@_map_function:Nwn
{ __prg_map_ \int_use:N \g__prg_map_int :w }
#1
- \q_recursion_tail \q_@@ { }
+ \s_@@ \q_recursion_tail \s_@@ { }
\__prg_break_point:Nn \prop_map_break: { \int_gdecr:N \g__prg_map_int }
}
\cs_generate_variant:Nn \prop_map_inline:Nn { c }
@@ -1119,6 +1112,7 @@
% \begin{macro}{\prop_del:Nn, \prop_del:NV, \prop_del:cn, \prop_del:cV}
% \begin{macro}{\prop_gdel:Nn, \prop_gdel:NV, \prop_gdel:cn, \prop_gdel:cV}
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \prop_del:Nn \prop_remove:Nn
\cs_new_eq:NN \prop_del:NV \prop_remove:NV
\cs_new_eq:NN \prop_del:cn \prop_remove:cn
@@ -1127,6 +1121,7 @@
\cs_new_eq:NN \prop_gdel:NV \prop_gremove:NV
\cs_new_eq:NN \prop_gdel:cn \prop_gremove:cn
\cs_new_eq:NN \prop_gdel:cV \prop_gremove:cV
+%</deprecated>
% \end{macrocode}
% \end{macro}
% \end{macro}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx
index f9c8f06e7e3..e917aeda4ea 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3seq.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3seq.dtx Copyright (C) 1990-2012 The LaTeX3 Project
+%% File: l3seq.dtx Copyright (C) 1990-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3seq.dtx 4339 2012-11-24 19:16:43Z joseph $
+\GetIdInfo$Id: l3seq.dtx 4434 2013-01-12 09:33:40Z bruno $
{L3 Sequences and stacks}
%</driver|package>
%<*driver>
@@ -437,8 +437,9 @@
% Applies \meta{function} to every \meta{item} stored in the
% \meta{sequence}. The \meta{function} will receive one argument for
% each iteration. The \meta{items} are returned from left to right.
-% The function \cs{seq_map_inline:Nn} is in general more efficient
-% than \cs{seq_map_function:NN}.
+% The function \cs{seq_map_inline:Nn} is faster than
+% \cs{seq_map_function:NN} for sequences with more than about~$10$
+% items.
% One mapping may be nested inside another.
% \end{function}
%
@@ -882,12 +883,10 @@
% \UnitTested
% Concatenating sequences is easy.
% \begin{macrocode}
-\cs_new_protected:Npn \seq_concat:NNN #1#2#3
- { \tl_set:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } }
-\cs_new_protected:Npn \seq_gconcat:NNN #1#2#3
- { \tl_gset:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } }
-\cs_generate_variant:Nn \seq_concat:NNN { ccc }
-\cs_generate_variant:Nn \seq_gconcat:NNN { ccc }
+\cs_new_eq:NN \seq_concat:NNN \tl_concat:NNN
+\cs_new_eq:NN \seq_gconcat:NNN \tl_gconcat:NNN
+\cs_new_eq:NN \seq_concat:ccc \tl_concat:ccc
+\cs_new_eq:NN \seq_gconcat:ccc \tl_gconcat:ccc
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -895,14 +894,8 @@
% \begin{macro}[pTF]{\seq_if_exist:N, \seq_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \seq_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \seq_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \seq_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \seq_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \seq_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \seq_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \seq_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \seq_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \seq_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \seq_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
@@ -1604,8 +1597,10 @@
%
% \begin{macro}{\seq_length:N, \seq_length:c}
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \seq_length:N \seq_count:N
\cs_new_eq:NN \seq_length:c \seq_count:c
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -1614,8 +1609,10 @@
% \begin{macro}{\seq_use:N, \seq_use:c}
% A simple short cut for a mapping.
% \begin{macrocode}
+%<*deprecated>
\cs_new:Npn \seq_use:N #1 { \seq_map_function:NN #1 \use:n }
\cs_generate_variant:Nn \seq_use:N { c }
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx
index 3eb3eb8c901..1a9d70f8756 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3skip.dtx
@@ -1,7 +1,7 @@
% \iffalse meta-comment
%
%% File: l3skip.dtx Copyright (C) 2004-2011 Frank Mittelbach, The LaTeX3 Project
-%% (C) 2012 The LaTeX3 Project
+%% (C) 2012,2013 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
@@ -36,7 +36,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3skip.dtx 4260 2012-11-04 17:20:25Z joseph $
+\GetIdInfo$Id: l3skip.dtx 4444 2013-01-13 20:27:20Z bruno $
{L3 Dimensions and skips}
%</driver|package>
%<*driver>
@@ -228,16 +228,37 @@
% \end{center}
% \end{function}
%
-% \begin{function}[EXP,pTF]{\dim_compare:n}
+% \begin{function}[updated = 2013-01-13, EXP, pTF]{\dim_compare:n}
% \begin{syntax}
-% \cs{dim_compare_p:n} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \\
+% \cs{dim_compare_p:n} \\
+% ~~\{ \\
+% ~~~~\meta{dimexpr_1} \meta{relation_1} \\
+% ~~~~\ldots{} \\
+% ~~~~\meta{dimexpr_N} \meta{relation_N} \\
+% ~~~~\meta{dimexpr_{N+1}} \\
+% ~~\} \\
% \cs{dim_compare:nTF}
-% ~~\{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \}
+% ~~\{ \\
+% ~~~~\meta{dimexpr_1} \meta{relation_1} \\
+% ~~~~\ldots{} \\
+% ~~~~\meta{dimexpr_N} \meta{relation_N} \\
+% ~~~~\meta{dimexpr_{N+1}} \\
+% ~~\} \\
% ~~\Arg{true code} \Arg{false code}
% \end{syntax}
-% This function first evaluates each of the \meta{dimension expressions}
-% as described for \cs{dim_eval:n}. The two results are then
-% compared using the \meta{relation}:
+% This function evaluates the \meta{dimension expressions} as
+% described for \cs{dim_eval:n} and compares consecutive result using
+% the corresponding \meta{relation}, namely it compares
+% \meta{dimexpr_1} and \meta{dimexpr_2} using the \meta{relation_1},
+% then \meta{dimexpr_2} and \meta{dimexpr_3} using the
+% \meta{relation_2}, until finally comparing \meta{dimexpr_N} and
+% \meta{dimexpr_{N+1}} using the \meta{relation_N}. The test yields
+% \texttt{true} if all comparisons are \texttt{true}. Each
+% \meta{dimension expression} is evaluated only once, and the
+% evaluation is lazy, in the sense that if one comparison is
+% \texttt{false}, then no other \meta{dimension expression} is
+% evaluated and no other comparison is performed. The
+% \meta{relations} can be any of the following:
% \begin{center}
% \begin{tabular}{ll}
% Equal & |=| or |==| \\
@@ -331,35 +352,35 @@
% \texttt{false}.
% \end{function}
%
-% \begin{function}[rEXP]{\dim_do_until:nn}
+% \begin{function}[updated = 2013-01-13, rEXP]{\dim_do_until:nn}
% \begin{syntax}
-% \cs{dim_do_until:nn} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \Arg{code}
+% \cs{dim_do_until:nn} \Arg{dimension relation} \Arg{code}
% \end{syntax}
% Places the \meta{code} in the input stream for \TeX{} to process, and
-% then evaluates the relationship between the two
-% \meta{dimension expressions} as described for \cs{dim_compare:nTF}.
+% then evaluates the \meta{dimension relation}
+% as described for \cs{dim_compare:nTF}.
% If the test is \texttt{false} then the \meta{code} will be inserted
% into the input stream again and a loop will occur until the
% \meta{relation} is \texttt{true}.
% \end{function}
%
-% \begin{function}[rEXP]{\dim_do_while:nn}
+% \begin{function}[updated = 2013-01-13, rEXP]{\dim_do_while:nn}
% \begin{syntax}
-% \cs{dim_do_while:nn} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \Arg{code}
+% \cs{dim_do_while:nn} \Arg{dimension relation} \Arg{code}
% \end{syntax}
% Places the \meta{code} in the input stream for \TeX{} to process, and
-% then evaluates the relationship between the two
-% \meta{dimension expressions} as described for \cs{dim_compare:nTF}.
+% then evaluates the \meta{dimension relation}
+% as described for \cs{dim_compare:nTF}.
% If the test is \texttt{true} then the \meta{code} will be inserted
% into the input stream again and a loop will occur until the
% \meta{relation} is \texttt{false}.
% \end{function}
%
-% \begin{function}[rEXP]{\dim_until_do:nn}
+% \begin{function}[updated = 2013-01-13, rEXP]{\dim_until_do:nn}
% \begin{syntax}
-% \cs{dim_until_do:nn} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \Arg{code}
+% \cs{dim_until_do:nn} \Arg{dimension relation} \Arg{code}
% \end{syntax}
-% Evaluates the relationship between the two \meta{dimension expressions}
+% Evaluates the \meta{dimension relation}
% as described for \cs{dim_compare:nTF}, and then places the
% \meta{code} in the input stream if the \meta{relation} is
% \texttt{false}. After the \meta{code} has been processed by \TeX{} the
@@ -367,11 +388,11 @@
% \texttt{true}.
% \end{function}
%
-% \begin{function}[rEXP]{\dim_while_do:nn}
+% \begin{function}[updated = 2013-01-13, rEXP]{\dim_while_do:nn}
% \begin{syntax}
-% \cs{dim_while_do:nn} \{ \meta{dimexpr_1} \meta{relation} \meta{dimexpr_2} \} \Arg{code}
+% \cs{dim_while_do:nn} \Arg{dimension relation} \Arg{code}
% \end{syntax}
-% Evaluates the relationship between the two \meta{dimension expressions}
+% Evaluates the \meta{dimension relation}
% as described for \cs{dim_compare:nTF}, and then places the
% \meta{code} in the input stream if the \meta{relation} is
% \texttt{true}. After the \meta{code} has been processed by \TeX{} the
@@ -991,14 +1012,8 @@
% \begin{macro}[pTF]{\dim_if_exist:N, \dim_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \dim_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \dim_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \dim_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \dim_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \dim_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \dim_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \dim_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \dim_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \dim_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \dim_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
@@ -1134,58 +1149,61 @@
% \end{macro}
%
% \begin{macro}[pTF, EXP]{\dim_compare:n}
-% \begin{macro}[aux, EXP]{\@@_compare_aux:w, \@@_compare_aux:NNw}
+% \begin{macro}[aux, EXP]{\@@_compare:w, \@@_compare:wNN}
% \begin{macro}[aux, EXP]
% {
-% \@@_compare_=:NNw,
-% \@@_compare_<:NNw,
-% \@@_compare_>:NNw,
-% \@@_compare_==:NNw,
-% \@@_compare_!=:NNw,
-% \@@_compare_<=:NNw,
-% \@@_compare_>=:NNw
+% \@@_compare_=:w,
+% \@@_compare_!:w,
+% \@@_compare_<:w,
+% \@@_compare_>:w
% }
% This code is adapted from the \cs{int_compare:nTF} function. First
-% evaluate the left-hand side. Then access the relation symbol by
-% grabbing until \texttt{pt} (with category other), and pursue
-% otherwise just as for \cs{int_compare:nTF}.
+% make sure that there is at least one relation operator, by
+% evaluating a dimension expression with a trailing
+% \cs{__prg_compare_error:}. Just like for integers, the looping
+% auxiliary \cs{@@_compare:wNN} closes a primitive conditional and
+% opens a new one. It is actually easier to grab a dimension operand
+% than an integer one, because once evaluated, dimensions all end with
+% \texttt{pt} (with category other). Thus we do not need specific
+% auxiliaries for the three \enquote{simple} relations |<|, |=|,
+% and~|>|.
% \begin{macrocode}
\prg_new_conditional:Npnn \dim_compare:n #1 { p , T , F , TF }
{
- \exp_after:wN \@@_compare_aux:w \dim_use:N \@@_eval:w #1
- \__prg_compare_error: \@@_eval_end:
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
+ \exp_after:wN \@@_compare:w
+ \dim_use:N \@@_eval:w #1 \__prg_compare_error:
}
-\exp_args:Nno \use:nn
- { \cs_new:Npn \@@_compare_aux:w #1 }
- { \tl_to_str:n { pt } }
- #2 \__prg_compare_error:
+\cs_new:Npn \@@_compare:w #1 \__prg_compare_error:
{
- \exp_after:wN \@@_compare_aux:NNw #2 ?? \q_mark
- #1 pt #2
+ \exp_after:wN \if_false: \tex_romannumeral:D -`0
+ \@@_compare:wNN #1 ? { = \@@_compare_end:w \else: } \q_stop
}
-\cs_new:Npn \@@_compare_aux:NNw #1#2#3 \q_mark
+\exp_args:Nno \use:nn
+ { \cs_new:Npn \@@_compare:wNN #1 }
+ { \tl_to_str:n {pt} }
+ #2#3
{
- \use:c { @@_compare_ #1 \if_meaning:w = #2 = \fi: :NNw }
- \__prg_compare_error:Nw #1
+ \if_meaning:w = #3
+ \use:c { @@_compare_#2:w }
+ \fi:
+ #1 pt \exp_stop_f:
+ \prg_return_false:
+ \exp_after:wN \use_none_delimit_by_q_stop:w
+ \fi:
+ \reverse_if:N \if_dim:w #1 pt #2
+ \exp_after:wN \@@_compare:wNN
+ \dim_use:N \@@_eval:w #3
}
-\cs_new:cpn { @@_compare_=:NNw } #1#2#3 =
- { \if_dim:w #3 = \@@_eval:w }
-\cs_new:cpn { @@_compare_<:NNw } #1#2#3 <
- { \if_dim:w #3 < \@@_eval:w }
-\cs_new:cpn { @@_compare_>:NNw } #1#2#3 >
- { \if_dim:w #3 > \@@_eval:w }
-\cs_new:cpn { @@_compare_==:NNw } #1#2#3 ==
- { \if_dim:w #3 = \@@_eval:w }
-\cs_new:cpn { @@_compare_!=:NNw } #1#2#3 !=
- { \reverse_if:N \if_dim:w #3 = \@@_eval:w }
-\cs_new:cpn { @@_compare_<=:NNw } #1#2#3 <=
- { \reverse_if:N \if_dim:w #3 > \@@_eval:w }
-\cs_new:cpn { @@_compare_>=:NNw } #1#2#3 >=
- { \reverse_if:N \if_dim:w #3 < \@@_eval:w }
+\cs_new:cpn { @@_compare_ ! :w }
+ #1 \reverse_if:N #2 ! #3 = { #1 #2 = #3 }
+\cs_new:cpn { @@_compare_ = :w }
+ #1 \@@_eval:w = { #1 \@@_eval:w }
+\cs_new:cpn { @@_compare_ < :w }
+ #1 \reverse_if:N #2 < #3 = { #1 #2 > #3 }
+\cs_new:cpn { @@_compare_ > :w }
+ #1 \reverse_if:N #2 > #3 = { #1 #2 < #3 }
+\cs_new:Npn \@@_compare_end:w #1 \prg_return_false: #2 \q_stop
+ { #1 \prg_return_false: \else: \prg_return_true: \fi: }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1454,14 +1472,8 @@
% \begin{macro}[pTF]{\skip_if_exist:N, \skip_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \skip_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \skip_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \skip_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \skip_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \skip_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \skip_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \skip_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \skip_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \skip_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \skip_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
@@ -1705,14 +1717,8 @@
% \begin{macro}[pTF]{\muskip_if_exist:N, \muskip_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \muskip_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \muskip_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \muskip_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \muskip_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \muskip_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \muskip_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \muskip_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \muskip_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \muskip_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \muskip_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
@@ -1847,8 +1853,10 @@
% \begin{macro}[EXP, pTF]{\skip_if_infinite_glue:n}
% Reverse of \cs{skip_if_finite:nTF}.
% \begin{macrocode}
+%<*deprecated>
\prg_new_conditional:Npnn \skip_if_infinite_glue:n #1 { p , T , F , TF }
{ \skip_if_finite:nTF {#1} \prg_return_false: \prg_return_true: }
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -1858,14 +1866,18 @@
% Moved here, was in \pkg{l3prg} but load order means we define it here
% now.
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \prg_case_dim:nnn \dim_case:nnn
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\dim_eval:w, \dim_eval_end:}
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \dim_eval:w \__dim_eval:w
\cs_new_eq:NN \dim_eval_end: \__dim_eval_end:
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -1876,6 +1888,7 @@
% \begin{macro}[aux]{\@@_set_max:NNNn}
% Deprecated on 2012-09-09 for removal after 2012-12-31.
% \begin{macrocode}
+%<*deprecated>
\cs_new_protected_nopar:Npn \dim_set_max:Nn
{ \@@_set_max:NNNn < \dim_set:Nn }
\cs_new_protected_nopar:Npn \dim_gset_max:Nn
@@ -1890,6 +1903,7 @@
\cs_generate_variant:Nn \dim_gset_max:Nn { c }
\cs_generate_variant:Nn \dim_set_min:Nn { c }
\cs_generate_variant:Nn \dim_gset_min:Nn { c }
+%</deprecated>
% \end{macrocode}
% \end{macro}
% \end{macro}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
index 0f166541978..dc164dc20c8 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3tl.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3tl.dtx Copyright (C) 1990-2012 The LaTeX3 Project
+%% File: l3tl.dtx Copyright (C) 1990-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3tl.dtx 4339 2012-11-24 19:16:43Z joseph $
+\GetIdInfo$Id: l3tl.dtx 4415 2013-01-08 12:32:51Z bruno $
{L3 Token lists}
%</driver|package>
%<*driver>
@@ -465,8 +465,8 @@
% \begin{function}[updated = 2011-08-13, 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}
+% \cs{tl_if_single_p:N} \meta{tl~var}
+% \cs{tl_if_single:NTF} \meta{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 a single normal token (neither an explicit space
@@ -680,7 +680,7 @@
%
% \begin{function}[added = 2012-05-13, EXP]{\tl_count:N, \tl_count:c}
% \begin{syntax}
-% \cs{tl_count:N} \Arg{tl~var}
+% \cs{tl_count:N} \meta{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
@@ -714,7 +714,7 @@
% \begin{function}[updated = 2012-01-08]
% {\tl_reverse:N, \tl_reverse:c, \tl_greverse:N, \tl_greverse:c}
% \begin{syntax}
-% \cs{tl_reverse:N} \Arg{tl~var}
+% \cs{tl_reverse:N} \meta{tl~var}
% \end{syntax}
% Reverses the order of the \meta{items} stored in \meta{tl~var}, so
% that \meta{item_1}\meta{item_2}\meta{item_3} \ldots \meta{item_n}
@@ -1150,14 +1150,8 @@
% \begin{macro}[pTF]{\tl_if_exist:N, \tl_if_exist:c}
% Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
% \begin{macrocode}
-\cs_new_eq:NN \tl_if_exist:NTF \cs_if_exist:NTF
-\cs_new_eq:NN \tl_if_exist:NT \cs_if_exist:NT
-\cs_new_eq:NN \tl_if_exist:NF \cs_if_exist:NF
-\cs_new_eq:NN \tl_if_exist_p:N \cs_if_exist_p:N
-\cs_new_eq:NN \tl_if_exist:cTF \cs_if_exist:cTF
-\cs_new_eq:NN \tl_if_exist:cT \cs_if_exist:cT
-\cs_new_eq:NN \tl_if_exist:cF \cs_if_exist:cF
-\cs_new_eq:NN \tl_if_exist_p:c \cs_if_exist_p:c
+\prg_new_eq_conditional:NNn \tl_if_exist:N \cs_if_exist:N { TF , T , F , p }
+\prg_new_eq_conditional:NNn \tl_if_exist:c \cs_if_exist:c { TF , T , F , p }
% \end{macrocode}
% \end{macro}
%
@@ -2543,7 +2537,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \tl_show:N #1
{
- \cs_if_exist:NTF #1
+ \tl_if_exist:NTF #1
{ \cs_show:N #1 }
{
\__msg_kernel_error:nnx { kernel } { variable-not-defined }
@@ -2704,7 +2698,9 @@
%
% \begin{macro}{\tl_length_tokens:n}
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \tl_length_tokens:n \tl_count_tokens:n
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -2714,11 +2710,13 @@
% {\tl_length:N, \tl_length:c, \tl_length:n, \tl_length:V, \tl_length:o}
% Renames.
% \begin{macrocode}
+%<*deprecated>
\cs_new_eq:NN \tl_length:N \tl_count:N
\cs_new_eq:NN \tl_length:c \tl_count:c
\cs_new_eq:NN \tl_length:n \tl_count:n
\cs_new_eq:NN \tl_length:V \tl_count:V
\cs_new_eq:NN \tl_length:o \tl_count:o
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -2730,8 +2728,10 @@
% a token list is empty if and only if its string representation is
% empty.
% \begin{macrocode}
+%<*deprecated>
\prg_new_conditional:Npnn \tl_if_empty:x #1 { p , T , F , TF }
{ \__str_if_eq_x_return:nn { } {#1} }
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
@@ -2741,12 +2741,14 @@
% \begin{macro}[EXP, pTF]{\tl_if_head_N_type:n}
% \begin{macro}[EXP, pTF]{\tl_if_head_space:n}
% \begin{macrocode}
+%<*deprecated>
\prg_new_eq_conditional:NNn \tl_if_head_group:n \tl_if_head_is_group:n
{ p , T , F , TF }
\prg_new_eq_conditional:NNn \tl_if_head_N_type:n \tl_if_head_is_N_type:n
{ p , T , F , TF }
\prg_new_eq_conditional:NNn \tl_if_head_space:n \tl_if_head_is_space:n
{ p , T , F , TF }
+%</deprecated>
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2756,11 +2758,12 @@
% Deprecated 2012-09-01 for removal after 2012-12-31. This is broken as
% it will strip braces from a case such as |a{bc}|.
% \begin{macrocode}
+%<*deprecated>
\cs_new:Npn \tl_tail:w #1#2 \q_stop {#2}
+%</deprecated>
% \end{macrocode}
% \end{macro}
%
-%
% \begin{macrocode}
%</initex|package>
% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx
index 6e3ef14d414..16e5510475a 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3token.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3token.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3token.dtx Copyright (C) 2005-2012 The LaTeX3 Project
+%% File: l3token.dtx Copyright (C) 2005-2013 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
@@ -35,7 +35,7 @@
%
%<*driver|package>
\RequirePackage{l3bootstrap}
-\GetIdInfo$Id: l3token.dtx 4384 2012-12-20 15:47:56Z bruno $
+\GetIdInfo$Id: l3token.dtx 4428 2013-01-10 13:23:29Z bruno $
{L3 Experimental token manipulation}
%</driver|package>
%<*driver>
@@ -1759,7 +1759,7 @@
% token has either a space (e.g., |the letter A|), a digit
% (e.g., |\count123|) or a double quote (e.g., |\char"A|).
%
-% Ten exceptions: on the one hand, \cs{c_undefined:D} is not a
+% Ten exceptions: on the one hand, \cs{tex_undefined:D} is not a
% primitive, but its meaning is |undefined|, only letters;
% on the other hand, \tn{space}, \tn{italiccorr},
% \tn{hyphen}, \tn{firstmark}, \tn{topmark},
@@ -1781,7 +1781,7 @@
%
% We are now left with a string, which we must analyze. For primitives,
% it contains only letters. For non-primitives, it contains either
-% |"|, or a space, or a digit. Two exceptions remain: \cs{c_undefined:D},
+% |"|, or a space, or a digit. Two exceptions remain: \cs{tex_undefined:D},
% which is not a primitive, and \tn{nullfont}, which is a primitive.
%
% Spaces cannot be grabbed in an undelimited way, so we check them
@@ -1790,7 +1790,7 @@
% first character less than |`A| (this is not quite a test for
% \enquote{only letters}, but is close enough to work in this context).
% If this first character is |:| then we have a primitive, or
-% \cs{c_undefined:D}, and if it is |"| or a digit, then the token
+% \cs{tex_undefined:D}, and if it is |"| or a digit, then the token
% is not a primitive.
%
% \begin{macrocode}
@@ -2076,30 +2076,26 @@
% \end{macro}
%
% \begin{macro}{\@@_ignore_spaces_execute_branches:}
-% \begin{macro}[aux]{\@@_ignore_spaces_execute_branches_aux:}
-% This function removes one token at a time with the same mechanism as
-% \cs{@@_true_remove:w}. We directly use the primitive meaning test
-% rather than \cs{token_if_eq_meaning:NNTF} because \cs{l_peek_token}
-% may be an outer macro (coming from non-\LaTeX3 packages). We cannot
-% replace \cs{@@_tmp:w} by \cs{l_peek_token} here because if the
-% latter is an outer macro, it may not appear in the skipped branch of
-% a conditional.
+% This function removes one space token at a time, and calls
+% \cs{@@_execute_branches:} when encountering the first non-space
+% token. We directly use the primitive meaning test rather than
+% \cs{token_if_eq_meaning:NNTF} because \cs{l_peek_token} may be an
+% outer macro (coming from non-\LaTeX3 packages). Spaces are removed
+% using a side-effect of \texttt{f}-expansion:
+% |\tex_romannumeral:D -`0| removes one space.
% \begin{macrocode}
\cs_new_protected_nopar:Npn \@@_ignore_spaces_execute_branches:
{
\if_meaning:w \l_peek_token \c_space_token
- \tex_afterassignment:D \@@_ignore_spaces_execute_branches_aux:
- \exp_after:wN \cs_set_eq:NN
- \exp_after:wN \@@_tmp:w
+ \exp_after:wN \peek_after:Nw
+ \exp_after:wN \@@_ignore_spaces_execute_branches:
+ \tex_romannumeral:D -`0
\else:
\exp_after:wN \@@_execute_branches:
\fi:
}
-\cs_new_protected_nopar:Npn \@@_ignore_spaces_execute_branches_aux:
- { \peek_after:Nw \@@_ignore_spaces_execute_branches: }
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
% \begin{macro}[aux]{\@@_def:nnnn}
% \begin{macro}[aux]{\@@_def:nnnnn}
diff --git a/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx b/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
index b460dc095cb..4e7635b8be3 100644
--- a/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/l3keys2e/l3keys2e.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-%% File: l3keys2e.dtx (C) Copyright 2009,2011,2012 The LaTeX3 Project
+%% File: l3keys2e.dtx (C) Copyright 2009,2011-2013 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
@@ -37,8 +37,8 @@
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2012/12/21]
-%<package>\@ifpackagelater{expl3}{2012/12/21}
+\RequirePackage{expl3}[2013/03/12]
+%<package>\@ifpackagelater{expl3}{2013/03/12}
%<package> {}
%<package> {%
%<package> \PackageError{l3keys2e}{Support package l3kernel too old}
@@ -50,7 +50,7 @@
%<package> }%
%<package> \endinput
%<package> }
-\GetIdInfo$Id: l3keys2e.dtx 4390 2012-12-21 06:59:20Z joseph $
+\GetIdInfo$Id: l3keys2e.dtx 4467 2013-03-12 08:29:05Z joseph $
{LaTeX2e option processing using LaTeX3 keys}
%</driver|package>
%<*driver>
@@ -153,11 +153,11 @@
{\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
% \end{macrocode}
%
-% \begin{macro}{\@@_latexe_options_clist}
+% \begin{macro}{\l_@@_latexe_options_clist}
% A single list is used for all options, into which they are collected
% before processing.
% \begin{macrocode}
-\clist_new:N \@@_latexe_options_clist
+\clist_new:N \l_@@_latexe_options_clist
% \end{macrocode}
% \end{macro}
%
@@ -171,7 +171,7 @@
%
% \begin{macro}{\@@_latexe_options:n}
% The main function calls functions to collect up the global and local
-% options into \cs{@@_latexe_options_clist} before calling the
+% options into \cs{l_@@_latexe_options_clist} before calling the
% underlying functions to actually do the processing. So that a suitable
% message is produced if the option is unknown, the special
% \texttt{unknown} key is set if it does not already exist for the
@@ -179,7 +179,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_latexe_options:n #1
{
- \clist_clear:N \@@_latexe_options_clist
+ \clist_clear:N \l_@@_latexe_options_clist
\@@_latexe_options_global:n {#1}
\@@_latexe_options_local:
\keys_if_exist:nnF {#1} { unknown }
@@ -193,7 +193,7 @@
}
}
}
- \keys_set:nV {#1} \@@_latexe_options_clist
+ \keys_set:nV {#1} \l_@@_latexe_options_clist
\AtEndOfPackage { \cs_set_eq:NN \@unprocessedoptions \scan_stop: }
}
% \end{macrocode}
@@ -231,12 +231,12 @@
\cs_new_protected:Npn \@@_latexe_options_class:n #1
{
\keys_if_exist:nnTF {#1} { unknown }
- { \clist_put_right:No \@@_latexe_options_clist \@classoptionslist }
+ { \clist_put_right:No \l_@@_latexe_options_clist \@classoptionslist }
{
\clist_map_inline:Nn \@classoptionslist
{
\keys_if_exist:nnTF {#1} { \@@_latexe_remove_equals:n {##1} }
- { \clist_put_right:Nn \@@_latexe_options_clist {##1} }
+ { \clist_put_right:Nn \l_@@_latexe_options_clist {##1} }
{ \clist_put_right:Nn \@unusedoptionlist {##1} }
}
}
@@ -256,7 +256,7 @@
{
\keys_if_exist:nnT {#1} { \@@_latexe_remove_equals:n {##1} }
{
- \clist_put_right:Nn \@@_latexe_options_clist {##1}
+ \clist_put_right:Nn \l_@@_latexe_options_clist {##1}
\clist_remove_all:Nn \@unusedoptionlist {##1}
}
}
@@ -275,7 +275,7 @@
{
\cs_if_exist:cT { opt@ \@currname . \@currext }
{
- \exp_args:NNc \clist_put_right:NV \@@_latexe_options_clist
+ \exp_args:NNc \clist_put_right:NV \l_@@_latexe_options_clist
{ opt@ \@currname . \@currext }
}
}
diff --git a/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx b/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
index 67b80d5358a..64a7cb504d9 100644
--- a/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/xparse/xparse.dtx
@@ -4,7 +4,7 @@
%% David Carlisle
%% (C) Copyright 2004-2008 Frank Mittelbach,
%% The LaTeX3 Project
-%% (C) Copyright 2009-2012 The LaTeX3 Project
+%% (C) Copyright 2009-2013 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
@@ -41,8 +41,8 @@
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2012/12/21]
-%<package>\@ifpackagelater{expl3}{2012/12/21}
+\RequirePackage{expl3}[2013/03/12]
+%<package>\@ifpackagelater{expl3}{2013/03/12}
%<package> {}
%<package> {%
%<package> \PackageError{xparse}{Support package l3kernel too old}
@@ -54,7 +54,7 @@
%<package> }%
%<package> \endinput
%<package> }
-\GetIdInfo$Id: xparse.dtx 4390 2012-12-21 06:59:20Z joseph $
+\GetIdInfo$Id: xparse.dtx 4467 2013-03-12 08:29:05Z joseph $
{L3 Experimental document command parser}
%</driver|package>
%<*driver>
@@ -200,24 +200,19 @@
% `|s o o m O{default}|', the input `|*[Foo]{Bar}|' would be parsed as:
% \begin{itemize}[nolistsep]
% \item |#1| = |\BooleanTrue|
-% \item |#2| = |{Foo}|
+% \item |#2| = |Foo|
% \item |#3| = |-NoValue-|
-% \item |#4| = |{Bar}|
-% \item |#5| = |{default}|
+% \item |#4| = |Bar|
+% \item |#5| = |default|
% \end{itemize}
% whereas `|[One][Two]{}[Three]|' would be parsed as:
% \begin{itemize}[nolistsep]
% \item |#1| = |\BooleanFalse|
-% \item |#2| = |{One}|
-% \item |#3| = |{Two}|
-% \item |#4| = |{}|
-% \item |#5| = |{Three}|
+% \item |#2| = |One|
+% \item |#3| = |Two|
+% \item |#4| = ||
+% \item |#5| = |Three|
% \end{itemize}
-% Note that after parsing the input there will be always exactly the
-% same number of \meta{balanced text} arguments as the number of letters
-% in the argument specifier. The \cs{BooleanTrue} and \cs{BooleanFalse}
-% tokens are passed without braces; all other arguments are passed as
-% brace groups.
%
% Delimited argument types (\texttt{d}, \texttt{o} and \texttt{r}) are
% defined such that they require matched pairs of delimiters when collecting
@@ -230,6 +225,20 @@
% Also note that |{| and |}| cannot be used as delimiters as they are used
% by \TeX{} as grouping tokens. Arguments to be grabbed inside these tokens
% must be created as either \texttt{m}- or \texttt{g}-type arguments.
+%
+% Within delimited arguments, non-balanced or otherwise awkward tokens may
+% be included by protecting the entire argument with a brace pair
+% \begin{verbatim}
+% \DeclareDocumentCommand{\foo}{o}{#1}
+% \foo[{[}] % Allowed as the "[" is 'hidden'
+% \end{verbatim}
+% These braces will be stripped if they surround the \emph{entire} content
+% of the optional argument
+% \begin{verbatim}
+% \DeclareDocumentCommand{\foo}{o}{#1}
+% \foo[{abc}] % => "abc"
+% \foo[ {abc}] % => " {abc}"
+% \end{verbatim}
%
% Two more tokens have a special meaning when creating an argument
% specifier. First, \texttt{+} is used to make an argument long (to
@@ -1868,6 +1877,13 @@
#4 \l_@@_args_tl
}
}
+% \end{macrocode}
+% Inside the \enquote{standard} grabber, there is a test to see if the
+% grabbed argument is entirely enclosed by braces. There are a couple of
+% extra factors to allow for: the argument might be entirely empty, and
+% spaces at the start and end of the input must be retained around a brace
+% group.
+% \begin{macrocode}
\cs_new_protected:Npn \@@_grab_D_aux:NNnN #1#2#3#4
{
\cs_set_protected_nopar:Npn \@@_grab_arg:w
@@ -1877,7 +1893,15 @@
\tl_if_in:nnTF {####1} {#1}
{ \@@_grab_D_nested:NNnnN #1 #2 {####1} {#3} #4 }
{
- \@@_add_arg:o { \use_none:n ####1 }
+ \tl_if_blank:oTF { \use_none:n ####1 }
+ { \@@_add_arg:o { \use_none:n ####1 } }
+ {
+ \str_if_eq_x:nnTF
+ { \exp_not:o { \use_none:n ####1 } }
+ { { \exp_not:o { \use_ii:nnn ####1 \q_nil } } }
+ { \@@_add_arg:o { \use_ii:nn ####1 } }
+ { \@@_add_arg:o { \use_none:n ####1 } }
+ }
#3 \l_@@_args_tl
}
}
@@ -2683,14 +2707,23 @@
% delimiter. In that case, we are done, and put the argument (from which we
% remove a spurious pair of delimiters coming from how we started the loop).
% Otherwise, we go back to looping with
-% \cs{@@_expandable_grab_D:NNNwNnnn}.
+% \cs{@@_expandable_grab_D:NNNwNnnn}. The code to deal with brace stripping
+% is much the same as for the non-expandable case.
% \begin{macrocode}
\cs_new:Npn \@@_expandable_grab_D:nnNNNwN #1#2#3#4#5#6 \q_@@ #7
{
\exp_args:No \tl_if_empty:oTF
{ #3 { \use_none:nnn } #2 \q_@@ #5 #4 \q_@@ #5 }
{
- \@@_put_arg_expandable:ow { \use_none:nn #1#2 }
+ \tl_if_blank:oTF { \use_none:nn #1#2 }
+ { \@@_put_arg_expandable:ow { } }
+ {
+ \str_if_eq_x:nnTF
+ { \exp_not:o { \use_none:nn #1#2 } }
+ { { \exp_not:o { \use_iii:nnnn #1#2 \q_nil } } }
+ { \@@_put_arg_expandable:ow { \use_iii:nnn #1#2 } }
+ { \@@_put_arg_expandable:ow { \use_none:nn #1#2 } }
+ }
#6 \q_@@ #7
}
{
@@ -2709,7 +2742,7 @@
% \begin{macro}[EXP]{\@@_expandable_grab_D_alt:w}
% \begin{macro}[EXP]{\@@_expandable_grab_D_alt:NNnwNn}
% \begin{macro}[EXP]{\@@_expandable_grab_D_alt:Nw}
-% When the delimiters are identical, nesting is not possble and a simplified
+% When the delimiters are identical, nesting is not possible and a simplified
% approach is used. The test concept here is the same as for the case where
% the delimiters are different.
% \begin{macrocode}
@@ -2728,7 +2761,18 @@
{ #4 {#3} \q_@@ #5 {#6} }
}
\cs_new:Npn \@@_expandable_grab_D_alt:Nwn #1#2 \q_@@ #3
- { \@@_put_arg_expandable:ow { \use_none:n #3 } #2 \q_@@ #1 }
+ {
+ \tl_if_blank:oTF { \use_none:nn #1#2 }
+ { \@@_put_arg_expandable:ow { } }
+ {
+ \str_if_eq_x:nnTF
+ { \exp_not:o { \use_none:n #3 } }
+ { { \exp_not:o { \use_ii:nnn #3 \q_nil } } }
+ { \@@_put_arg_expandable:ow { \use_ii:nn #3 } }
+ { \@@_put_arg_expandable:ow { \use_none:n #3 } }
+ }
+ #2 \q_@@ #1
+ }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -3405,19 +3449,29 @@
% \end{macro}
%
% \subsection{Package options}
-%
-% A faked key--value option to keep the log clean. Not yet perfect, but
-% better than nothing.
+%
+% \begin{variable}{\l_@@_options_clist}
+% \begin{variable}{\l_@@_log_bool}
+% Key--value option to log information: done by hand to keep dependencies
+% down.
% \begin{macrocode}
-\DeclareOption { log-declarations = true } { }
-\DeclareOption { log-declarations = false }
+\clist_new:N \l_@@_options_clist
+\DeclareOption* { \clist_put_right:NV \l_@@_options_clist \CurrentOption }
+\ProcessOptions \relax
+\keys_define:nn { xparse }
+ {
+ log-declarations .bool_set:N = \l_@@_log_bool ,
+ log-declarations .initial:n = true
+ }
+\keys_set:nV { xparse } \l_@@_options_clist
+\bool_if:NF \l_@@_log_bool
{
\msg_redirect_module:nnn { LaTeX / xparse } { info } { none }
\msg_redirect_module:nnn { LaTeX / xparse } { warning } { none }
}
-\DeclareOption { log-declarations } { }
-\ProcessOptions \scan_stop:
% \end{macrocode}
+% \end{variable}
+% \end{variable}
%
% \begin{macrocode}
%</package>
diff --git a/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx b/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
index 9f632ae9109..f8467ce2a14 100644
--- a/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
+++ b/Master/texmf-dist/source/latex/l3packages/xtemplate/xtemplate.dtx
@@ -4,7 +4,7 @@
%% David Carlisle
%% (C) Copyright 2004-2010 Frank Mittelbach,
%% The LaTeX3 Project
-%% (C) Copyright 2011,2012 The LaTeX3 Project
+%% (C) Copyright 2011-2013 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
@@ -41,8 +41,8 @@
%<*driver|package>
% The version of expl3 required is tested as early as possible, as
% some really old versions do not define \ProvidesExplPackage.
-\RequirePackage{expl3}[2012/12/21]
-%<package>\@ifpackagelater{expl3}{2012/12/21}
+\RequirePackage{expl3}[2013/03/12]
+%<package>\@ifpackagelater{expl3}{2013/03/12}
%<package> {}
%<package> {%
%<package> \PackageError{xtemplate}{Support package l3kernel too old}
@@ -54,7 +54,7 @@
%<package> }%
%<package> \endinput
%<package> }
-\GetIdInfo$Id: xtemplate.dtx 4390 2012-12-21 06:59:20Z joseph $
+\GetIdInfo$Id: xtemplate.dtx 4467 2013-03-12 08:29:05Z joseph $
{L3 Experimental prototype document functions}
%</driver|package>
%<*driver>