summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3file.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3file.dtx758
1 files changed, 482 insertions, 276 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
index fee42ad5736..6ea0556fab4 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-2016 The LaTeX3 Project
+%% File: l3file.dtx Copyright (C) 1990-2017 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
@@ -24,7 +24,7 @@
\documentclass[full]{l3doc}
%</driver>
%<*driver|package>
-\GetIdInfo$Id: l3file.dtx 6805 2016-12-28 22:15:52Z joseph $
+\GetIdInfo$Id: l3file.dtx 6964 2017-02-20 02:59:41Z bruno $
{L3 File and I/O operations}
%</driver|package>
%<*driver>
@@ -691,9 +691,9 @@
0 \tl_map_function:NN \l_@@_internal_name_tl
\@@_name_sanitize_aux:n
}
- \c_two
+ { 2 }
}
- = \c_zero
+ = 0
{
\tl_remove_all:Nn \l_@@_internal_name_tl { " }
\tl_if_in:NnT \l_@@_internal_name_tl { ~ }
@@ -714,10 +714,7 @@
}
}
\cs_new:Npn \@@_name_sanitize_aux:n #1
- {
- \token_if_eq_charcode:NNT #1 "
- { + \c_one }
- }
+ { \token_if_eq_charcode:NNT #1 " { + 1 } }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -925,7 +922,7 @@
% but non-existent stream number. Unlike writing, there is no concept
% of reading from the log.
% \begin{macrocode}
-\cs_new_eq:NN \c_term_ior \c_sixteen
+\int_const:Nn \c_term_ior { 16 }
% \end{macrocode}
% \end{variable}
%
@@ -964,14 +961,14 @@
\prop_new:N \g_@@_streams_prop
%<*package>
\int_step_inline:nnnn
- { \c_zero }
- { \c_one }
+ { 0 }
+ { 1 }
{
\cs_if_exist:NTF \normalend
{ \tex_count:D 38 \scan_stop: }
{
\tex_count:D 16 \scan_stop:
- \cs_if_exist:NT \loccount { - \c_one }
+ \cs_if_exist:NT \loccount { - 1 }
}
}
{
@@ -1100,7 +1097,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \ior_close:N #1
{
- \int_compare:nT { - \c_one < #1 < \c_sixteen }
+ \int_compare:nT { -1 < #1 < \c_term_ior }
{
\tex_closein:D #1
\prop_gremove:NV \g_@@_streams_prop #1
@@ -1147,21 +1144,23 @@
%
% \begin{macro}[pTF]{\ior_if_eof:N}
% To test if some particular input stream is exhausted the following
-% conditional is provided.
+% conditional is provided. The primitive test can only deal with
+% numbers in the range $[0,15]$ so we catch outliers (they are
+% exhausted).
% \begin{macrocode}
-\prg_new_conditional:Nnn \ior_if_eof:N { p , T , F , TF }
+\prg_new_conditional:Npnn \ior_if_eof:N #1 { p , T , F , TF }
{
\cs_if_exist:NTF #1
{
- \if_int_compare:w #1 = \c_sixteen
- \prg_return_true:
- \else:
- \if_eof:w #1
- \prg_return_true:
- \else:
- \prg_return_false:
- \fi:
- \fi:
+ \int_compare:nTF { -1 < #1 < \c_term_ior }
+ {
+ \if_eof:w #1
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+ { \prg_return_true: }
}
{ \prg_return_true: }
}
@@ -1184,7 +1183,7 @@
{
\use:x
{
- \int_set:Nn \tex_endlinechar:D { - \c_one }
+ \int_set:Nn \tex_endlinechar:D { -1 }
\exp_not:n { \etex_readline:D #1 to #2 }
\int_set:Nn \tex_endlinechar:D { \int_use:N \tex_endlinechar:D }
}
@@ -1213,11 +1212,22 @@
%
% \begin{variable}{\c_log_iow, \c_term_iow}
% Here we allocate two output streams for writing to the transcript
-% file only (\cs{c_log_iow}) and to both the terminal and
-% transcript file (\cs{c_term_iow}).
+% file only (\cs{c_log_iow}) and to both the terminal and transcript
+% file (\cs{c_term_iow}). Recent \LuaTeX{} provide $128$ write
+% streams; we also use \cs{c_term_iow} as the first non-allowed write
+% stream so its value depends on the engine.
% \begin{macrocode}
-\cs_new_eq:NN \c_log_iow \c_minus_one
-\int_const:Nn \c_term_iow { 128 }
+\int_const:Nn \c_log_iow { -1 }
+\int_const:Nn \c_term_iow
+ {
+ \cs_if_exist:NTF \luatex_directlua:D
+ {
+ \int_compare:nNnTF \luatex_luatexversion:D > { 80 }
+ { 128 }
+ { 16 }
+ }
+ { 16 }
+ }
% \end{macrocode}
% \end{variable}
%
@@ -1226,15 +1236,12 @@
% \begin{macrocode}
\seq_new:N \g_@@_streams_seq
%<*initex>
-\seq_set_eq:NN \g_@@_streams_seq \g__ior_streams_seq
-\cs_if_exist:NT \luatex_directlua:D
+\use:x
{
- \int_compare:nNnT \luatex_luatexversion:D > { 80 }
+ \exp_not:n { \seq_gset_split:Nnn \g_@@_streams_seq { } }
{
- \int_step_inline:nnnn { 16 } { 1 } { 127 }
- {
- \seq_gput_right:Nn \g_@@_streams_seq {#1}
- }
+ \int_step_function:nnnN { 0 } { 1 } { \c_term_iow }
+ \prg_do_nothing:
}
}
%</initex>
@@ -1255,14 +1262,14 @@
\prop_new:N \g_@@_streams_prop
%<*package>
\int_step_inline:nnnn
- { \c_zero }
- { \c_one }
+ { 0 }
+ { 1 }
{
\cs_if_exist:NTF \normalend
{ \tex_count:D 39 \scan_stop: }
{
\tex_count:D 17 \scan_stop:
- \cs_if_exist:NT \loccount { - \c_one }
+ \cs_if_exist:NT \loccount { - 1 }
}
}
{
@@ -1339,7 +1346,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \iow_close:N #1
{
- \int_compare:nT { - \c_one < #1 < \c_sixteen }
+ \int_compare:nT { - \c_log_iow < #1 < \c_term_iow }
{
\tex_immediate:D \tex_closeout:D #1
\prop_gremove:NV \g_@@_streams_prop #1
@@ -1386,7 +1393,8 @@
%
% \subsubsection{Immediate writing}
%
-% \begin{macro}[aux]{\@@_with:Nnn, \@@_with_aux:nNnn}
+% \begin{macro}[int]{\@@_with:Nnn}
+% \begin{macro}[aux]{\@@_with_aux:nNnn}
% If the integer~|#1| is equal to~|#2|, just leave~|#3| in the input
% stream. Otherwise, pass the old value to an auxiliary, which sets
% the integer to the new value, runs the code, and restores the
@@ -1406,6 +1414,7 @@
}
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
% \begin{macro}{\iow_now:Nn, \iow_now:Nx, \iow_now:cn, \iow_now:cx}
% This routine writes the second argument onto the output stream without
@@ -1464,7 +1473,14 @@
% used by the messaging system, but is designed such that it is
% available for other uses.
%
-% \begin{macro}[var, added = 2012-06-24]{\l_iow_line_count_int}
+% \begin{macro}{\c_catcode_other_space_tl}
+% Create a space with category code $12$: an \enquote{other} space.
+% \begin{macrocode}
+\tl_const:Nx \c_catcode_other_space_tl { \char_generate:nn { `\ } { 12 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_iow_line_count_int}
% This is the \enquote{raw} number of characters in a line which
% can be written to the terminal.
% The standard value is the line length typically used by
@@ -1473,96 +1489,102 @@
\int_new:N \l_iow_line_count_int
\int_set:Nn \l_iow_line_count_int { 78 }
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
-% \begin{macro}[aux]{\l_@@_target_count_int}
-% This stores the target line count: the full number of characters
-% in a line, minus any part for a leader at the start of each line.
+% \begin{variable}{\l_@@_newline_tl}
+% The token list inserted to produce a new line, with the
+% \meta{run-on text}.
% \begin{macrocode}
-\int_new:N \l_@@_target_count_int
+\tl_new:N \l_@@_newline_tl
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
-% \begin{macro}[aux]
-% {
-% \l_@@_current_line_int,
-% \l_@@_current_word_int,
-% \l_@@_current_indentation_int
-% }
-% These store the number of characters in the line and word currently
-% being constructed, and the current indentation, respectively.
+% \begin{variable}{\l_@@_line_target_int}
+% This stores the target line count: the full number of characters
+% in a line, minus any part for a leader at the start of each line.
% \begin{macrocode}
-\int_new:N \l_@@_current_line_int
-\int_new:N \l_@@_current_word_int
-\int_new:N \l_@@_current_indentation_int
+\int_new:N \l_@@_line_target_int
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
-% \begin{macro}[aux]
-% {
-% \l_@@_current_line_tl,
-% \l_@@_current_word_tl,
-% \l_@@_current_indentation_tl
-% }
-% These hold the current line of text and current word,
-% and a number of spaces for indentation, respectively.
-% \begin{macrocode}
-\tl_new:N \l_@@_current_line_tl
-\tl_new:N \l_@@_current_word_tl
-\tl_new:N \l_@@_current_indentation_tl
+% \begin{macro}[aux]{\@@_set_indent:n}
+% \begin{macro}[aux]{\@@_unindent:w}
+% \begin{variable}{\l_@@_one_indent_tl, \l_@@_one_indent_int}
+% The \texttt{one_indent} variables hold one indentation marker and
+% its length. The \cs{@@_unindent:w} auxiliary removes one
+% indentation. The function \cs{@@_set_indent:n} (that could possibly
+% be public) sets the indentation in a consistent way. We set it to
+% four spaces by default.
+% \begin{macrocode}
+\tl_new:N \l_@@_one_indent_tl
+\int_new:N \l_@@_one_indent_int
+\cs_new:Npn \@@_unindent:w { }
+\cs_new_protected:Npn \@@_set_indent:n #1
+ {
+ \tl_set:Nx \l_@@_one_indent_tl
+ { \exp_args:No \__str_to_other_fast:n { \tl_to_str:n {#1} } }
+ \int_set:Nn \l_@@_one_indent_int { \str_count:N \l_@@_one_indent_tl }
+ \exp_last_unbraced:NNo
+ \cs_set:Npn \@@_unindent:w \l_@@_one_indent_tl { }
+ }
+\exp_args:Nx \@@_set_indent:n { \prg_replicate:nn { 4 } { ~ } }
% \end{macrocode}
-%\end{macro}
+% \end{variable}
+% \end{macro}
+% \end{macro}
%
-% \begin{macro}[aux]{\l_@@_wrap_tl}
-% Used for the expansion step before detokenizing, and for the output
-% from wrapping text: fully expanded and with lines which are not
-% overly long.
+% \begin{variable}{\l_@@_indent_tl, \l_@@_indent_int}
+% The current indentation (some copies of \cs{l_@@_one_indent_tl}) and
+% its number of characters.
% \begin{macrocode}
-\tl_new:N \l_@@_wrap_tl
+\tl_new:N \l_@@_indent_tl
+\int_new:N \l_@@_indent_int
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
-% \begin{macro}[aux]{\l_@@_newline_tl}
-% The token list inserted to produce the new line, with the
-% \meta{run-on text}.
+% \begin{variable}{\l_@@_line_tl, \l_@@_line_part_tl}
+% These hold the current line of text and a partial line to be added
+% to it, respectively.
% \begin{macrocode}
-\tl_new:N \l_@@_newline_tl
+\tl_new:N \l_@@_line_tl
+\tl_new:N \l_@@_line_part_tl
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
-% \begin{macro}[aux]{\l_@@_line_start_bool}
-% Boolean to avoid adding a space at the beginning of forced newlines,
-% and to know when to add the indentation.
+% \begin{variable}{\l_@@_line_break_bool}
+% Indicates whether the line was broken precisely at a chunk boundary.
% \begin{macrocode}
-\bool_new:N \l_@@_line_start_bool
+\bool_new:N \l_@@_line_break_bool
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
-% \begin{macro}{\c_catcode_other_space_tl}
-% Create a space with category code $12$: an \enquote{other} space.
+% \begin{variable}{\l_@@_wrap_tl}
+% Used for the expansion step before detokenizing, and for the output
+% from wrapping text: fully expanded and with lines which are not
+% overly long.
% \begin{macrocode}
-\tl_const:Nx \c_catcode_other_space_tl { \char_generate:nn { `\ } { 12 } }
+\tl_new:N \l_@@_wrap_tl
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
-% \begin{macro}[aux]{\c_@@_wrap_marker_tl}
-% \begin{macro}[aux]
+% \begin{variable}{\c_@@_wrap_marker_tl}
+% \begin{variable}
% {
% \c_@@_wrap_end_marker_tl,
% \c_@@_wrap_newline_marker_tl,
% \c_@@_wrap_indent_marker_tl,
% \c_@@_wrap_unindent_marker_tl
% }
-% Every special action of the wrapping code is preceded by
+% Every special action of the wrapping code is starts with
% the same recognizable string, \cs{c_@@_wrap_marker_tl}.
% Upon seeing that \enquote{word}, the wrapping code reads
% one space-delimited argument to know what operation to
% perform. The setting of \tn{escapechar} here is not
% very important, but makes \cs{c_@@_wrap_marker_tl} look
-% nicer.
+% marginally nicer.
% \begin{macrocode}
\group_begin:
- \int_set:Nn \tex_escapechar:D { - \c_one }
+ \int_set:Nn \tex_escapechar:D { -1 }
\tl_const:Nx \c_@@_wrap_marker_tl
{ \tl_to_str:n { \^^I \^^O \^^W \^^_ \^^W \^^R \^^A \^^P } }
\group_end:
@@ -1571,26 +1593,32 @@
{
\tl_const:cx { c_@@_wrap_ #1 _marker_tl }
{
- \c_catcode_other_space_tl
\c_@@_wrap_marker_tl
- \c_catcode_other_space_tl
#1
\c_catcode_other_space_tl
}
}
% \end{macrocode}
-% \end{macro}
-% \end{macro}
+% \end{variable}
+% \end{variable}
%
% \begin{macro}{\iow_indent:n}
-% \begin{macro}[aux]{\@@_indent:n, \@@_indent_error:n}
-% We give a (protected) error definition to \cs{iow_indent:n}
-% when outside messages. Within wrapped message, it places
-% the instruction for increasing the indentation before its
-% argument, and the instruction for unindenting afterwards.
-% Note that there will be no forced line-break, so the indentation
-% only changes when the next line is started.
-% \begin{macrocode}
+% \begin{macro}[EXP,aux]{\@@_indent:n}
+% \begin{macro}[EXP,aux]{\@@_indent_error:n}
+% We set \cs{iow_indent:n} to produce an error when outside
+% messages. Within wrapped message, it is set to \cs{@@_indent:n} when
+% valid and otherwise to \cs{@@_indent_error:n}. The first places the
+% instruction for increasing the indentation before its argument, and
+% the instruction for unindenting afterwards. The second produces an
+% error expandably. Note that there will be no forced line-break, so
+% the indentation only changes when the next line is started.
+% \begin{macrocode}
+\cs_new_protected:Npn \iow_indent:n #1
+ {
+ \__msg_kernel_error:nnnnn { kernel } { iow-indent }
+ { \iow_wrap:nnnN } { \iow_indent:n } {#1}
+ #1
+ }
\cs_new:Npx \@@_indent:n #1
{
\c_@@_wrap_indent_marker_tl
@@ -1599,36 +1627,28 @@
}
\cs_new:Npn \@@_indent_error:n #1
{
- \__msg_kernel_expandable_error:nn { kernel } { indent-outside-wrapping-code }
+ \__msg_kernel_expandable_error:nnnnn { kernel } { iow-indent }
+ { \iow_wrap:nnnN } { \iow_indent:n } {#1}
#1
}
-\cs_new_protected:Npn \iow_indent:n { \@@_indent_error:n }
% \end{macrocode}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% \begin{macro}{\iow_wrap:nnnN}
% \begin{macro}[aux]{\@@_wrap_set:Nx}
% The main wrapping function works as follows. First give |\\|,
% \verb*|\ | and other formatting commands the correct definition for
-% messages, before fully-expanding the input. In package mode, the
-% expansion uses \LaTeXe{}'s \cs{protect} mechanism. Afterwards, set
-% the newline marker (two assignments to fully expand, then convert
-% to a string) and its length, and initialize some registers.
-% There is then a loop over each word in the input, which will do the
-% actual wrapping. After the loop, the resulting text is passed on to
-% the function which has been given as a post-processor.
-% The argument |#4| is available for additional set up steps for
-% the output. The definition of |\\| and \verb*|\ | use an
-% \enquote{other} space rather than a normal space, because the latter
-% might be absorbed by \TeX{} to end a number or other \texttt{f}-type
-% expansions. The \cs{tl_to_str:N} step converts the \enquote{other}
-% space back to a normal space.
+% messages and perform the given setup~|#3|. The definition of
+% \verb*|\ | uses an \enquote{other} space rather than a normal space,
+% because the latter might be absorbed by \TeX{} to end a number or
+% other \texttt{f}-type expansions.
% \begin{macrocode}
\cs_new_protected:Npn \iow_wrap:nnnN #1#2#3#4
{
\group_begin:
- \int_set:Nn \tex_escapechar:D { - \c_one }
+ \int_set:Nn \tex_escapechar:D { -1 }
\cs_set:Npx \{ { \token_to_str:N \{ }
\cs_set:Npx \# { \token_to_str:N \# }
\cs_set:Npx \} { \token_to_str:N \} }
@@ -1639,48 +1659,39 @@
\cs_set_eq:NN \ \c_catcode_other_space_tl
\cs_set_eq:NN \iow_indent:n \@@_indent:n
#3
-%<*initex>
+% \end{macrocode}
+% Then fully-expand the input: in package mode, the expansion uses
+% \LaTeXe{}'s \cs{protected} mechanism. As soon as the expansion is
+% done, reset \cs{iow_indent:n} to its error definition: it only works
+% in the first argument of \cs{iow_wrap:nnnN}.
+% \begin{macrocode}
+%<*initex>
\tl_set:Nx \l_@@_wrap_tl {#1}
%</initex>
%<*package>
\@@_wrap_set:Nx \l_@@_wrap_tl {#1}
%</package>
+ \cs_set_eq:NN \iow_indent:n \@@_indent_error:n
% \end{macrocode}
-% To warn users that \cs{iow_indent:n} only works in the first argument
-% of \cs{iow_wrap:nnnN} reset \cs{iow_indent:n} to its error
-% definition. Then store a newline character and the run-on text as a
-% string in \cs{l_@@_newline_tl}, and set some variables. The first
-% line's target count is equal to the length of the whole line. The
-% value \cs{l_@@_target_count_int} is altered later on by
-% \cs{@@_wrap_set_target:}.
+% Afterwards, set the newline marker (two assignments to fully expand,
+% then convert to a string) and initialize the target count for lines
+% (the first line has target count \cs{l_iow_line_count_int} instead).
% \begin{macrocode}
- \cs_set_eq:NN \iow_indent:n \@@_indent_error:n
\tl_set:Nx \l_@@_newline_tl { \iow_newline: #2 }
\tl_set:Nx \l_@@_newline_tl { \tl_to_str:N \l_@@_newline_tl }
- \int_set_eq:NN \l_@@_target_count_int \l_iow_line_count_int
- \tl_clear:N \l_@@_current_indentation_tl
- \int_zero:N \l_@@_current_line_int
- \tl_set:Nn \l_@@_current_line_tl { \use_none:n }
- \bool_set_true:N \l_@@_line_start_bool
-% \end{macrocode}
-% After some setup above (in particular the odd setting of the current line
-% to \cs{use_none:n}), a loop goes through space-delimited words in the
-% message, recognizing special markers. To make sure that the first line
-% behaves identically to others, start with a newline marker: the
-% \cs{use_none:n} above avoids actually getting a new line in the output.
-% \begin{macrocode}
- \use:x
- {
- \exp_not:n { \tl_clear:N \l_@@_wrap_tl }
- \@@_wrap_loop:w
- \tl_to_str:N \c_@@_wrap_newline_marker_tl
- \tl_to_str:N \l_@@_wrap_tl
- \tl_to_str:N \c_@@_wrap_end_marker_tl
- \c_space_tl \c_space_tl
- \exp_not:N \q_stop
- }
- \exp_args:NNo \group_end:
- #4 \l_@@_wrap_tl
+ \int_set:Nn \l_@@_line_target_int
+ { \l_iow_line_count_int - \str_count:N \l_@@_newline_tl + 1 }
+% \end{macrocode}
+% There is then a loop over the input, which will store the wrapped
+% result in \cs{l_@@_wrap_tl}. After the loop, the resulting text is
+% passed on to the function which has been given as a post-processor.
+% The \cs{tl_to_str:N} step converts the \enquote{other} spaces back
+% to normal spaces. The \texttt{f}-expansion removes a leading space
+% from \cs{l_@@_wrap_tl}.
+% \begin{macrocode}
+ \@@_wrap_do:
+ \exp_args:NNf \group_end:
+ #4 { \tl_to_str:N \l_@@_wrap_tl }
}
% \end{macrocode}
% As using the generic loader will mean that \cs{protected@edef} is
@@ -1694,160 +1705,342 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}[aux]{\@@_wrap_set_target:}
-% This is called at the beginning of every line (both those forced by
-% |\\| and those due to line-breaking). The initial call does
-% nothing except redefine \cs{@@_wrap_set_target:} itself (within the
-% group in which \cs{iow_wrap:nnnN} works). The next call (at the
-% beginning of the second line) disables any later call and sets the
-% \cs{l_@@_target_count_int} to the correct value, namely the
-% \cs{l_iow_line_count_int} shortened by the length of the run-on
-% text (the shift by~$1$ is due to the presence of \cs{iow_newline:}
-% in \cs{l_@@_newline_tl}).
-% This is a bit of a hack to measure the string length of the run on text
-% without the \pkg{l3str} module (which is still experimental). This should
-% be replaced once the string module is finalised with something a little
-% cleaner.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_wrap_set_target:
+% \begin{macro}[aux]{\@@_wrap_do:, \@@_wrap_start:w}
+% Escape spaces. Set up a few variables, in particular the initial
+% value of \cs{l_@@_wrap_tl}: the space will stop the
+% \texttt{f}-expansion of the main wrapping function and
+% \cs{use_none:n} will remove a newline marker inserted by later code.
+% The main loop consists of repeatedly calling the \texttt{chunk}
+% auxiliary to wrap chunks delimited by (newline or indentation)
+% markers.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_wrap_do:
{
- \cs_set_protected:Npn \@@_wrap_set_target:
+ \tl_set:Nx \l_@@_wrap_tl
{
- \cs_set_protected:Npn \@@_wrap_set_target: { }
- \tl_replace_all:Nnn \l_@@_newline_tl { ~ } { \c_space_tl }
- \int_set:Nn \l_@@_target_count_int
- { \l_iow_line_count_int - \tl_count:N \l_@@_newline_tl + \c_one }
+ \exp_args:No \__str_to_other_fast:n \l_@@_wrap_tl
+ \c_@@_wrap_end_marker_tl
}
+ \exp_after:wN \@@_wrap_start:w \l_@@_wrap_tl
+ }
+\cs_new_protected:Npn \@@_wrap_start:w
+ {
+ \bool_set_false:N \l_@@_line_break_bool
+ \tl_clear:N \l_@@_line_tl
+ \tl_clear:N \l_@@_line_part_tl
+ \tl_set:Nn \l_@@_wrap_tl { ~ \use_none:n }
+ \int_zero:N \l_@@_indent_int
+ \tl_clear:N \l_@@_indent_tl
+ \@@_wrap_chunk:nw { \l_iow_line_count_int }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\@@_wrap_loop:w}
-% The loop grabs one word in the input, and checks whether it is
-% the special marker, or a normal word.
+% \begin{macro}[aux]{\@@_wrap_chunk:nw, \@@_wrap_next:nw}
+% The \texttt{chunk} and \texttt{next} auxiliaries are defined
+% indirectly to obtain the expansions of \cs{c_catcode_other_space_tl}
+% and \cs{c_@@_wrap_marker_tl} in their definition. The \texttt{next}
+% auxiliary calls a function corresponding to the type of marker (its
+% |##2|), which can be \texttt{newline} or \texttt{indent} or
+% \texttt{unindent} or \texttt{end}. The first argument of the
+% \texttt{chunk} auxiliary is a target number of characters and the
+% second is some string to wrap. If the chunk is empty simply call
+% \texttt{next}. Otherwise, set up a call to \cs{@@_wrap_line:nw},
+% including the indentation if the current line is empty, and
+% including a trailing space (|#1|) before the
+% \cs{@@_wrap_end_chunk:w} auxiliary.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_wrap_loop:w #1 ~ %
+\cs_set_protected:Npn \@@_tmp:w #1#2
{
- \tl_set:Nn \l_@@_current_word_tl {#1}
- \tl_if_eq:NNTF \l_@@_current_word_tl \c_@@_wrap_marker_tl
- { \@@_wrap_special:w }
- { \@@_wrap_word: }
+ \cs_new_protected:Npn \@@_wrap_chunk:nw ##1##2 #2
+ {
+ \tl_if_empty:nTF {##2}
+ {
+ \tl_clear:N \l_@@_line_part_tl
+ \@@_wrap_next:nw {##1}
+ }
+ {
+ \tl_if_empty:NTF \l_@@_line_tl
+ {
+ \@@_wrap_line:nw
+ { \l_@@_indent_tl }
+ ##1 - \l_@@_indent_int ;
+ }
+ { \@@_wrap_line:nw { } ##1 ; }
+ ##2 #1
+ \@@_wrap_end_chunk:w 7 6 5 4 3 2 1 0 \q_stop
+ }
+ }
+ \cs_new_protected:Npn \@@_wrap_next:nw ##1##2 #1
+ { \use:c { @@_wrap_##2:n } {##1} }
}
+\exp_args:NVV \@@_tmp:w \c_catcode_other_space_tl \c_@@_wrap_marker_tl
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\@@_wrap_word:}
-% \begin{macro}[aux]{\@@_wrap_word_fits:}
-% \begin{macro}[aux]{\@@_wrap_word_newline:}
-% For a normal word, update the line count, then test if the current
-% word would fit in the current line, and call the appropriate function.
-% If the word fits in the current line, add it to the line, preceded by
-% a space unless it is the first word of the line.
-% Otherwise, the current line is added to the result, with the run-on text.
-% The current word (and its character count) are then put in the new line.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_wrap_word:
+% \begin{macro}[aux]{\@@_wrap_line:nw}
+% \begin{macro}[EXP,aux]
+% {
+% \@@_wrap_line_loop:w,
+% \@@_wrap_line_aux:Nw,
+% \@@_wrap_line_end:NnnnnnnnN,
+% \@@_wrap_line_end:nw,
+% \@@_wrap_end_chunk:w
+% }
+% This is followed by \Arg{string} \meta{intexpr} |;|. It stores the
+% \meta{string} and up to \meta{intexpr} characters from the current
+% chunk into \cs{l_@@_line_part_tl}. Characters are grabbed 8~at a
+% time and left in \cs{l_@@_line_part_tl} by the \texttt{line_loop}
+% auxiliary. When $k<8$ remain to be found, the \texttt{line_aux}
+% auxiliary calls the \texttt{line_end} auxiliary followed by (the
+% single digit) $k$, then $7-k$ empty brace groups, then the chunk's
+% remaining characters. The \texttt{line_end} auxiliary leaves
+% $k$~characters from the chunk in the line part, then ends the
+% assignment. Ignore the \cs{use_none:nnnnn} line for now. If the
+% next character is a space the line can be broken there:
+% store what we found into the result and get the next line.
+% Otherwise some work is needed to find a break-point. So far we have
+% ignored what happens if the chunk is shorter than the requested
+% number of characters: this is dealt with by the \texttt{end_chunk}
+% auxiliary, which gets treated like a character by the rest of the
+% code. It ends up being called either as one of the arguments
+% |#2|--|#9| of the \texttt{line_loop} auxiliary or as one of the
+% arguments |#2|--|#8| of the \texttt{line_end} auxiliary. In both
+% cases stop the assignment and work out how many characters are still
+% needed. The weird \cs{use_none:nnnnn} ensures that the required
+% data is in the right place.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_wrap_line:nw #1
+ {
+ \tex_edef:D \l_@@_line_part_tl { \if_false: } \fi:
+ #1
+ \exp_after:wN \@@_wrap_line_loop:w
+ \__int_value:w \__int_eval:w
+ }
+\cs_new:Npn \@@_wrap_line_loop:w #1 ; #2#3#4#5#6#7#8#9
+ {
+ \if_int_compare:w #1 < 8 \exp_stop_f:
+ \@@_wrap_line_aux:Nw #1
+ \fi:
+ #2 #3 #4 #5 #6 #7 #8 #9
+ \exp_after:wN \@@_wrap_line_loop:w
+ \__int_value:w \__int_eval:w #1 - 8 ;
+ }
+\cs_new:Npn \@@_wrap_line_aux:Nw #1#2#3 \exp_after:wN #4 ;
+ {
+ #2
+ \exp_after:wN \@@_wrap_line_end:NnnnnnnnN
+ \exp_after:wN #1
+ \exp:w \exp_end_continue_f:w
+ \exp_after:wN \exp_after:wN
+ \if_case:w #1 \exp_stop_f:
+ \prg_do_nothing:
+ \or: \use_none:n
+ \or: \use_none:nn
+ \or: \use_none:nnn
+ \or: \use_none:nnnn
+ \or: \use_none:nnnnn
+ \or: \use_none:nnnnnn
+ \or: \use_none:nnnnnnn
+ \fi:
+ { } { } { } { } { } { } { } #3
+ }
+\cs_new:Npn \@@_wrap_line_end:NnnnnnnnN #1#2#3#4#5#6#7#8#9
+ {
+ #2 #3 #4 #5 #6 #7 #8
+ \use_none:nnnnn \__int_eval:w 8 - ; #9
+ \token_if_eq_charcode:NNTF \c_space_token #9
+ { \@@_wrap_line_end:nw { } }
+ { \if_false: { \fi: } \@@_wrap_break:w #9 }
+ }
+\cs_new:Npn \@@_wrap_line_end:nw #1
+ {
+ \if_false: { \fi: }
+ \@@_wrap_store_do:n {#1}
+ \@@_wrap_next_line:w
+ }
+\cs_new:Npn \@@_wrap_end_chunk:w
+ #1 \__int_eval:w #2 - #3 ; #4#5 \q_stop
{
- \int_set:Nn \l_@@_current_word_int
- { \exp_args:No \str_count_ignore_spaces:n \l_@@_current_word_tl }
- \int_add:Nn \l_@@_current_line_int { \l_@@_current_word_int }
- \int_compare:nNnTF \l_@@_current_line_int < \l_@@_target_count_int
- { \@@_wrap_word_fits: }
- { \@@_wrap_word_newline: }
- \@@_wrap_loop:w
+ \if_false: { \fi: }
+ \exp_args:Nf \@@_wrap_next:nw { \int_eval:n { #2 - #4 } }
}
-\cs_new_protected:Npn \@@_wrap_word_fits:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP,aux]{\@@_wrap_break:w}
+% \begin{macro}[EXP,aux]
+% {
+% \@@_wrap_break_first:w,
+% \@@_wrap_break_none:w,
+% \@@_wrap_break_loop:w,
+% \@@_wrap_break_end:w,
+% }
+% Functions here are defined indirectly: \cs{@@_tmp:w} is eventually
+% called with an \enquote{other} space as its argument. The goal is
+% to remove from \cs{l_@@_line_part_tl} the part after the last space.
+% In most cases this is done by repeatedly calling the
+% \texttt{break_loop} auxiliary, which leaves \enquote{words}
+% (delimited by spaces) until it hits the trailing space: then its
+% argument |##3| is |?| \cs{@@_wrap_break_end:w} instead of a single
+% token, and that \texttt{break_end} auxiliary leaves in the
+% assignment the line until the last space, then calls
+% \cs{@@_wrap_line_end:nw} to finish up the line and move on to the
+% next. If there is no space in \cs{l_@@_line_part_tl} then the
+% \texttt{break_first} auxiliary calls the \texttt{break_none}
+% auxiliary. In that case, if the current line is empty, the complete
+% word (including |##4|, characters beyond what we had grabbed) is
+% added to the line, making it over-long. Otherwise, the word will be
+% used for the following line (and the last space of the line so far
+% is removed because it was inserted due to the presence of a marker).
+% \begin{macrocode}
+\cs_set_protected:Npn \@@_tmp:w #1
{
- \bool_if:NTF \l_@@_line_start_bool
+ \cs_new:Npn \@@_wrap_break:w
{
- \bool_set_false:N \l_@@_line_start_bool
- \tl_put_right:Nx \l_@@_current_line_tl
- { \l_@@_current_indentation_tl \l_@@_current_word_tl }
- \int_add:Nn \l_@@_current_line_int
- { \l_@@_current_indentation_int }
+ \tex_edef:D \l_@@_line_part_tl
+ { \if_false: } \fi:
+ \exp_after:wN \@@_wrap_break_first:w
+ \l_@@_line_part_tl
+ #1
+ { ? \@@_wrap_break_end:w }
+ \q_mark
}
+ \cs_new:Npn \@@_wrap_break_first:w ##1 #1 ##2
{
- \tl_put_right:Nx \l_@@_current_line_tl
- { ~ \l_@@_current_word_tl }
- \int_incr:N \l_@@_current_line_int
+ \use_none:nn ##2 \@@_wrap_break_none:w
+ \@@_wrap_break_loop:w ##1 #1 ##2
}
- }
-\cs_new_protected:Npn \@@_wrap_word_newline:
- {
- \@@_wrap_set_target:
- \tl_put_right:Nx \l_@@_wrap_tl
- { \l_@@_current_line_tl \l_@@_newline_tl }
- \int_set:Nn \l_@@_current_line_int
+ \cs_new:Npn \@@_wrap_break_none:w ##1##2 #1 ##3 \q_mark ##4 #1
{
- \l_@@_current_word_int
- + \l_@@_current_indentation_int
+ \tl_if_empty:NTF \l_@@_line_tl
+ { ##2 ##4 \@@_wrap_line_end:nw { } }
+ { \@@_wrap_line_end:nw { \@@_wrap_trim:N } ##2 ##4 #1 }
}
- \tl_set:Nx \l_@@_current_line_tl
- { \l_@@_current_indentation_tl \l_@@_current_word_tl }
+ \cs_new:Npn \@@_wrap_break_loop:w ##1 #1 ##2 #1 ##3
+ {
+ \use_none:n ##3
+ ##1 #1
+ \@@_wrap_break_loop:w ##2 #1 ##3
+ }
+ \cs_new:Npn \@@_wrap_break_end:w ##1 #1 ##2 ##3 #1 ##4 \q_mark
+ { ##1 \@@_wrap_line_end:nw { } ##3 }
}
+\exp_args:NV \@@_tmp:w \c_catcode_other_space_tl
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}[aux]{\@@_wrap_special:w}
-% \begin{macro}[aux]{\@@_wrap_newline:w}
-% \begin{macro}[aux]{\@@_wrap_indent:w}
-% \begin{macro}[aux]{\@@_wrap_unindent:w}
-% \begin{macro}[aux]{\@@_wrap_end:w}
-% When the \enquote{special} marker is encountered,
-% read what operation to perform, as a space-delimited
-% argument, perform it, and remember to loop.
-% In fact, to avoid spurious spaces when two special
-% actions follow each other, we look ahead for another
-% copy of the marker.
-% Forced newlines are almost identical to those caused by overflow,
-% except that here the word is empty.
-% To indent more, add four spaces to the start of the indentation
-% token list. To reduce indentation, rebuild the indentation token
-% list using \cs{prg_replicate:nn}.
-% At the end, we simply save the last line (without the run-on text),
-% and prevent the loop.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_wrap_special:w #1 ~ #2 ~ #3 ~ %
+% \begin{macro}[aux]{\@@_wrap_next_line:w}
+% The special case where the end of a line coincides with the end of a
+% chunk is detected here, to avoid a spurious empty line. Otherwise,
+% call \cs{@@_wrap_line:nw} to find characters for the next line
+% (remembering to account for the indentation).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_wrap_next_line:w #1#2 \q_stop
{
- \use:c { @@_wrap_#1: }
- \str_if_eq_x:nnTF { #2~#3 } { ~ \c_@@_wrap_marker_tl }
- { \@@_wrap_special:w }
- { \@@_wrap_loop:w #2 ~ #3 ~ }
+ \tl_clear:N \l_@@_line_tl
+ \token_if_eq_meaning:NNTF #1 \@@_wrap_end_chunk:w
+ {
+ \tl_clear:N \l_@@_line_part_tl
+ \bool_set_true:N \l_@@_line_break_bool
+ \@@_wrap_next:nw { \l_@@_line_target_int }
+ }
+ {
+ \@@_wrap_line:nw
+ { \l_@@_indent_tl }
+ \l_@@_line_target_int - \l_@@_indent_int ;
+ #1 #2 \q_stop
+ }
}
-\cs_new_protected:Npn \@@_wrap_newline:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_wrap_indent:, \@@_wrap_unindent:}
+% These functions are called after a chunk has been wrapped, when
+% encountering \texttt{indent}/\texttt{unindent} markers. Add the
+% line part (last line part of the previous chunk) to the line so far
+% and reset a boolean denoting the presence of a line-break. Most
+% importantly, add or remove one indent from the current indent (both
+% the integer and the token list). Finally, continue wrapping.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_wrap_indent:n #1
{
- \@@_wrap_set_target:
- \tl_put_right:Nx \l_@@_wrap_tl
- { \l_@@_current_line_tl \l_@@_newline_tl }
- \int_zero:N \l_@@_current_line_int
- \tl_clear:N \l_@@_current_line_tl
- \bool_set_true:N \l_@@_line_start_bool
+ \tl_put_right:Nx \l_@@_line_tl { \l_@@_line_part_tl }
+ \bool_set_false:N \l_@@_line_break_bool
+ \int_add:Nn \l_@@_indent_int { \l_@@_one_indent_int }
+ \tl_put_right:No \l_@@_indent_tl { \l_@@_one_indent_tl }
+ \@@_wrap_chunk:nw {#1}
}
-\cs_new_protected:Npx \@@_wrap_indent:
+\cs_new_protected:Npn \@@_wrap_unindent:n #1
{
- \int_add:Nn \l_@@_current_indentation_int \c_four
- \tl_put_right:Nx \exp_not:N \l_@@_current_indentation_tl
- { \c_space_tl \c_space_tl \c_space_tl \c_space_tl }
+ \tl_put_right:Nx \l_@@_line_tl { \l_@@_line_part_tl }
+ \bool_set_false:N \l_@@_line_break_bool
+ \int_sub:Nn \l_@@_indent_int { \l_@@_one_indent_int }
+ \tl_set:Nx \l_@@_indent_tl
+ { \exp_after:wN \@@_unindent:w \l_@@_indent_tl }
+ \@@_wrap_chunk:nw {#1}
}
-\cs_new_protected:Npn \@@_wrap_unindent:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_wrap_newline:, \@@_wrap_end:}
+% These functions are called after a chunk has been line-wrapped, when
+% encountering a \texttt{newline}/\texttt{end} marker. Unless we just
+% took a line-break, store the line part and the line so far into the
+% whole \cs{l_@@_wrap_tl}, trimming a trailing space. In the
+% \texttt{newline} case look for a new line (of length
+% \cs{l_@@_line_target_int}) in a new chunk.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_wrap_newline:n #1
{
- \int_sub:Nn \l_@@_current_indentation_int \c_four
- \tl_set:Nx \l_@@_current_indentation_tl
- { \prg_replicate:nn \l_@@_current_indentation_int { ~ } }
+ \bool_if:NF \l_@@_line_break_bool
+ { \@@_wrap_store_do:n { \@@_wrap_trim:N } }
+ \bool_set_false:N \l_@@_line_break_bool
+ \@@_wrap_chunk:nw { \l_@@_line_target_int }
}
-\cs_new_protected:Npn \@@_wrap_end:
+\cs_new_protected:Npn \@@_wrap_end:n #1
{
- \tl_put_right:Nx \l_@@_wrap_tl
- { \l_@@_current_line_tl }
- \use_none_delimit_by_q_stop:w
+ \bool_if:NF \l_@@_line_break_bool
+ { \@@_wrap_store_do:n { \@@_wrap_trim:N } }
+ \bool_set_false:N \l_@@_line_break_bool
}
% \end{macrocode}
% \end{macro}
+%
+% \begin{macro}[aux]{\@@_wrap_store_do:n}
+% First add the last line part to the line, then append it to
+% \cs{l_@@_wrap_tl} with the appropriate new line (with
+% \enquote{run-on} text), possibly with its last space removed (|#1|
+% is empty or \cs{@@_wrap_trim:N}).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_wrap_store_do:n #1
+ {
+ \tl_set:Nx \l_@@_line_tl
+ { \l_@@_line_tl \l_@@_line_part_tl }
+ \tl_set:Nx \l_@@_wrap_tl
+ {
+ \l_@@_wrap_tl
+ \l_@@_newline_tl
+ #1 \l_@@_line_tl
+ }
+ \tl_clear:N \l_@@_line_tl
+ }
+% \end{macrocode}
% \end{macro}
-% \end{macro}
-% \end{macro}
+%
+% \begin{macro}[EXP, aux]{\@@_wrap_trim:N, \@@_wrap_trim:w}
+% Remove one trailing \enquote{other} space from the argument.
+% \begin{macrocode}
+\cs_set_protected:Npn \@@_tmp:w #1
+ {
+ \cs_new:Npn \@@_wrap_trim:N ##1
+ { \tl_if_empty:NF ##1 { \exp_after:wN \@@_wrap_trim:w ##1 \q_stop } }
+ \cs_new:Npn \@@_wrap_trim:w ##1 #1 \q_stop {##1}
+ }
+\exp_args:NV \@@_tmp:w \c_catcode_other_space_tl
+% \end{macrocode}
% \end{macro}
%
% \subsection{Messages}
@@ -1878,8 +2071,13 @@
{
File~names~must~contain~balanced~numbers~of~quotes~(").
}
-\__msg_kernel_new:nnn { kernel } { indent-outside-wrapping-code }
- { Only~\iow_wrap:nnnN~(arg~1)~allows~\iow_indent:n }
+\__msg_kernel_new:nnnn { kernel } { iow-indent }
+ { Only~#1 (arg~1)~allows~#2 }
+ {
+ The~command~#2 can~only~be~used~in~messages~
+ which~will~be~wrapped~using~#1.~
+ It~was~called~with~argument~'#3'.
+ }
% \end{macrocode}
%
% \subsection{Deprecated functions}
@@ -1887,7 +2085,15 @@
% \begin{macro}[added = 2012-06-24, updated = 2012-07-31, deprecated=2017-12-31]{\ior_get_str:NN}
% For removal after 2017-12-31.
% \begin{macrocode}
-\cs_new_eq:NN \ior_get_str:NN \ior_str_get:NN
+\cs_new_protected:Npn \ior_get_str:NN
+ {
+ \__msg_kernel_warning:nnxxx { kernel } { deprecated-command }
+ { 2017-12-31 }
+ { \token_to_str:N \ior_get_str:NN }
+ { \token_to_str:N \ior_str_get:NN }
+ \cs_gset_eq:NN \ior_get_str:NN \ior_str_get:NN
+ \ior_str_get:NN
+ }
% \end{macrocode}
% \end{macro}
%