diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3io.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3io.dtx | 379 |
1 files changed, 262 insertions, 117 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3io.dtx b/Master/texmf-dist/source/latex/l3kernel/l3io.dtx index e406ab611a0..b31b0a3f8c3 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3io.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3io.dtx @@ -35,7 +35,7 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3io.dtx 2799 2011-09-10 15:46:33Z will $ +\GetIdInfo$Id: l3io.dtx 2896 2011-10-09 20:36:50Z joseph $ {L3 Experimental input-output operations} %</driver|package> %<*driver> @@ -86,9 +86,21 @@ % and is independent of the name of the file (except of course that % the file name is needed when the file is opened). % -% \section{Opening and closing streams} +% \section{Managing streams} +% +% \begin{function}[added = 2011-09-26] +% {\ior_new:N, \ior_new:c, \iow_new:N, \io_new:c} +% \begin{syntax} +% \cs{ior_new:Nn} \meta{stream} +% \end{syntax} +% Globally reserves the name of the \meta{stream}, either for reading +% or for writing as appropriate. The \meta{stream} is not opened until the +% appropriate \cs{\ldots_open:Nn} function is used. Attempting to use +% a \meta{stream} which has not been opened will result in a \TeX{} +% error. +% \end{function} % -% \begin{function}{\ior_open:Nn, \ior_open:cn} +% \begin{function}[updated = 2011-09-26]{\ior_open:Nn, \ior_open:cn} % \begin{syntax} % \cs{ior_open:Nn} \meta{stream} \Arg{file name} % \end{syntax} @@ -100,7 +112,7 @@ % is given or the file ends. % \end{function} % -% \begin{function}{\iow_open:Nn, \iow_open:cn} +% \begin{function}[updated = 2011-09-26]{\iow_open:Nn, \iow_open:cn} % \begin{syntax} % \cs{iow_open:Nn} \meta{stream} \Arg{file name} % \end{syntax} @@ -114,26 +126,22 @@ % additive). % \end{function} % -% \begin{function}{\ior_close:N, \ior_close:c} +% \begin{function}[updated = 2011-09-26]{\ior_close:N, \ior_close:c} % \begin{syntax} % \cs{ior_close:N} \meta{stream} % \end{syntax} % Closes the \meta{stream}. Streams should always be closed when % they are finished with as this ensures that they remain available -% to other programmer. The name of the \meta{stream} will be freed at -% this stage, to ensure that any further attempts to read from it results -% in an error. +% to other programmer. % \end{function} % -% \begin{function}{\iow_close:N, \iow_close:c} +% \begin{function}[updated = 2011-09-26]{\iow_close:N, \iow_close:c} % \begin{syntax} % \cs{iow_close:N} \meta{stream} % \end{syntax} % Closes the \meta{stream}. Streams should always be closed when % they are finished with as this ensures that they remain available -% to other programmer. The name of the \meta{stream} will be freed at -% this stage, to ensure that any further attempts to write to it results -% in an error. +% to other programmer. % \end{function} % % \begin{function}{\ior_list_streams:, \iow_list_streams:} @@ -237,7 +245,7 @@ % % \section{Wrapping lines in output} % -% \begin{function}[updated = 2011-06-03]{\iow_wrap:xnnnN} +% \begin{function}[updated = 2011-09-21]{\iow_wrap:xnnnN} % \begin{syntax} % \cs{iow_wrap:xnnnN} \Arg{text} \Arg{run-on text} \Arg{run-on length} \Arg{set up} \meta{function} % \end{syntax} @@ -251,9 +259,17 @@ % before the wrapping takes place. The result of the wrapping operation % is passed as a braced argument to the \meta{function}, which will % typically be a wrapper around a writing operation. Within the -% \meta{text}, |\\| may be used to force a new line and \verb|\ | may be -% used to represent a forced space (for example after a control -% sequence). Both the wrapping process and the subsequent write operation +% \meta{text}, +% \begin{itemize} +% \item |\\| may be used to force a new line, +% \item \verb|\ | may be used to represent a forced space +% (for example after a control sequence), +% \item |\#|, |\%|, |\{|, |\}|, |\~| may be used to represent +% the corresponding character, +% \item \cs{iow_indent:n} may be used to indent a part of the +% message. +% \end{itemize} +% Both the wrapping process and the subsequent write operation % will perform \texttt{x}-type expansion. For this reason, material which % is to be written \enquote{as is} should be given as the argument to % \cs{token_to_str:N} or \cs{tl_to_str:n} (as appropriate) within @@ -263,6 +279,18 @@ % output will \emph{not} expand further when written to a file. % \end{function} % +% \begin{function}[added = 2011-09-21]{\iow_indent:n} +% \begin{syntax} +% \cs{iow_indent:n} \Arg{text} +% \end{syntax} +% In the context of \cs{iow_wrap:xnnnN} (for instance in messages), +% indents \meta{text} by four spaces. This function will not cause +% a line break, and only affects lines which start within the scope +% of the \meta{text}. In case the indented \meta{text} should appear +% on separate lines from the surrounding text, use |\\| to force +% line breaks. +% \end{function} +% % \begin{variable}{\l_iow_line_length_int} % The maximum length of a line to be written by the \cs{iow_wrap:xxnnN} % function. This value depends on the \TeX{} system in use: the standard @@ -345,7 +373,7 @@ % \end{texnote} % \end{function} % -%\begin{function}[EXP,pTF]{\ior_if_eof:N} +%\begin{function}[updated = 2011-09-26, EXP,pTF]{\ior_if_eof:N} % \begin{syntax} % \cs{ior_if_eof_p:N} \meta{stream} \\ % \cs{ior_if_eof:NTF} \meta{stream} \Arg{true code} \Arg{false code} @@ -512,6 +540,21 @@ % \end{macrocode} % \end{macro} % \end{macro} +% +% \begin{macro}{\ior_new:N, \ior_new:c, \iow_new:N, \iow_new:c} +% Reserving a new stream is done by defining the stream as the $16$ (which +% must be in error). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_new:N #1 + { + \chk_if_free_cs:N #1 + \tex_global:D \tex_chardef:D #1 16 ~ + } +\cs_new_eq:NN \iow_new:N \ior_new:N +\cs_generate_variant:Nn \ior_new:N { c } +\cs_generate_variant:Nn \iow_new:N { c } +% \end{macrocode} +% \end{macro} % % \begin{macro}{\ior_open:Nn, \ior_open:cn} % \begin{macro}{\iow_open:Nn, \iow_open:cn} @@ -690,9 +733,10 @@ { \int_compare:nNnF #1 = \c_minus_one { - \tex_closein:D #1 + \int_compare:nNnF #1 = \c_sixteen + { \tex_closein:D #1 } \prop_gdel:NV \g_ior_streams_prop #1 - \cs_undefine:N #1 + \tex_global:D \tex_chardef:D #1 16 ~ } } } @@ -702,9 +746,10 @@ { \int_compare:nNnF #1 = \c_minus_one { - \tex_immediate:D \tex_closeout:D #1 + \int_compare:nNnF #1 = \c_sixteen + { \tex_closein:D #1 } \prop_gdel:NV \g_iow_streams_prop #1 - \cs_undefine:N #1 + \tex_global:D \tex_chardef:D #1 16 ~ } } } @@ -842,6 +887,23 @@ % \end{macrocode} % \end{macro} % +% \subsection{Special characters for writing} +% +% \begin{macro}{\iow_newline:} +% Global variable holding the character that forces a new line when +% something is written to an output stream +% \begin{macrocode} +\cs_new_nopar:Npn \iow_newline: { ^^J } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\iow_char:N} +% Function to write any escaped char to an output stream. +% \begin{macrocode} +\cs_new_eq:NN \iow_char:N \cs_to_str:N +% \end{macrocode} +% \end{macro} +% % \subsection{Hard-wrapping lines based on length} % % The code here implements a generic hard-wrapping function. This is @@ -849,7 +911,7 @@ % available for other uses. % % \begin{macro}{\l_iow_line_length_int} -% The is the \enquote{raw} length of a line which can be written to +% The is the \enquote{raw} length of a line which can be written to a % file. The standard value is the line length typically used by % \TeX{}Live and Mik\TeX{}. % \begin{macrocode} @@ -866,20 +928,29 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\l_iow_current_line_int, \l_iow_current_word_int} +% \begin{macro}[aux]{ +% \l_iow_current_line_int, +% \l_iow_current_word_int, +% \l_iow_current_indentation_int} % These store the number of characters in the line and word currently -% being constructed, respectively. +% being constructed, and the current indentation, respectively. % \begin{macrocode} \int_new:N \l_iow_current_line_int \int_new:N \l_iow_current_word_int +\int_new:N \l_iow_current_indentation_int % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\l_iow_current_line_tl, \l_iow_current_word_tl} -% These hold the current line of text and current word, respectively. +% \begin{macro}[aux]{ +% \l_iow_current_line_tl, +% \l_iow_current_word_tl, +% \l_iow_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_iow_current_line_tl \tl_new:N \l_iow_current_word_tl +\tl_new:N \l_iow_current_indentation_tl % \end{macrocode} %\end{macro} % @@ -898,21 +969,14 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\q_iow_stop} -% A quark which will not appear elsewhere. -% \begin{macrocode} -\quark_new:N \q_iow_stop -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\l_iow_line_start_bool} -% Boolean to avoid adding a space at the beginning of lines. +% \begin{macro}[aux]{\l_iow_line_start_bool} +% Boolean to avoid adding a space at the beginning of forced newlines. % \begin{macrocode} \bool_new:N \l_iow_line_start_bool % \end{macrocode} % \end{macro} % -% \begin{macro}{\c_catcode_other_space_tl} +% \begin{macro}[aux]{\c_catcode_other_space_tl} % Lowercase a character with category code $12$ to produce an % \enquote{other} space. We can do everything within the group, % because \cs{tl_const:Nn} defines its argument globally. @@ -925,13 +989,68 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[aux]{\c_iow_wrap_marker_tl} +% \begin{macro}[aux]{ +% \c_iow_wrap_end_marker_tl, +% \c_iow_wrap_newline_marker_tl, +% \c_iow_wrap_indent_marker_tl, +% \c_iow_wrap_unindent_marker_tl} +% \begin{macro}[aux]{\iow_wrap_new_marker:n} +% Every special action of the wrapping code is preceeded by +% the same recognizable string, \cs{c_iow_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_iow_wrap_marker_tl} look +% nicer. Note that \cs{iow_wrap_new_marker:n} does not +% survive the group, but all constants are defined globally. +% \begin{macrocode} +\group_begin: + \int_set_eq:NN \tex_escapechar:D \c_minus_one + \tl_const:Nx \c_iow_wrap_marker_tl + { \tl_to_str:n { \^^I \^^O \^^W \^^_ \^^W \^^R \^^A \^^P } } + \cs_set:Npn \iow_wrap_new_marker:n #1 + { + \tl_const:cx { c_iow_wrap_ #1 _marker_tl } + { + \c_catcode_other_space_tl + \c_iow_wrap_marker_tl + \c_catcode_other_space_tl + #1 + \c_catcode_other_space_tl + } + } + \iow_wrap_new_marker:n { end } + \iow_wrap_new_marker:n { newline } + \iow_wrap_new_marker:n { indent } + \iow_wrap_new_marker:n { unindent } +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\iow_indent:n} +% \begin{macro}[aux]{\iow_indent_expandable:n} +% We give a dummy (protected) 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} +\cs_new_protected:Npn \iow_indent:n #1 { } +\cs_new:Npx \iow_indent_expandable:n #1 + { + \c_iow_wrap_indent_marker_tl + #1 + \c_iow_wrap_unindent_marker_tl + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \begin{macro}{\iow_wrap:xnnnN} -% \begin{macro}[aux]{\iow_wrap_loop:w} -% \begin{macro}[aux]{\iow_wrap_word:} -% \begin{macro}[aux]{\iow_wrap_word_fits:} -% \begin{macro}[aux]{\iow_wrap_word_newline:} -% \begin{macro}[aux]{\iow_wrap_newline:} -% \begin{macro}[aux]{\iow_wrap_end:} % The main wrapping function works as follows. The target number of % characters in a line is calculated, before fully-expanding the input % such that |\\| and \verb*|\ | are converted into the appropriate @@ -949,13 +1068,22 @@ { \group_begin: \int_set:Nn \l_iow_target_length_int { \l_iow_line_length_int - ( #3 ) } + \int_zero:N \l_iow_current_indentation_int + \tl_clear:N \l_iow_current_indentation_tl \int_zero:N \l_iow_current_line_int \tl_clear:N \l_iow_current_line_tl \tl_clear:N \l_iow_wrap_tl \bool_set_true:N \l_iow_line_start_bool - \cs_set:Npx \\ - { \c_catcode_other_space_tl \iow_newline: \c_catcode_other_space_tl } + \int_set_eq:NN \tex_escapechar:D \c_minus_one + \cs_set_nopar:Npx \{ { \token_to_str:N \{ } + \cs_set_nopar:Npx \# { \token_to_str:N \# } + \cs_set_nopar:Npx \} { \token_to_str:N \} } + \cs_set_nopar:Npx \% { \token_to_str:N \% } + \cs_set_nopar:Npx \~ { \token_to_str:N \~ } + \int_set:Nn \tex_escapechar:D { 92 } + \cs_set_eq:NN \\ \c_iow_wrap_newline_marker_tl \cs_set_eq:NN \ \c_catcode_other_space_tl + \cs_set_eq:NN \iow_indent:n \iow_indent_expandable:n #4 %<*initex> \tl_set:Nx \l_iow_wrap_tl {#1} @@ -966,53 +1094,61 @@ \cs_set:Npn \\ { \iow_newline: #2 } \use:x { - \exp_not:N \iow_wrap_loop:w - \tl_to_str:N \l_iow_wrap_tl \c_space_tl - \exp_not:N \q_iow_stop \c_space_tl + \iow_wrap_loop:w + \tl_to_str:N \l_iow_wrap_tl + \tl_to_str:N \c_iow_wrap_end_marker_tl + \c_space_tl \c_space_tl + \exp_not:N \q_stop } \exp_args:NNo \group_end: #5 \l_iow_wrapped_tl } % \end{macrocode} -% The loop grabs one word in the input, and checks whether it is -% the end, or a forced new line, or a normal word. +% \end{macro} +% +% \begin{macro}[aux]{\iow_wrap_loop:w} +% The loop grabs one word in the input, and checks whether it is +% the special marker, or a normal word. % \begin{macrocode} \cs_new_protected:Npn \iow_wrap_loop:w #1 ~ % { \tl_set:Nn \l_iow_current_word_tl {#1} - \tl_if_eq:NNTF \l_iow_current_word_tl \iow_newline: - { \iow_wrap_newline: } - { - \tl_if_eq:NNTF \l_iow_current_word_tl \q_iow_stop - { \iow_wrap_end: } - { \iow_wrap_word: } - } + \tl_if_eq:NNTF \l_iow_current_word_tl \c_iow_wrap_marker_tl + { \iow_wrap_special:w } + { \iow_wrap_word: } } % \end{macrocode} -% For a normal word, update the line length, then test if the current -% word would fit in the current line, and call the appropriate function. +% \end{macro} +% +% \begin{macro}[aux]{\iow_wrap_word:} +% \begin{macro}[aux]{\iow_wrap_word_fits:} +% \begin{macro}[aux]{\iow_wrap_word_newline:} +% For a normal word, update the line length, 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 length) are then put in the new line. % \begin{macrocode} \cs_new_protected_nopar:Npn \iow_wrap_word: { \int_set:Nn \l_iow_current_word_int { \str_length_skip_spaces:N \l_iow_current_word_tl } \int_add:Nn \l_iow_current_line_int { \l_iow_current_word_int } - \int_compare:nNnTF \l_iow_current_line_int - < \l_iow_target_length_int + \int_compare:nNnTF \l_iow_current_line_int < \l_iow_target_length_int { \iow_wrap_word_fits: } { \iow_wrap_word_newline: } \iow_wrap_loop:w } -% \end{macrocode} -% 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. -% \begin{macrocode} \cs_new_protected_nopar:Npn \iow_wrap_word_fits: { \bool_if:NTF \l_iow_line_start_bool { \bool_set_false:N \l_iow_line_start_bool - \tl_set_eq:NN \l_iow_current_line_tl \l_iow_current_word_tl + \tl_put_right:Nx \l_iow_current_line_tl + { \l_iow_current_indentation_tl \l_iow_current_word_tl } + \int_add:Nn \l_iow_current_line_int + { \l_iow_current_indentation_int } } { \tl_put_right:Nx \l_iow_current_line_tl @@ -1020,21 +1156,51 @@ \int_incr:N \l_iow_current_line_int } } -% \end{macrocode} -% Otherwise, the current line is added to the result, with the run-on text. -% The current word (and its length) are then put in the new line. -% \begin{macrocode} \cs_new_protected_nopar:Npn \iow_wrap_word_newline: { \tl_put_right:Nx \l_iow_wrapped_tl { \l_iow_current_line_tl \\ } - \int_set_eq:NN \l_iow_current_line_int \l_iow_current_word_int - \tl_set_eq:NN \l_iow_current_line_tl \l_iow_current_word_tl + \int_set:Nn \l_iow_current_line_int + { + \l_iow_current_word_int + + \l_iow_current_indentation_int + } + \tl_set:Nx \l_iow_current_line_tl + { \l_iow_current_indentation_tl \l_iow_current_word_tl } } % \end{macrocode} -% Forced newlines are almost identical to those caused by overflow, -% except that here the word is empty. And remember to continue the loop! +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\iow_wrap_special:w} +% \begin{macro}[aux]{\iow_wrap_newline:w} +% \begin{macro}[aux]{\iow_wrap_indent:w} +% \begin{macro}[aux]{\iow_wrap_unindent:w} +% \begin{macro}[aux]{\iow_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_nopar:Npn \iow_wrap_special:w #1 ~ #2 ~ #3 ~ % + { + \cs_if_exist:cTF { iow_wrap_#1: } + { \use:c { iow_wrap_#1: } } + { \msg_expandable_error:n {#1} } + \str_if_eq:xxTF { #2~#3 } { ~ \c_iow_wrap_marker_tl } + { \iow_wrap_special:w } + { \iow_wrap_loop:w #2 ~ #3 ~ } + } \cs_new_protected_nopar:Npn \iow_wrap_newline: { \tl_put_right:Nx \l_iow_wrapped_tl @@ -1042,15 +1208,24 @@ \int_zero:N \l_iow_current_line_int \tl_clear:N \l_iow_current_line_tl \bool_set_true:N \l_iow_line_start_bool - \iow_wrap_loop:w } -% \end{macrocode} -% At the end, we simply save the last line (without the run-on text). -% \begin{macrocode} +\cs_new_protected_nopar:Npx \iow_wrap_indent: + { + \int_add:Nn \l_iow_current_indentation_int \c_four + \tl_put_right:Nx \exp_not:N \l_iow_current_indentation_tl + { \c_space_tl \c_space_tl \c_space_tl \c_space_tl } + } +\cs_new_protected_nopar:Npn \iow_wrap_unindent: + { + \int_sub:Nn \l_iow_current_indentation_int \c_four + \tl_set:Nx \l_iow_current_indentation_tl + { \prg_replicate:nn \l_iow_current_indentation_int { ~ } } + } \cs_new_protected_nopar:Npn \iow_wrap_end: { \tl_put_right:Nx \l_iow_wrapped_tl { \l_iow_current_line_tl } + \use_none_delimit_by_q_stop:w } % \end{macrocode} % \end{macro} @@ -1058,12 +1233,10 @@ % \end{macro} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro}{\str_length_skip_spaces:N} -% \begin{macro}{\str_length_skip_spaces:n} -% \begin{macro}{\str_length_loop:NNNNNNNNN} +% \begin{macro}[aux]{\str_length_skip_spaces:N} +% \begin{macro}[aux]{\str_length_skip_spaces:n} +% \begin{macro}[aux]{\str_length_loop:NNNNNNNNN} % The wrapping code requires to measure the number of character % in each word. This could be done with \cs{tl_length:n}, but % it is ten times faster (literally) to use the code below. @@ -1091,23 +1264,6 @@ % \end{macro} % \end{macro} % -% \subsection{Special characters for writing} -% -% \begin{macro}{\iow_newline:} -% Global variable holding the character that forces a new line when -% something is written to an output stream -% \begin{macrocode} -\cs_new_nopar:Npn \iow_newline: { ^^J } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\iow_char:N} -% Function to write any escaped char to an output stream. -% \begin{macrocode} -\cs_new_eq:NN \iow_char:N \cs_to_str:N -% \end{macrocode} -% \end{macro} -% % \subsection{Reading input} % % \begin{macro}[pTF]{\ior_if_eof_p:N} @@ -1119,10 +1275,14 @@ { \cs_if_exist:NTF #1 { - \if_eof:w #1 + \if_int_compare:w #1 = \c_sixteen \prg_return_true: - \else: - \prg_return_false: + \else: + \if_eof:w #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: \fi: } { \prg_return_true: } @@ -1171,21 +1331,6 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\ior_new:N, \ior_new:c} -% \begin{macro}{\iow_new:N, \iow_new:c} -% As input--output operations are done using a stack, |new| operations seem -% out-of-place. They are therefore set up just to gobble the input. -% \begin{macrocode} -%<*deprecated> -\cs_new_eq:NN \ior_new:N \use_none:n -\cs_new_eq:NN \ior_new:c \use_none:n -\cs_new_eq:NN \iow_new:N \use_none:n -\cs_new_eq:NN \iow_new:c \use_none:n -%</deprecated> -% \end{macrocode} -% \end{macro} -% \end{macro} -% % \begin{macro}{\ior_open_streams:} % \begin{macro}{\iow_open_streams:} % Slightly misleading names. |