diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3file.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3file.dtx | 1589 |
1 files changed, 818 insertions, 771 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx index 9b8bd6b1a0a..919281bd552 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3file.dtx 3520 2012-03-09 19:34:07Z joseph $ - {L3 Experimental file and I/O operations} +\GetIdInfo$Id: l3file.dtx 3986 2012-07-15 19:23:51Z joseph $ + {L3 File and I/O operations} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -78,6 +78,13 @@ % \enquote{current path} for \TeX{} is somewhat broader than that for other % programs. % +% For functions which expect a \meta{file name} argument, this argument +% may contain both literal items and expandable content, which should on +% full expansion be the desired file name. Any active characters (as +% declared in \cs{l_char_active_seq}) will \emph{not} be expanded, +% allowing the direct use of these in file names. +% Spaces are not allowed in file names. +% % \section{File operation functions} % % \begin{variable}{\g_file_current_name_tl} @@ -95,11 +102,6 @@ % Searches for \meta{file name} using the current \TeX{} search % path and the additional paths controlled by % \cs{file_path_include:n}). -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% The expansion occurs when \TeX{} searches for the file. -% \end{texnote} % \end{function} % % \begin{function}[updated = 2012-02-10]{\file_add_path:nN} @@ -108,16 +110,9 @@ % \end{syntax} % Searches for \meta{file name} in the path as detailed for % \cs{file_if_exist:nTF}, and if found sets the \meta{tl var} the -% fully-qualified name of the file, \emph{i.e}.~the path and file name. +% fully-qualified name of the file, \emph{i.e.}~the path and file name. % If the file is not found then the \meta{tl var} will contain the % marker \cs{q_no_value}. -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% Any active characters (as declared in \cs{l_char_active_seq}) will -% \emph{not} be expanded, allowing the direct use of these in -% file names. -% \end{texnote} % \end{function} % % \begin{function}[updated = 2012-02-17]{\file_input:n} @@ -128,30 +123,29 @@ % \cs{file_if_exist:nTF}, and if found reads in the file as % additional \LaTeX{} source. All files read are recorded % for information and the file name stack is updated by this -% function. An error will be raised if the file is not found -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% Any active characters (as declared in \cs{l_char_active_seq}) will -% \emph{not} be expanded, allowing the direct use of these in -% file names. -% \end{texnote} +% function. An error will be raised if the file is not found. % \end{function} % -% \begin{function}{\file_path_include:n} +% \begin{function}[updated = 2012-07-04]{\file_path_include:n} % \begin{syntax} % \cs{file_path_include:n} \Arg{path} % \end{syntax} % Adds \meta{path} to the list of those used to search when reading % files. The assignment is local. +% The \meta{path} is processed in the same way as a \meta{file name}, +% \emph{i.e.}, with \texttt{x}-type expansion except active +% characters. Spaces are not allowed in the \meta{path}. % \end{function} % -% \begin{function}{\file_path_remove:n} +% \begin{function}[updated = 2012-07-04]{\file_path_remove:n} % \begin{syntax} % \cs{file_path_remove:n} \Arg{path} % \end{syntax} % Removes \meta{path} from the list of those used to search when reading % files. The assignment is local. +% The \meta{path} is processed in the same way as a \meta{file name}, +% \emph{i.e.}, with \texttt{x}-type expansion except active +% characters. Spaces are not allowed in the \meta{path}. % \end{function} % % \begin{function}{\file_list:} @@ -171,16 +165,20 @@ % close streams when they are no longer needed, to release them for other % processes. % +% Note that I/O operations are global: streams should all be declared +% with global names and treated accordingly. +% % \begin{function}[added = 2011-09-26, updated = 2011-12-27] % {\ior_new:N, \ior_new:c, \iow_new:N, \iow_new:c} % \begin{syntax} -% \cs{ior_new:Nn} \meta{stream} +% \cs{ior_new:N} \meta{stream} +% \cs{iow_new:N} \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. +% 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 is an error, and the +% \meta{stream} will behave as the corresponding \cs{c_term_\ldots}. % \end{function} % % \begin{function}[updated = 2012-02-10]{\ior_open:Nn, \ior_open:cn} @@ -192,14 +190,7 @@ % 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 file ends. -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% Any active characters (as declared in \cs{l_char_active_seq}) will -% \emph{not} be expanded, allowing the direct use of these in -% file names. -% \end{texnote} +% is given or the \TeX{} run ends. % \end{function} % % \begin{function}[updated = 2012-02-09]{\iow_open:Nn, \iow_open:cn} @@ -211,34 +202,20 @@ % 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{iow_close:N} instruction -% is given or the file ends. Opening a file for writing will clear +% is given or the \TeX{} run ends. Opening a file for writing will clear % any existing content in the file (\emph{i.e.}~writing is \emph{not} % additive). -% \begin{texnote} -% The \meta{file name} may contain both literal items and expandable -% content, which should on full expansion be the desired file name. -% Any active characters (as declared in \cs{l_char_active_seq}) will -% \emph{not} be expanded, allowing the direct use of these in -% file names. -% \end{texnote} % \end{function} % -% \begin{function}[updated = 2011-12-27]{\ior_close:N, \ior_close:c} +% \begin{function}[updated = 2012-07-03] +% {\ior_close:N, \ior_close:c, \iow_close:N, \iow_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. -% \end{function} -% -% \begin{function}[updated = 2011-12-27]{\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. +% to other programmers. % \end{function} % % \begin{function}{\ior_list_streams:, \iow_list_streams:} @@ -250,38 +227,38 @@ % stream: intended for tracking down problems. % \end{function} % -% \section{Reading from files} +% \subsection{Reading from files} % -% \begin{function}{\ior_to:NN,\ior_gto:NN} +% \begin{function}[added = 2012-06-24]{\ior_get:NN} % \begin{syntax} -% \cs{ior_to:NN} \meta{stream} \meta{token list variable} +% \cs{ior_get:NN} \meta{stream} \meta{token list variable} % \end{syntax} -% Functions that reads one or more lines (until an equal number of left +% Function that reads one or more lines (until an equal number of left % and right braces are found) from the input \meta{stream} and stores -% the result in the \meta{token list} variable, locally or globally. If the +% the result locally in the \meta{token list} variable. If the % \meta{stream} is not open, input is requested from the terminal. % The material read from the \meta{stream} will be tokenized by % \TeX{} according to the category codes in force when the function % is used. % \begin{texnote} -% This protected macro expands to the \TeX{} primitives \tn{read} -% or \tn{global}\tn{read} along with the |to| keyword. +% This protected macro expands to the \TeX{} primitive \tn{read} +% along with the |to| keyword. % \end{texnote} % \end{function} % -% \begin{function}{\ior_str_to:NN,\ior_str_gto:NN} +% \begin{function}[added = 2012-06-24]{\ior_get_str:NN} % \begin{syntax} -% \cs{ior_str_to:NN} \meta{stream} \meta{token list variable} +% \cs{ior_get_str:NN} \meta{stream} \meta{token list variable} % \end{syntax} -% Functions that reads one line from the input \meta{stream} and stores -% the result in the \meta{token list} variable, locally or globally. If the +% Function that reads one line from the input \meta{stream} and stores +% the result locally in the \meta{token list} variable. If the % \meta{stream} is not open, input is requested from the terminal. -% The material read from the \meta{stream} as a series of tokens with +% 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). % \begin{texnote} -% This protected macro expands to the \eTeX{} primitives \tn{readline} -% or \tn{global}\tn{readline} along with the |to| keyword. +% This protected macro expands to the \eTeX{} primitive \tn{readline} +% along with the |to| keyword. % \end{texnote} % \end{function} % @@ -297,17 +274,13 @@ % % \section{Writing to files} % -% \begin{function}{\iow_now:Nn, \iow_now:Nx} +% \begin{function}[updated = 2012-06-05]{\iow_now:Nn, \iow_now:Nx} % \begin{syntax} % \cs{iow_now:Nn} \meta{stream} \Arg{tokens} % \end{syntax} % This functions writes \meta{tokens} to the specified % \meta{stream} immediately (\emph{i.e.}~the write operation is called % on expansion of \cs{iow_now:Nn}). -% \begin{texnote} -% \cs{iow_now:Nx} is a protected macro which expands to -% the two \TeX{} primitives \tn{immediate}\tn{write}. -% \end{texnote} % \end{function} % % \begin{function}{\iow_log:n, \iow_log:x} @@ -355,9 +328,9 @@ % % \begin{function}[EXP]{\iow_char:N} % \begin{syntax} -% \cs{iow_char:N} \meta{token} +% \cs{iow_char:N} |\|\meta{char} % \end{syntax} -% Inserts \meta{token} into the output stream. Useful when trying to +% Inserts \meta{char} into the output stream. Useful when trying to % write difficult characters such as |%|, |{|, |}|, % \emph{etc.}~in messages, for example: % \begin{verbatim} @@ -376,47 +349,59 @@ % expansion (\emph{e.g.}~in the second argument of \cs{iow_now:Nn}). % \end{function} % -% \section{Wrapping lines in output} +% \subsection{Wrapping lines in output} % -% \begin{function}[updated = 2011-09-21]{\iow_wrap:xnnnN} +% \begin{function}[added = 2012-06-28]{\iow_wrap:nnnN} % \begin{syntax} -% \cs{iow_wrap:xnnnN} \Arg{text} \Arg{run-on text} \Arg{run-on length} \Arg{set up} \meta{function} +% \cs{iow_wrap:nnnN} \Arg{text} \Arg{run-on text} \Arg{set up} \meta{function} % \end{syntax} % This function will wrap the \meta{text} to a fixed number of % characters per line. At the start of each line which is wrapped, -% the \meta{run-on text} will be inserted. The line length targeted -% will be the value of \cs{l_iow_line_length_int} minus the -% \meta{run-on length}. The later value should be the number of -% characters in the \meta{run-on text}. Additional functions may be -% added to the wrapping by using the \meta{set up}, which is executed -% 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}, +% the \meta{run-on text} will be inserted. The line character count +% targeted will be the value of \cs{l_iow_line_count_int} minus the +% number of characters in the \meta{run-on text}. The \meta{text} and +% \meta{run-on text} are exhaustively expanded by the function, with the +% following substitutions: % \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. +% \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 -% the \meta{text}. The output of \cs{iow_wrap:xnnnN} (\emph{i.e.}~the -% argument passed to the \meta{function}) will consist of characters of -% category code $12$ (other) and $10$ (space) only. This means that the +% Additional functions may be added to the wrapping by using the +% \meta{set up}, which is executed before the wrapping takes place: this +% may include overriding the substitutions listed. +% +% Any expandable material in the \meta{text} which is not to be expanded +% on wrapping should be converted to a string using \cs{token_to_str:N}, +% \cs{tl_to_str:n}, \cs{tl_to_str:N}, \emph{etc.} +% +% The result of the wrapping operation is passed as a braced argument to the +% \meta{function}, which will typically be a wrapper around a write +% operation. The output of \cs{iow_wrap:nnnN} (\emph{i.e.}~the argument +% passed to the \meta{function}) will consist of characters of category +% \enquote{other} (category code~12), with the exception of spaces which +% will have category \enquote{space} (category code~10). This means that the % output will \emph{not} expand further when written to a file. +% +% \begin{texnote} +% Internally, \cs{iow_wrap:nnnN} carries out an \texttt{x}-type expansion +% on the \meta{text} to expand it. This is done in such a way that +% \cs{exp_not:N} or \cs{exp_not:n} \emph{could} be used to prevent +% expansion of material. However, this is less conceptually clear than +% conversion to a string, which is therefore the supported method for +% handling expandable material in the \meta{text}. +% \end{texnote} % \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), +% In the context of \cs{iow_wrap:nnnN} (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 @@ -424,8 +409,9 @@ % 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} +% \begin{variable}[added = 2012-06-24]{\l_iow_line_count_int} +% The maximum number of characters in a line to be written +% by the \cs{iow_wrap:nnnN} % function. This value depends on the \TeX{} system in use: the standard % value is $78$, which is typically correct for unmodified \TeX{}live % and MiK\TeX{} systems. @@ -436,11 +422,11 @@ % (\enquote{other}), and character code $32$ (space). % \end{variable} % -% \section{Constant input--output streams} +% \subsection{Constant input--output streams} % % \begin{variable}{\c_term_ior} % Constant input stream for reading from the terminal. Reading from this -% stream using \cs{ior_to:NN} or similar will result in a prompt from +% stream using \cs{ior_get:NN} or similar will result in a prompt from % \TeX{} of the form % \begin{verbatim} % <tl>= @@ -452,123 +438,61 @@ % (plus the log), respectively. % \end{variable} % -% \section{Experimental functions} -% -% \begin{function}[added = 2012-02-11]{\ior_map_inline:Nn} -% \begin{syntax} -% \cs{ior_map_inline:Nn} \meta{stream} \Arg{inline function} -% \end{syntax} -% Applies the \meta{inline function} to \meta{items} obtained by -% reading one or more lines (until an equal number of left and right -% braces are found) from the \meta{stream}. The \meta{inline function} -% should consist of code which will receive the \meta{line} as |#1|. -% \end{function} +% \subsection{Primitive conditionals} % -% \begin{function}[added = 2012-02-11]{\ior_str_map_inline:nn} +% \begin{function}[EXP]{\if_eof:w} % \begin{syntax} -% \cs{ior_str_map_inline:Nn} \Arg{stream} \Arg{inline function} +% \cs{if_eof:w} \meta{stream} +% ~~\meta{true code} +% \cs{else:} +% ~~\meta{false code} +% \cs{fi:} % \end{syntax} -% Applies the \meta{inline function} to every \meta{line} -% in the \meta{file}. 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 -% will receive the \meta{line} as |#1|. +% Tests if the \meta{stream} returns \enquote{end of file}, which is true +% for non-existent files. The \cs{else:} branch is optional. +% \begin{texnote} +% This is the \TeX{} primitive \tn{ifeof}. +% \end{texnote} % \end{function} % -% \section{Internal file functions} -% -% \begin{variable}{\g_file_stack_seq} -% Stores the stack of nested files loaded using \cs{file_input:n}. This -% is needed to restore the appropriate file name to -% \cs{g_file_current_name_tl} at the end of each file. -% \end{variable} +% \subsection{Internal file functions and variables} % -% \begin{variable}{\g_file_record_seq} -% Stores the name of every file loaded using \cs{file_input:n}. In -% contrast to \cs{g_file_stack_seq}, no items are ever removed from this -% sequence. +% \begin{variable}{\l__file_internal_name_ior} +% Used to test for the existence of files when opening. % \end{variable} % -% \begin{variable}{\l_file_internal_name_tl} +% \begin{variable}{\l__file_internal_name_tl} % Used to return the full name of a file for internal use. % \end{variable} % -% \begin{variable}{\l_file_search_path_seq} -% The sequence of file paths to search when loading a file. -% \end{variable} -% -% \begin{variable}{\l_file_internal_saved_path_seq} -% When loaded on top of \LaTeXe{}, there is a need to save the search -% path so that \tn{input@path} can be used as appropriate. -% \end{variable} -% -% \begin{variable}[added = 2011-09-06]{\l_file_internal_seq} -% When loaded on top of \LaTeXe{}, there is a need to convert -% the comma lists \tn{input@path} and \tn{@filelist} to sequences. -% \end{variable} -% -% \section{Internal input--output functions} -% -% \begin{function}[added = 2012-02-09]{\file_name_sanitize:nn} +% \begin{function}[added = 2012-02-09]{\__file_name_sanitize:nn} % \begin{syntax} -% \cs{file_name_sanitize:nn} \Arg{name} \Arg{tokens} +% \cs{__file_name_sanitize:nn} \Arg{name} \Arg{tokens} % \end{syntax} % Exhaustively-expands the \meta{name} with the exception of any -% category \meta{active} (catcode~$12$) tokens, which are not expanded. +% category \meta{active} (catcode~$13$) tokens, which are not expanded. % The list of \meta{active} tokens is taken from \cs{l_char_active_seq}. % The \meta{sanitized name} is then inserted (in braces) after the % \meta{tokens}, which should further process the file name. If any % spaces are found in the name after expansion, an error is raised. % \end{function} % -% \begin{function}[EXP]{\if_eof:w} -% \begin{syntax} -% \cs{if_eof:w} \meta{stream} -% ~~\meta{true code} -% \cs{else:} -% ~~\meta{false code} -% \cs{fi:} -% \end{syntax} -% Tests if the \meta{stream} returns \enquote{end of file}, which is true -% for non-existent files. The \cs{else:} branch is optional. -% \begin{texnote} -% This is the \TeX{} primitive \tn{ifeof}. -% \end{texnote} -% \end{function} +% \subsection{Internal input--output functions} % -% \begin{function}[added = 2012-01-23] -% {\ior_open_unsafe:Nn, \ior_open_unsafe:No, \iow_open_unsafe:Nn} +% \begin{function}[added = 2012-01-23]{\__ior_open:Nn, \__ior_open:No} % \begin{syntax} -% \cs{ior_open_unsafe:Nn} \meta{stream} \Arg{file name} +% \cs{__ior_open:Nn} \meta{stream} \Arg{file name} % \end{syntax} -% These functions have identical syntax to the generally-available -% versions without the |_unsafe| suffix. However, these functions do not -% take precautions against active characters in the \meta{file name}: they -% are therefore intended to be used by higher-level functions which -% have already fully expanded the \meta{file name} and which need to -% perform multiple open or close operations. See for example the +% This function has identical syntax to the public version. However, +% is does not take precautions against active characters in the +% \meta{file name}, and it does not attempt to add a \meta{path} to +% the \meta{file name}: it is therefore intended to be used by +% higher-level +% functions which have already fully expanded the \meta{file name} and which +% need to perform multiple open or close operations. See for example the % implementation of \cs{file_add_path:Nn}, % \end{function} % -% \begin{function}{\ior_raw_new:N, \ior_raw_new:c} -% \begin{syntax} -% \cs{ior_raw_new:N} \meta{stream} -% \end{syntax} -% Directly allocates a new stream for reading, bypassing the stack -% system. This is to be used only when a new stream is required at a -% \TeX{} level, when a new stream is requested by the stack itself. -% \end{function} -% -% \begin{function}{\iow_raw_new:N, \iow_raw_new:c} -% \begin{syntax} -% \cs{iow_raw_new:N} \meta{stream} -% \end{syntax} -% Directly allocates a new stream for writing, bypassing the stack -% system. This is to be used only when a new stream is required at a -% \TeX{} level, when a new stream is requested by the stack itself. -% \end{function} -% % \end{documentation} % % \begin{implementation} @@ -582,10 +506,14 @@ % \end{macrocode} % % \begin{macrocode} +%<@@=file> +% \end{macrocode} +% +% \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -593,12 +521,10 @@ % % \begin{variable}{\g_file_current_name_tl} % The name of the current file should be available at all times. -% \begin{macrocode} -\tl_new:N \g_file_current_name_tl -% \end{macrocode} % For the format the file name needs to be picked up at the start of the % file. In package mode the current file name is collected from \LaTeXe{}. % \begin{macrocode} +\tl_new:N \g_file_current_name_tl %<*initex> \tex_everyjob:D \exp_after:wN { @@ -612,91 +538,92 @@ % \end{macrocode} % \end{variable} % -% \begin{variable}{\g_file_stack_seq} +% \begin{variable}{\g_@@_stack_seq} % The input list of files is stored as a sequence stack. % \begin{macrocode} -\seq_new:N \g_file_stack_seq +\seq_new:N \g_@@_stack_seq % \end{macrocode} % \end{variable} % -% \begin{variable}{\g_file_record_seq} -% The total list of files used is recorded separately from the current file -% stack, as nothing is ever popped from this list. -% \begin{macrocode} -\seq_new:N \g_file_record_seq -% \end{macrocode} -% The current file name should be included in the file list! +% \begin{variable}{\g_@@_record_seq} +% The total list of files used is recorded separately from the current +% file stack, as nothing is ever popped from this list. The current +% file name should be included in the file list! In format mode, this +% is done at the very start of the \TeX{} run. In package mode we +% will eventually copy the contents of \cs{@filelist}. % \begin{macrocode} +\seq_new:N \g_@@_record_seq %<*initex> \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D - \seq_gput_right:NV \g_file_record_seq \g_file_current_name_tl + \seq_gput_right:NV \g_@@_record_seq \g_file_current_name_tl } %</initex> % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_file_internal_name_tl} +% \begin{variable}{\l_@@_internal_name_tl} % Used to return the fully-qualified name of a file. % \begin{macrocode} -\tl_new:N \l_file_internal_name_tl +\tl_new:N \l_@@_internal_name_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_file_search_path_seq} +% \begin{variable}{\l_@@_search_path_seq} % The current search path. % \begin{macrocode} -\seq_new:N \l_file_search_path_seq +\seq_new:N \l_@@_search_path_seq % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_file_internal_saved_path_seq} +% \begin{variable}{\l_@@_saved_search_path_seq} % The current search path has to be saved for package use. % \begin{macrocode} %<*package> -\seq_new:N \l_file_internal_saved_path_seq +\seq_new:N \l_@@_saved_search_path_seq %</package> % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_file_internal_seq} +% \begin{variable}{\l_@@_internal_seq} % Scratch space for comma list conversion in package mode. % \begin{macrocode} %<*package> -\seq_new:N \l_file_internal_seq +\seq_new:N \l_@@_internal_seq %</package> % \end{macrocode} % \end{variable} % -% \begin{macro}[int]{\file_name_sanitize:nn} +% \begin{macro}[aux]{\@@_name_sanitize:nn} % For converting a token list to a string where active characters are treated % as strings from the start. % \begin{macrocode} -\cs_new_protected:Npn \file_name_sanitize:nn #1#2 +\cs_new_protected:Npn \@@_name_sanitize:nn #1#2 { \group_begin: \seq_map_inline:Nn \l_char_active_seq { \cs_set_nopar:Npx ##1 { \token_to_str:N ##1 } } - \tl_set:Nx \l_file_internal_name_tl {#1} - \tl_set:Nx \l_file_internal_name_tl - { \tl_to_str:N \l_file_internal_name_tl } - \tl_if_in:NnTF \l_file_internal_name_tl { ~ } + \tl_set:Nx \l_@@_internal_name_tl {#1} + \tl_set:Nx \l_@@_internal_name_tl + { \tl_to_str:N \l_@@_internal_name_tl } + \tl_if_in:NnT \l_@@_internal_name_tl { ~ } { - \msg_kernel_error:nnx { file } { space-in-file-name } - { \l_file_internal_name_tl } + \__msg_kernel_error:nnx { kernel } { space-in-file-name } + { \l_@@_internal_name_tl } + \tl_remove_all:Nn \l_@@_internal_name_tl { ~ } } \use:x { \group_end: - \exp_not:n {#2} { \l_file_internal_name_tl } + \exp_not:n {#2} { \l_@@_internal_name_tl } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\file_add_path:nN} -% \begin{macro}[aux]{\file_add_path_aux:nN, \file_add_path_search:nN} +% \begin{macro}[aux]{\@@_add_path:nN, \@@_add_path_search:nN} % The way to test if a file exists is to try to open it: if it does not % exist then \TeX{} will report end-of-file. For files which are in the % current directory, this is straight-forward. For other locations, a @@ -705,33 +632,31 @@ % |#2| is returned empty. % \begin{macrocode} \cs_new_protected:Npn \file_add_path:nN #1 - { \file_name_sanitize:nn {#1} { \file_add_path_aux:nN } } -\cs_new_protected:Npn \file_add_path_aux:nN #1#2 + { \@@_name_sanitize:nn {#1} { \@@_add_path:nN } } +\cs_new_protected:Npn \@@_add_path:nN #1#2 { - \ior_open_unsafe:Nn \g_file_internal_ior {#1} - \ior_if_eof:NTF \g_file_internal_ior - { \file_add_path_search:nN {#1} #2 } - { - \ior_close:N \g_file_internal_ior - \tl_set:Nn #2 {#1} - } + \__ior_open:Nn \g__file_internal_ior {#1} + \ior_if_eof:NTF \g__file_internal_ior + { \@@_add_path_search:nN {#1} #2 } + { \tl_set:Nn #2 {#1} } + \ior_close:N \g__file_internal_ior } -\cs_new_protected:Npn \file_add_path_search:nN #1#2 +\cs_new_protected:Npn \@@_add_path_search:nN #1#2 { - \tl_set:Nn #2 { \q_no_value } + \tl_set:Nn #2 { \q_no_value } %<*package> \cs_if_exist:NT \input@path { - \seq_set_eq:NN \l_file_internal_saved_path_seq \l_file_search_path_seq - \seq_set_from_clist:NN \l_file_internal_seq \input@path - \seq_concat:NNN \l_file_search_path_seq - \l_file_search_path_seq \l_file_internal_seq + \seq_set_eq:NN \l_@@_saved_search_path_seq \l_@@_search_path_seq + \seq_set_split:NnV \l_@@_internal_seq { , } \input@path + \seq_concat:NNN \l_@@_search_path_seq + \l_@@_search_path_seq \l_@@_internal_seq } %</package> - \seq_map_inline:Nn \l_file_search_path_seq + \seq_map_inline:Nn \l_@@_search_path_seq { - \ior_open_unsafe:Nn \g_file_internal_ior { ##1 #1 } - \ior_if_eof:NF \g_file_internal_ior + \__ior_open:Nn \g__file_internal_ior { ##1 #1 } + \ior_if_eof:NF \g__file_internal_ior { \tl_set:Nx #2 { ##1 #1 } \seq_map_break: @@ -739,9 +664,8 @@ } %<*package> \cs_if_exist:NT \input@path - { \seq_set_eq:NN \l_file_search_path_seq \l_file_internal_saved_path_seq } + { \seq_set_eq:NN \l_@@_search_path_seq \l_@@_saved_search_path_seq } %</package> - \ior_close:N \g_file_internal_ior } % \end{macrocode} % \end{macro} @@ -751,12 +675,12 @@ % The test for the existence of a file is a wrapper around the function to % add a path to a file. If the file was found, the path will contain % something, whereas if the file was not located then the return value -% will be empty. +% will be \cs{q_no_value}. % \begin{macrocode} \prg_new_protected_conditional:Npnn \file_if_exist:n #1 { T , F , TF } { - \file_add_path:nN {#1} \l_file_internal_name_tl - \quark_if_no_value:NTF \l_file_internal_name_tl + \file_add_path:nN {#1} \l_@@_internal_name_tl + \quark_if_no_value:NTF \l_@@_internal_name_tl { \prg_return_false: } { \prg_return_true: } } @@ -764,78 +688,124 @@ % \end{macro} % % \begin{macro}{\file_input:n} -% \begin{macro}[aux]{\file_input_aux:n \file_input_aux:V, \file_input_error:n} +% \begin{macro}[aux]{\@@_input:n \@@_input:V} +% \begin{macro}[aux, EXP]{\@@_input_aux:w} +% \begin{macro}[aux]{\@@_input_aux:n, \@@_input_aux:o} % Loading a file is done in a safe way, checking first that the file -% exists and loading only if it does. +% exists and loading only if it does. Push the file name on the +% \cs{g_@@_stack_seq}, and add it to the file list, either +% \cs{g_@@_record_seq}, or \cs{@filelist} in package mode. % \begin{macrocode} \cs_new_protected:Npn \file_input:n #1 { - \file_add_path:nN {#1} \l_file_internal_name_tl - \quark_if_no_value:NTF \l_file_internal_name_tl - { \file_name_sanitize:nn {#1} { \file_input_error:n } } - { \file_input_aux:V \l_file_internal_name_tl } + \file_add_path:nN {#1} \l_@@_internal_name_tl + \quark_if_no_value:NTF \l_@@_internal_name_tl + { + \@@_name_sanitize:nn {#1} + { \__msg_kernel_error:nnx { kernel } { file-not-found } } + } + { \@@_input:V \l_@@_internal_name_tl } } -\cs_new_protected:Npn \file_input_aux:n #1 +\cs_new_protected:Npn \@@_input:n #1 + { + \quark_if_nil:oTF { \@@_input_aux:w #1 . \q_nil . \q_stop } + { \@@_input_aux:o { \tl_to_str:n { #1 .tex } } } + { \@@_input_aux:n {#1} } + } +\cs_generate_variant:Nn \@@_input:n { V } +\cs_new:Npn \@@_input_aux:w #1 . #2 . #3 \q_stop { #2 } +\cs_new_protected:Npn \@@_input_aux:n #1 { %<*initex> - \seq_gput_right:Nn \g_file_record_seq {#1} + \seq_gput_right:Nn \g_@@_record_seq {#1} %</initex> %<*package> - \@addtofilelist {#1} + \clist_if_exist:NTF \@filelist + { \@addtofilelist {#1} } + { \seq_gput_right:Nn \g_@@_record_seq {#1} } %</package> - \seq_gpush:Nn \g_file_stack_seq \g_file_current_name_tl + \seq_gpush:Nn \g_@@_stack_seq \g_file_current_name_tl \tl_gset:Nn \g_file_current_name_tl {#1} \tex_input:D #1 \c_space_tl - \seq_gpop:NN \g_file_stack_seq \g_file_current_name_tl + \seq_gpop:NN \g_@@_stack_seq \g_file_current_name_tl } -\cs_generate_variant:Nn \file_input_aux:n { V } -\cs_new_protected:Npn \file_input_error:n #1 - { \msg_kernel_error:nnx { file } { file-not-found } {#1} } +\cs_generate_variant:Nn \@@_input_aux:n { o } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\file_path_include:n} % \begin{macro}{\file_path_remove:n} +% \begin{macro}[aux]{\@@_path_include:n} % Wrapper functions to manage the search path. % \begin{macrocode} \cs_new_protected:Npn \file_path_include:n #1 + { \@@_name_sanitize:nn {#1} { \@@_path_include:n } } +\cs_new_protected:Npn \@@_path_include:n #1 { - \seq_if_in:NnF \l_file_search_path_seq {#1} - { \seq_put_right:Nn \l_file_search_path_seq {#1} } + \seq_if_in:NnF \l_@@_search_path_seq {#1} + { \seq_put_right:Nn \l_@@_search_path_seq {#1} } } \cs_new_protected:Npn \file_path_remove:n #1 - { \seq_remove_all:Nn \l_file_search_path_seq {#1} } + { + \@@_name_sanitize:nn {#1} + { \seq_remove_all:Nn \l_@@_search_path_seq } + } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % % \begin{macro}{\file_list:} -% A function to list all files used to the log. +% A function to list all files used to the log, without duplicates. +% In package mode, if \cs{@filelist} is still defined, we need to take +% it into account (we capture it \cs{AtBeginDocument} into +% \cs{g_@@_record_seq}), turning each file name into a string. % \begin{macrocode} \cs_new_protected_nopar:Npn \file_list: { - \seq_remove_duplicates:N \g_file_record_seq + \seq_set_eq:NN \l_@@_internal_seq \g_@@_record_seq +%<*package> + \clist_if_exist:NT \@filelist + { + \clist_map_inline:Nn \@filelist + { + \seq_put_right:No \l_@@_internal_seq + { \tl_to_str:n {##1} } + } + } +%</package> + \seq_remove_duplicates:N \l_@@_internal_seq \iow_log:n { *~File~List~* } - \seq_map_inline:Nn \g_file_record_seq { \iow_log:n {##1} } + \seq_map_inline:Nn \l_@@_internal_seq { \iow_log:n {##1} } \iow_log:n { ************* } } % \end{macrocode} % \end{macro} % -% When used as a package, there is a need to hold onto the standard -% file list as well as the new one here. +% When used as a package, there is a need to hold onto the standard file +% list as well as the new one here. File names recorded in +% \cs{@filelist} must be turned to strings before being added to +% \cs{g_@@_record_seq}. % \begin{macrocode} %<*package> \AtBeginDocument { - \seq_set_from_clist:NN \l_file_internal_seq \@filelist - \seq_gconcat:NNN \g_file_record_seq \g_file_record_seq \l_file_internal_seq + \clist_map_inline:Nn \@filelist + { \seq_gput_right:No \g_@@_record_seq { \tl_to_str:n {#1} } } } %</package> % \end{macrocode} % -% \subsection{Input--output variables constants} +% \subsection{Input operations} +% +% \begin{macrocode} +%<@@=ior> +% \end{macrocode} +% +% \subsubsection{Variables and constants} % % \begin{variable}{\c_term_ior} % Reading from the terminal (with a prompt) is done using a positive @@ -846,20 +816,10 @@ % \end{macrocode} % \end{variable} % -% \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}). -% \begin{macrocode} -\cs_new_eq:NN \c_log_iow \c_minus_one -\cs_new_eq:NN \c_term_iow \c_sixteen -% \end{macrocode} -% \end{variable} -% -% \begin{variable}{\c_iow_streams_tl, \c_ior_streams_tl} +% \begin{variable}{\c_@@_streams_tl} % The list of streams available, by number. % \begin{macrocode} -\tl_const:Nn \c_iow_streams_tl +\tl_const:Nn \c_@@_streams_tl { \c_zero \c_one @@ -878,151 +838,118 @@ \c_fourteen \c_fifteen } -\cs_new_eq:NN \c_ior_streams_tl \c_iow_streams_tl % \end{macrocode} % \end{variable} % -% \begin{variable}{\g_iow_streams_prop, \g_ior_streams_prop} +% \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{macrocode} -\prop_new:N \g_iow_streams_prop -\prop_new:N \g_ior_streams_prop +\prop_new:N \g_@@_streams_prop %<*package> -\prop_put:Nnn \g_iow_streams_prop { 0 } { LaTeX2e~reserved } -\prop_put:Nnn \g_iow_streams_prop { 1 } { LaTeX2e~reserved } -\prop_put:Nnn \g_iow_streams_prop { 2 } { LaTeX2e~reserved } -\prop_put:Nnn \g_ior_streams_prop { 0 } { LaTeX2e~reserved } +\prop_put:Nnn \g_@@_streams_prop { 0 } { LaTeX2e~reserved } %</package> % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_iow_stream_int, \l_ior_stream_int} +% \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{macrocode} -\int_new:N \l_iow_stream_int -\cs_new_eq:NN \l_ior_stream_int \l_iow_stream_int +\int_new:N \l_@@_stream_int % \end{macrocode} % \end{variable} % -% \subsection{Stream management} +% \subsubsection{Stream management} % -% \begin{macro}[int]{\ior_raw_new:N, \ior_raw_new:c} -% \begin{macro}[int]{\iow_raw_new:N, \iow_raw_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{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 \ior_raw_new:N #1 - { \alloc_reg:nNN { ior } \tex_chardef:D #1 } -\alloc_setup_type:nnn { iow } \c_zero \c_sixteen -\cs_new_protected:Npn \iow_raw_new:N #1 - { \alloc_reg:nNN { iow } \tex_chardef:D #1 } +\__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 \iow_raw_new:N \newwrite -\cs_set_eq:NN \ior_raw_new:N \newread +\cs_set_eq:NN \@@_new:N \newread %</package> -\cs_generate_variant:Nn \ior_raw_new:N { c } -\cs_generate_variant:Nn \iow_raw_new:N { c } +\cs_generate_variant:Nn \@@_new:N { c } % \end{macrocode} % \end{macro} -% \end{macro} % -% \begin{macro}{\ior_new:N, \ior_new:c, \iow_new:N, \iow_new:c} +% \begin{macro}{\ior_new:N, \ior_new:c} % Reserving a new stream is done by defining the name as equal to using the % terminal. % \begin{macrocode} \cs_new_protected:Npn \ior_new:N #1 { \cs_new_eq:NN #1 \c_term_ior } \cs_generate_variant:Nn \ior_new:N { c } -\cs_new_protected:Npn \iow_new:N #1 { \cs_new_eq:NN #1 \c_term_iow } -\cs_generate_variant:Nn \iow_new:N { c } % \end{macrocode} % \end{macro} % -% \begin{variable}{\g_file_internal_ior} -% Delayed from above so that the mechanisms are in place. +% \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 +\ior_new:N \g__file_internal_ior % \end{macrocode} % \end{variable} % -% \begin{macro}{\ior_open:Nn, \ior_open:cn, \iow_open:Nn, \iow_open:cn} -% \begin{macro}[int]{\ior_open_aux:Nn} +% \begin{macro}{\ior_open:Nn, \ior_open:cn} % \begin{macro}[TF]{\ior_open:Nn} -% \begin{macro}[aux]{\ior_open_aux:NnTF} -% \begin{macro}[int] -% {\ior_open_unsafe:Nn, \ior_open_unsafe:No, \iow_open_unsafe:Nn} -% In both cases, 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. For reading files, there is an intermediate -% auxiliary to allow path addition, keeping the internal function fast -% and avoiding an infinite loop. +% \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. % \begin{macrocode} \cs_new_protected:Npn \ior_open:Nn #1#2 - { \file_name_sanitize:nn {#2} { \ior_open_aux:Nn #1 } } + { \__file_name_sanitize:nn {#2} { \@@_open_aux:Nn #1 } } \cs_generate_variant:Nn \ior_open:Nn { c } -\cs_new_protected:Npn \iow_open:Nn #1#2 - { \file_name_sanitize:nn {#2} { \iow_open_unsafe:Nn #1 } } -\cs_generate_variant:Nn \iow_open:Nn { c } -\cs_new_protected:Npn \ior_open_aux:Nn #1#2 +\cs_new_protected:Npn \@@_open_aux:Nn #1#2 { - \file_add_path:nN {#2} \l_file_internal_name_tl - \quark_if_no_value:NTF \l_file_internal_name_tl - { \file_input_error:n {#2} } - { \ior_open_unsafe:No #1 \l_file_internal_name_tl } + \file_add_path:nN {#2} \l__file_internal_name_tl + \quark_if_no_value:NTF \l__file_internal_name_tl + { \__msg_kernel_error:nnx { kernel } { file-not-found } {#2} } + { \@@_open:No #1 \l__file_internal_name_tl } } \prg_new_protected_conditional:Npnn \ior_open:Nn #1#2 { T , F , TF } - { \file_name_sanitize:nn {#2} { \ior_open_aux:NnTF #1 } } -\cs_new_protected:Npn \ior_open_aux:NnTF #1#2 + { \__file_name_sanitize:nn {#2} { \@@_open_aux:NnTF #1 } } +\cs_new_protected:Npn \@@_open_aux:NnTF #1#2 { - \file_add_path:nN {#2} \l_file_internal_name_tl - \quark_if_no_value:NTF \l_file_internal_name_tl + \file_add_path:nN {#2} \l__file_internal_name_tl + \quark_if_no_value:NTF \l__file_internal_name_tl { \prg_return_false: } { - \ior_open_unsafe:No #1 \l_file_internal_name_tl + \@@_open:No #1 \l__file_internal_name_tl \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 \ior_open_unsafe:Nn #1#2 +\cs_new_protected:Npn \@@_open:Nn #1#2 { \ior_close:N #1 - \int_set:Nn \l_ior_stream_int \c_sixteen - \tl_map_function:NN \c_ior_streams_tl \ior_alloc_read:n - \int_compare:nNnTF \l_ior_stream_int = \c_sixteen - { \msg_kernel_fatal:nn { ior } { streams-exhausted } } + \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 } } { - \ior_stream_alloc:N #1 - \prop_gput:NVn \g_ior_streams_prop \l_ior_stream_int {#2} + \@@_alloc:N #1 + \prop_gput:NVn \g_@@_streams_prop \l_@@_stream_int {#2} \tex_openin:D #1#2 \scan_stop: } } -\cs_generate_variant:Nn \ior_open_unsafe:Nn { No } -\cs_new_protected:Npn \iow_open_unsafe:Nn #1#2 - { - \iow_close:N #1 - \int_set:Nn \l_iow_stream_int \c_sixteen - \tl_map_function:NN \c_iow_streams_tl \iow_alloc_write:n - \int_compare:nNnTF \l_iow_stream_int = \c_sixteen - { \msg_kernel_fatal:nn { iow } { streams-exhausted } } - { - \iow_stream_alloc:N #1 - \prop_gput:NVn \g_iow_streams_prop \l_iow_stream_int {#2} - \tex_immediate:D \tex_openout:D #1#2 \scan_stop: - } - } +\cs_generate_variant:Nn \@@_open:Nn { No } % \end{macrocode} % \end{macro} % \end{macro} @@ -1030,114 +957,321 @@ % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\ior_alloc_read:n} -% \begin{macro}[aux]{\iow_alloc_write:n} -% These functions are used to 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}[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{macrocode} -\cs_new_protected:Npn \iow_alloc_write:n #1 +\cs_new_protected:Npn \@@_alloc:n #1 { - \prop_if_in:NnF \g_iow_streams_prop {#1} + \prop_if_in:NnF \g_@@_streams_prop {#1} { - \int_set:Nn \l_iow_stream_int {#1} - \tl_map_break: - } - } -\cs_new_protected:Npn \ior_alloc_read:n #1 - { - \prop_if_in:NnF \g_iow_streams_prop {#1} - { - \int_set:Nn \l_ior_stream_int {#1} + \int_set:Nn \l_@@_stream_int {#1} \tl_map_break: } } % \end{macrocode} % \end{macro} -% \end{macro} % -% \begin{macro}[aux]{\iow_stream_alloc:N, \ior_stream_alloc:N} -% \begin{macro}[aux]{\iow_stream_alloc_aux:, \ior_stream_alloc_aux:} -% \begin{variable}{\g_iow_internal_iow, \g_ior_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{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} -\iow_new:N \g_iow_internal_iow -\ior_new:N \g_ior_internal_ior -\cs_new_protected:Npn \iow_stream_alloc:N #1 +\ior_new:N \g_@@_internal_ior +\cs_new_protected:Npn \@@_alloc:N #1 { - \cs_if_exist:cF { g_iow_ \int_use:N \l_iow_stream_int _iow } + \cs_if_exist:cF { g_ior_ \int_use:N \l_@@_stream_int _ior } { %<*package> - \iow_stream_alloc_aux: - \int_compare:nNnT \l_iow_stream_int = \c_sixteen + \@@_alloc: + \int_compare:nNnT \l_@@_stream_int = \c_sixteen { - \iow_raw_new:N \g_iow_internal_iow - \int_set:Nn \l_iow_stream_int { \g_iow_internal_iow } + \@@_new:N \g_@@_internal_ior + \int_set:Nn \l_@@_stream_int { \g_@@_internal_ior } \cs_gset_eq:cN - { g_iow_ \int_use:N \l_iow_stream_int _iow } \g_iow_internal_iow + { g_ior_ \int_use:N \l_@@_stream_int _ior } \g_@@_internal_ior } %</package> %<*initex> - \iow_raw_new:c { g_iow_ \int_use:N \l_iow_stream_int _iow } + \@@_new:c { g_ior_ \int_use:N \l_@@_stream_int _ior } %</initex> } - \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_iow_stream_int _iow } + \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_@@_stream_int _ior } } %<*package> -\cs_new_protected_nopar:Npn \iow_stream_alloc_aux: +\cs_new_protected_nopar:Npn \@@_alloc: { - \int_incr:N \l_iow_stream_int - \int_compare:nNnT \l_iow_stream_int < \c_sixteen + \int_incr:N \l_@@_stream_int + \int_compare:nNnT \l_@@_stream_int < \c_sixteen { - \cs_if_exist:cTF { g_iow_ \int_use:N \l_iow_stream_int _iow } + \cs_if_exist:cTF { g_ior_ \int_use:N \l_@@_stream_int _ior } { - \prop_if_in:NVT \g_iow_streams_prop \l_iow_stream_int - { \iow_stream_alloc_aux: } + \prop_if_in:NVT \g_@@_streams_prop \l_@@_stream_int + { \@@_alloc: } } - { \iow_stream_alloc_aux: } + { \@@_alloc: } + } + } +%</package> +% \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. +% \begin{macrocode} +\cs_new_protected:Npn \ior_close:N #1 + { + \__chk_if_exist_cs:N #1 + \int_compare:nNnF #1 < \c_zero + { + \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 + } + } + } +\cs_generate_variant:Nn \ior_close:N { c } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_list_streams:} +% \begin{macro}[aux]{\@@_list_streams:Nn} +% Show the property lists, but with some \enquote{pretty printing}. +% See the \pkg{l3msg} module. If there are no open read streams, +% issue the message \texttt{show-no-stream}, and show an empty +% token list. If there are open read streams, format them with +% \cs{__msg_show_item_unbraced:nn}, and with the message +% \texttt{show-open-streams}. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ior_list_streams: + { \@@_list_streams:Nn \g_@@_streams_prop { input } } +\cs_new_protected:Npn \@@_list_streams:Nn #1#2 + { + \__msg_term:nnn { LaTeX / kernel } + { \prop_if_empty:NTF #1 { show-no-stream } { show-open-streams } } + {#2} + \__msg_show_variable:x + { \prop_map_function:NN #1 \__msg_show_item_unbraced:nn } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Reading input} +% +% \begin{macro}[int]{\if_eof:w} +% The primitive conditional +% \begin{macrocode} +\cs_new_eq:NN \if_eof:w \tex_ifeof:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[pTF]{\ior_if_eof:N} +% To test if some particular input stream is exhausted the following +% conditional is provided. +% \begin{macrocode} +\prg_new_conditional:Nnn \ior_if_eof:N { 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: } + { \prg_return_true: } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_get:NN} +% And here we read from files. +% \begin{macrocode} +\cs_new_protected:Npn \ior_get:NN #1#2 + { \tex_read:D #1 to #2 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ior_get_str:NN} +% Reading as strings is also a primitive wrapper. +% \begin{macrocode} +\cs_new_protected:Npn \ior_get_str:NN #1#2 + { \etex_readline:D #1 to #2 } +% \end{macrocode} +% \end{macro} +% +% \subsection{Output operations} +% +% \begin{macrocode} +%<@@=iow> +% \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. +% +% \subsubsection{Variables and constants} +% +% \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}). +% \begin{macrocode} +\cs_new_eq:NN \c_log_iow \c_minus_one +\cs_new_eq:NN \c_term_iow \c_sixteen +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\c_@@_streams_tl} +% The list of streams available, by number: copied from the input +% operations. +% \begin{macrocode} +\cs_new_eq:NN \c_@@_streams_tl \c__ior_streams_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_streams_prop} +% As for reads, but with more reserved as \LaTeXe{} takes up a few here. +% \begin{macrocode} +\prop_new:N \g_@@_streams_prop +%<*package> +\prop_put:Nnn \g_@@_streams_prop { 0 } { LaTeX2e~reserved } +\prop_put:Nnn \g_@@_streams_prop { 1 } { LaTeX2e~reserved } +\prop_put:Nnn \g_@@_streams_prop { 2 } { LaTeX2e~reserved } +%</package> +% \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_new_protected:Npn \ior_stream_alloc:N #1 +\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. +% \begin{macrocode} +\cs_new_protected:Npn \iow_new:N #1 { \cs_new_eq:NN #1 \c_term_iow } +\cs_generate_variant:Nn \iow_new:N { c } +% \end{macrocode} +% \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{macrocode} +\cs_new_protected:Npn \iow_open:Nn #1#2 + { \__file_name_sanitize:nn {#2} { \@@_open:Nn #1 } } +\cs_generate_variant:Nn \iow_open:Nn { c } +\cs_new_protected:Npn \@@_open:Nn #1#2 { - \cs_if_exist:cF { g_ior_ \int_use:N \l_ior_stream_int _ior } + \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 + { \__msg_kernel_fatal:nn { kernel } { output-streams-exhausted } } + { + \@@_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: + } + } +% \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> - \ior_stream_alloc_aux: - \int_compare:nNnT \l_ior_stream_int = \c_sixteen + \@@_alloc: + \int_compare:nNnT \l_@@_stream_int = \c_sixteen { - \ior_raw_new:N \g_ior_internal_ior - \int_set:Nn \l_ior_stream_int { \g_ior_internal_ior } + \@@_new:N \g_@@_internal_iow + \int_set:Nn \l_@@_stream_int { \g_@@_internal_iow } \cs_gset_eq:cN - { g_ior_ \int_use:N \l_iow_stream_int _ior } \g_ior_internal_ior + { g_iow_ \int_use:N \l_@@_stream_int _iow } \g_@@_internal_iow } %</package> %<*initex> - \ior_raw_new:c { g_ior_ \int_use:N \l_ior_stream_int _ior } + \@@_new:c { g_iow_ \int_use:N \l_@@_stream_int _iow } %</initex> } - \cs_gset_eq:Nc #1 { g_ior_ \int_use:N \l_ior_stream_int _ior } + \cs_gset_eq:Nc #1 { g_iow_ \int_use:N \l_@@_stream_int _iow } } %<*package> -\cs_new_protected_nopar:Npn \ior_stream_alloc_aux: +\cs_new_protected_nopar:Npn \@@_alloc: { - \int_incr:N \l_ior_stream_int - \int_compare:nNnT \l_ior_stream_int < \c_sixteen + \int_incr:N \l_@@_stream_int + \int_compare:nNnT \l_@@_stream_int < \c_sixteen { - \cs_if_exist:cTF { g_ior_ \int_use:N \l_ior_stream_int _ior } + \cs_if_exist:cTF { g_iow_ \int_use:N \l_@@_stream_int _iow } { - \prop_if_in:NVT \g_ior_streams_prop \l_ior_stream_int - { \ior_stream_alloc_aux: } + \prop_if_in:NVT \g_@@_streams_prop \l_@@_stream_int + { \@@_alloc: } } - { \ior_stream_alloc_aux: } + { \@@_alloc: } } } %</package> @@ -1146,84 +1280,41 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\ior_close:N, \ior_close:c, \iow_close:N, \iow_close:c} +% \begin{macro}{\iow_close:N, \iow_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. % \begin{macrocode} -\cs_new_protected:Npn \ior_close:N #1 - { - \cs_if_exist:NT #1 - { - \int_compare:nNnF #1 = \c_minus_one - { - \int_compare:nNnF #1 = \c_sixteen - { \tex_closein:D #1 } - \prop_gdel:NV \g_ior_streams_prop #1 - \cs_gset_eq:NN #1 \c_term_ior - } - } - } \cs_new_protected:Npn \iow_close:N #1 { - \cs_if_exist:NT #1 + \__chk_if_exist_cs:N #1 + \int_compare:nNnF #1 < \c_zero { - \int_compare:nNnF #1 = \c_minus_one + \int_compare:nNnF #1 > \c_fifteen { - \int_compare:nNnF #1 = \c_sixteen - { \tex_closein:D #1 } - \prop_gdel:NV \g_iow_streams_prop #1 + \tex_closeout:D #1 + \prop_gremove:NV \g_@@_streams_prop #1 \cs_gset_eq:NN #1 \c_term_iow } } } -\cs_generate_variant:Nn \ior_close:N { c } \cs_generate_variant:Nn \iow_close:N { c } % \end{macrocode} % \end{macro} % -% \begin{macro}{\ior_list_streams:} -% Show the property lists, but with some \enquote{pretty printing}. -% See the \pkg{l3msg} module. If there are no open read streams, -% issue the message \texttt{show-no-stream}, and show an empty -% token list. If there are open read streams, format them with -% \cs{msg_aux_show_unbraced:nn}, and with the message -% \texttt{show-open-streams}. +% \begin{macro}{\iow_list_streams:} +% \begin{macro}{\@@_list_streams:Nn} +% Done as for input, but with a copy of the auxiliary so the name is correct. % \begin{macrocode} -\cs_new_protected_nopar:Npn \ior_list_streams: - { \ior_list_streams_aux:Nn \g_ior_streams_prop { ior } } \cs_new_protected_nopar:Npn \iow_list_streams: - { \ior_list_streams_aux:Nn \g_iow_streams_prop { iow } } -\cs_new_protected:Npn \ior_list_streams_aux:Nn #1#2 - { - \msg_aux_use:nn { LaTeX / #2 } - { \prop_if_empty:NTF #1 { show-no-stream } { show-open-streams } } - \msg_aux_show:x - { \prop_map_function:NN #1 \msg_aux_show_unbraced:nn } - } + { \@@_list_streams:Nn \g_@@_streams_prop { output } } +\cs_new_eq:NN \@@_list_streams:Nn \__ior_list_streams:Nn % \end{macrocode} % \end{macro} +% \end{macro} % -% Text for the error messages. -% \begin{macrocode} -\msg_kernel_new:nnnn { iow } { streams-exhausted } - { Output~streams~exhausted } - { - TeX~can~only~open~up~to~16~output~streams~at~one~time.\\ - All~16 are currently~in~use,~and~something~wanted~to~open - another~one. - } -\msg_kernel_new:nnnn { ior } { streams-exhausted } - { Input~streams~exhausted } - { - TeX~can~only~open~up~to~16~input~streams~at~one~time.\\ - All~16 are currently~in~use,~and~something~wanted~to~open - another~one. - } -% \end{macrocode} -% -% \subsection{Deferred writing} +% \subsubsection{Deferred writing} % % \begin{macro}{\iow_shipout_x:Nn, \iow_shipout_x:Nx} % First the easy part, this is the primitive. @@ -1234,7 +1325,7 @@ % \end{macro} % % \begin{macro}{\iow_shipout:Nn, \iow_shipout:Nx} -% With \eTeX{} available deferred writing is easy. +% With \eTeX{} available deferred writing without expansion is easy. % \begin{macrocode} \cs_new_protected:Npn \iow_shipout:Nn #1#2 { \iow_shipout_x:Nn #1 { \exp_not:n {#2} } } @@ -1242,30 +1333,26 @@ % \end{macrocode} % \end{macro} % -% \subsection{Immediate writing} +% \subsubsection{Immediate writing} % -% \begin{macro}{\iow_now:Nx} -% An abbreviation for an often used operation, which immediately -% writes its second argument expanded to the output stream. -% \begin{macrocode} -\cs_new_protected_nopar:Npn \iow_now:Nx { \tex_immediate:D \iow_shipout_x:Nn } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}{\iow_now:Nn} +% \begin{macro}{\iow_now:Nn, \iow_now:Nx} % This routine writes the second argument onto the output stream without % expansion. If this stream isn't open, the output goes to the terminal % instead. If the first argument is no output stream at all, we get an -% internal error. +% internal error. We don't use the expansion done by \tn{write} to +% get the |Nx| variant, because it differs in subtle ways from +% \texttt{x}-expansion, namely, macro parameter characters would not +% need to be doubled. % \begin{macrocode} \cs_new_protected:Npn \iow_now:Nn #1#2 - { \iow_now:Nx #1 { \exp_not:n {#2} } } + { \tex_immediate:D \iow_shipout_x:Nn #1 { \exp_not:n {#2} } } +\cs_generate_variant:Nn \iow_now:Nn { Nx } % \end{macrocode} % \end{macro} % % \begin{macro}{\iow_log:n, \iow_log:x} % \begin{macro}{\iow_term:n, \iow_term:x} -% Writing to the log and the terminal directly are relatively easy. +% Writing to the log and the terminal directly are relatively easy. % \begin{macrocode} \cs_set_protected_nopar:Npn \iow_log:x { \iow_now:Nx \c_log_iow } \cs_new_protected_nopar:Npn \iow_log:n { \iow_now:Nn \c_log_iow } @@ -1275,7 +1362,7 @@ %\end{macro} %\end{macro} % -% \subsection{Special characters for writing} +% \subsubsection{Special characters for writing} % % \begin{macro}{\iow_newline:} % Global variable holding the character that forces a new line when @@ -1292,83 +1379,87 @@ % \end{macrocode} % \end{macro} % -% \subsection{Hard-wrapping lines based on length} +% \subsubsection{Hard-wrapping lines to a character count} % % The code here implements a generic hard-wrapping function. This is % used by the messaging system, but is designed such that it is % available for other uses. % -% \begin{macro}{\l_iow_line_length_int} -% This 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 +% \begin{macro}[var, added = 2012-06-24]{\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 % \TeX{}Live and Mik\TeX{}. % \begin{macrocode} -\int_new:N \l_iow_line_length_int -\int_set:Nn \l_iow_line_length_int { 78 } +\int_new:N \l_iow_line_count_int +\int_set:Nn \l_iow_line_count_int { 78 } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\l_iow_target_length_int} -% This stores the target line length: the full length minus any -% part for a leader at the start of each line. +% \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{macrocode} -\int_new:N \l_iow_target_length_int +\int_new:N \l_@@_target_count_int % \end{macrocode} % \end{macro} % % \begin{macro}[aux] % { -% \l_iow_current_line_int, -% \l_iow_current_word_int, -% \l_iow_current_indentation_int +% \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{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 +\int_new:N \l_@@_current_line_int +\int_new:N \l_@@_current_word_int +\int_new:N \l_@@_current_indentation_int % \end{macrocode} % \end{macro} % % \begin{macro}[aux] % { -% \l_iow_current_line_tl, -% \l_iow_current_word_tl, -% \l_iow_current_indentation_tl +% \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_iow_current_line_tl -\tl_new:N \l_iow_current_word_tl -\tl_new:N \l_iow_current_indentation_tl +\tl_new:N \l_@@_current_line_tl +\tl_new:N \l_@@_current_word_tl +\tl_new:N \l_@@_current_indentation_tl % \end{macrocode} %\end{macro} % -% \begin{macro}[aux]{\l_iow_wrap_tl} -% Used for the expansion step before detokenizing. +% \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{macrocode} -\tl_new:N \l_iow_wrap_tl +\tl_new:N \l_@@_wrap_tl % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\l_iow_wrapped_tl} -% The output from wrapping text: fully expanded and with lines -% which are not overly long. +% \begin{macro}[aux]{\l_@@_newline_tl} +% The token list inserted to produce the new line, with the +% \meta{run-on text}. % \begin{macrocode} -\tl_new:N \l_iow_wrapped_tl +\tl_new:N \l_@@_newline_tl % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\l_iow_line_start_bool} -% Boolean to avoid adding a space at the beginning of forced newlines. +% \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{macrocode} -\bool_new:N \l_iow_line_start_bool +\bool_new:N \l_@@_line_start_bool % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\c_catcode_other_space_tl} +% \begin{macro}{\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. @@ -1381,49 +1472,45 @@ % \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} +% \begin{macro}[aux]{\c_@@_wrap_marker_tl} +% \begin{macro}[aux] +% { +% \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 preceeded by -% the same recognizable string, \cs{c_iow_wrap_marker_tl}. +% 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_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. +% very important, but makes \cs{c_@@_wrap_marker_tl} look +% nicer. % \begin{macrocode} \group_begin: \int_set_eq:NN \tex_escapechar:D \c_minus_one - \tl_const:Nx \c_iow_wrap_marker_tl + \tl_const:Nx \c_@@_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: +\tl_map_inline:nn + { { end } { newline } { indent } { unindent } } + { + \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{macro} % % \begin{macro}{\iow_indent:n} -% \begin{macro}[aux]{\iow_indent_expandable:n} +% \begin{macro}[aux]{\@@_indent: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 @@ -1432,23 +1519,26 @@ % 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 +\cs_new:Npx \@@_indent:n #1 { - \c_iow_wrap_indent_marker_tl + \c_@@_wrap_indent_marker_tl #1 - \c_iow_wrap_unindent_marker_tl + \c_@@_wrap_unindent_marker_tl } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\iow_wrap:xnnnN} -% 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 -% values. 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. +% \begin{macro}{\iow_wrap:nnnN} +% 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 @@ -1456,16 +1546,9 @@ % expansions. The \cs{tl_to_str:N} step converts the \enquote{other} % space back to a normal space. % \begin{macrocode} -\cs_new_protected:Npn \iow_wrap:xnnnN #1#2#3#4#5 +\cs_new_protected:Npn \iow_wrap:nnnN #1#2#3#4 { \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 \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 \# } @@ -1473,103 +1556,119 @@ \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_@@_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 + \cs_set_eq:NN \iow_indent:n \@@_indent:n + #3 %<*initex> - \tl_set:Nx \l_iow_wrap_tl {#1} + \tl_set:Nx \l_@@_wrap_tl {#1} %</initex> %<*package> - \protected@edef \l_iow_wrap_tl {#1} + \protected@edef \l_@@_wrap_tl {#1} %</package> - \cs_set:Npn \\ { \iow_newline: #2 } +% \end{macrocode} +% 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} + \tl_set:Nx \l_@@_newline_tl { \iow_newline: #2 } + \tl_set:Nx \l_@@_newline_tl { \tl_to_str:N \l_@@_newline_tl } + \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 } + \int_zero:N \l_@@_current_indentation_int + \tl_clear:N \l_@@_current_indentation_tl + \int_zero:N \l_@@_current_line_int + \tl_clear:N \l_@@_current_line_tl + \bool_set_true:N \l_@@_line_start_bool \use:x { - \iow_wrap_loop:w - \tl_to_str:N \l_iow_wrap_tl - \tl_to_str:N \c_iow_wrap_end_marker_tl + \exp_not:n { \tl_clear:N \l_@@_wrap_tl } + \@@_wrap_loop:w + \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: - #5 \l_iow_wrapped_tl + #4 \l_@@_wrap_tl } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux]{\iow_wrap_loop:w} +% \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{macrocode} -\cs_new_protected:Npn \iow_wrap_loop:w #1 ~ % +\cs_new_protected:Npn \@@_wrap_loop:w #1 ~ % { - \tl_set:Nn \l_iow_current_word_tl {#1} - \tl_if_eq:NNTF \l_iow_current_word_tl \c_iow_wrap_marker_tl - { \iow_wrap_special:w } - { \iow_wrap_word: } + \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: } } % \end{macrocode} % \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 +% \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 length) are then put in the new line. +% The current word (and its character count) are then put in the new line. % \begin{macrocode} -\cs_new_protected_nopar:Npn \iow_wrap_word: +\cs_new_protected_nopar:Npn \@@_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 - { \iow_wrap_word_fits: } - { \iow_wrap_word_newline: } - \iow_wrap_loop:w + \int_set:Nn \l_@@_current_word_int + { \__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 } -\cs_new_protected_nopar:Npn \iow_wrap_word_fits: +\cs_new_protected_nopar:Npn \@@_wrap_word_fits: { - \bool_if:NTF \l_iow_line_start_bool + \bool_if:NTF \l_@@_line_start_bool { - \bool_set_false:N \l_iow_line_start_bool - \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 } + \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 } } { - \tl_put_right:Nx \l_iow_current_line_tl - { ~ \l_iow_current_word_tl } - \int_incr:N \l_iow_current_line_int + \tl_put_right:Nx \l_@@_current_line_tl + { ~ \l_@@_current_word_tl } + \int_incr:N \l_@@_current_line_int } } -\cs_new_protected_nopar:Npn \iow_wrap_word_newline: +\cs_new_protected_nopar:Npn \@@_wrap_word_newline: { - \tl_put_right:Nx \l_iow_wrapped_tl - { \l_iow_current_line_tl \\ } - \int_set:Nn \l_iow_current_line_int + \tl_put_right:Nx \l_@@_wrap_tl + { \l_@@_current_line_tl \l_@@_newline_tl } + \int_set:Nn \l_@@_current_line_int { - \l_iow_current_word_int - + \l_iow_current_indentation_int + \l_@@_current_word_int + + \l_@@_current_indentation_int } - \tl_set:Nx \l_iow_current_line_tl - { \l_iow_current_indentation_tl \l_iow_current_word_tl } + \tl_set:Nx \l_@@_current_line_tl + { \l_@@_current_indentation_tl \l_@@_current_word_tl } } % \end{macrocode} % \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} +% \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. @@ -1584,37 +1683,37 @@ % At the end, we simply save the last line (without the run-on text), % and prevent the loop. % \begin{macrocode} -\cs_new_protected:Npn \iow_wrap_special:w #1 ~ #2 ~ #3 ~ % +\cs_new_protected:Npn \@@_wrap_special:w #1 ~ #2 ~ #3 ~ % { - \use:c { iow_wrap_#1: } - \str_if_eq:xxTF { #2~#3 } { ~ \c_iow_wrap_marker_tl } - { \iow_wrap_special:w } - { \iow_wrap_loop:w #2 ~ #3 ~ } + \use:c { @@_wrap_#1: } + \str_if_eq_x:nnTF { #2~#3 } { ~ \c_@@_wrap_marker_tl } + { \@@_wrap_special:w } + { \@@_wrap_loop:w #2 ~ #3 ~ } } -\cs_new_protected_nopar:Npn \iow_wrap_newline: +\cs_new_protected_nopar:Npn \@@_wrap_newline: { - \tl_put_right:Nx \l_iow_wrapped_tl - { \l_iow_current_line_tl \\ } - \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 + \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 } -\cs_new_protected_nopar:Npx \iow_wrap_indent: +\cs_new_protected_nopar:Npx \@@_wrap_indent: { - \int_add:Nn \l_iow_current_indentation_int \c_four - \tl_put_right:Nx \exp_not:N \l_iow_current_indentation_tl + \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 } } -\cs_new_protected_nopar:Npn \iow_wrap_unindent: +\cs_new_protected_nopar:Npn \@@_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 { ~ } } + \int_sub:Nn \l_@@_current_indentation_int \c_four + \tl_set:Nx \l_@@_current_indentation_tl + { \prg_replicate:nn \l_@@_current_indentation_int { ~ } } } -\cs_new_protected_nopar:Npn \iow_wrap_end: +\cs_new_protected_nopar:Npn \@@_wrap_end: { - \tl_put_right:Nx \l_iow_wrapped_tl - { \l_iow_current_line_tl } + \tl_put_right:Nx \l_@@_wrap_tl + { \l_@@_current_line_tl } \use_none_delimit_by_q_stop:w } % \end{macrocode} @@ -1624,29 +1723,29 @@ % \end{macro} % \end{macro} % -% \begin{macro}[aux]{\str_length_skip_spaces:N} -% \begin{macro}[aux]{\str_length_skip_spaces:n} -% \begin{macro}[aux]{\str_length_loop:NNNNNNNNN} +% \begin{macro}[aux]{\__str_count_ignore_spaces:N} +% \begin{macro}[aux]{\__str_count_ignore_spaces:n} +% \begin{macro}[aux]{\__str_count_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 +% in each word. This could be done with \cs{tl_count:n}, but % it is ten times faster (literally) to use the code below. % \begin{macrocode} -\cs_new_nopar:Npn \str_length_skip_spaces:N - { \exp_args:No \str_length_skip_spaces:n } -\cs_new:Npn \str_length_skip_spaces:n #1 +\cs_new_nopar:Npn \__str_count_ignore_spaces:N + { \exp_args:No \__str_count_ignore_spaces:n } +\cs_new:Npn \__str_count_ignore_spaces:n #1 { - \int_value:w \int_eval:w - \exp_after:wN \str_length_loop:NNNNNNNNN \tl_to_str:n {#1} + \__int_value:w \__int_eval:w + \exp_after:wN \__str_count_loop:NNNNNNNNN \tl_to_str:n {#1} { X8 } { X7 } { X6 } { X5 } { X4 } { X3 } { X2 } { X1 } { X0 } \q_stop - \int_eval_end: + \__int_eval_end: } -\cs_new:Npn \str_length_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9 +\cs_new:Npn \__str_count_loop:NNNNNNNNN #1#2#3#4#5#6#7#8#9 { \if_catcode:w X #9 \exp_after:wN \use_none_delimit_by_q_stop:w \else: 9 + - \exp_after:wN \str_length_loop:NNNNNNNNN + \exp_after:wN \__str_count_loop:NNNNNNNNN \fi: } % \end{macrocode} @@ -1654,132 +1753,80 @@ % \end{macro} % \end{macro} % -% \subsection{Reading input} +% \subsection{Messages} % -% \begin{macro}[int]{\if_eof:w} -% The primitive conditional % \begin{macrocode} -\cs_new_eq:NN \if_eof:w \tex_ifeof:D -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[pTF]{\ior_if_eof:N} -% To test if some particular input stream is exhausted the following -% conditional is provided. -% \begin{macrocode} -\prg_new_conditional:Nnn \ior_if_eof:N { p , T , F , TF } +\__msg_kernel_new:nnnn { kernel } { file-not-found } + { File~'#1'~not~found. } { - \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: - } - { \prg_return_true: } + The~requested~file~could~not~be~found~in~the~current~directory,~ + in~the~TeX~search~path~or~in~the~LaTeX~search~path. + } +\__msg_kernel_new:nnnn { kernel } { input-streams-exhausted } + { Input~streams~exhausted } + { + TeX~can~only~open~up~to~16~input~streams~at~one~time.\\ + All~16~are~currently~in~use,~and~something~wanted~to~open~ + another~one. + } +\__msg_kernel_new:nnnn { kernel } { output-streams-exhausted } + { Output~streams~exhausted } + { + TeX~can~only~open~up~to~16~output~streams~at~one~time.\\ + All~16~are~currently~in~use,~and~something~wanted~to~open~ + another~one. + } +\__msg_kernel_new:nnnn { kernel } { space-in-file-name } + { Space~in~file~name~'#1'. } + { + Spaces~are~not~permitted~in~files~loaded~by~LaTeX: \\ + Further~errors~may~follow! } % \end{macrocode} -% \end{macro} % -% \begin{macro}{\ior_to:NN, \ior_gto:NN} -% And here we read from files. -% \begin{macrocode} -\cs_new_protected:Npn \ior_to:NN #1#2 - { \tex_read:D #1 to #2 } -\cs_new_protected:Npn \ior_gto:NN #1#2 - { \tex_global:D \tex_read:D #1 to #2 } -% \end{macrocode} -% \end{macro} +% \subsection{Deprecated functions} % -% \begin{macro}{\ior_str_to:NN, \ior_str_gto:NN} -% Reading as strings is also a primitive wrapper. +% Deprecated on 2012-06-28, for removal by 2012-12-31. +% +% \begin{macro}{\iow_wrap:xnnnN} +% This was renamed and one unneed argument was removed. % \begin{macrocode} -\cs_new_protected:Npn \ior_str_to:NN #1#2 - { \etex_readline:D #1 to #2 } -\cs_new_protected:Npn \ior_str_gto:NN #1#2 - { \tex_global:D \etex_readline:D #1 to #2 } +\cs_new_protected:Npn \iow_wrap:xnnnN #1#2#3#4#5 + { \iow_wrap:nnnN {#1} {#2} {#4} #5 } % \end{macrocode} % \end{macro} % -% \subsection{Experimental functions} +% Deprecated on 2012-06-24, for removal by 2012-12-31. % -% \begin{macro}{\ior_map_inline:Nn, \ior_str_map_inline:Nn} -% \begin{macro}[aux]{\ior_str_map_inline_aux:NNn} -% \begin{macro}[aux]{\ior_str_map_inline_aux:NNNn} -% \begin{macro}[aux]{\ior_str_map_inline_loop:NNN} -% \begin{variable}{\l_ior_internal_tl} -% Mapping to an input stream can be done on either a token or a string -% basis, hence the set up. Within that, there is a check to avoid reading -% past the end of a file, hence the two applications of \cs{ior_if_eof:N}. -% This mapping cannot be nested as the stream has only one \enquote{current -% line}. +% \begin{variable}{\l_iow_line_length_int} +% Simple rename. Here we copy the \TeX{} register. % \begin{macrocode} -\cs_new_protected_nopar:Npn \ior_map_inline:Nn - { \ior_map_inline_aux:NNn \ior_to:NN } -\cs_new_protected_nopar:Npn \ior_str_map_inline:Nn - { \ior_map_inline_aux:NNn \ior_str_to:NN } -\cs_new_protected_nopar:Npn \ior_map_inline_aux:NNn - { - \exp_args:Nc \ior_map_inline_aux:NNNn - { ior_map_ \int_use:N \g_prg_map_int :n } - } -\cs_new_protected:Npn \ior_map_inline_aux:NNNn #1#2#3#4 - { - \cs_set:Npn #1 ##1 {#4} - \int_gincr:N \g_prg_map_int - \ior_if_eof:NF #3 { \ior_map_inline_loop:NNN #1#2#3 } - \prg_break_point:n { \int_gdecr:N \g_prg_map_int } - } -\cs_new_protected:Npn \ior_map_inline_loop:NNN #1#2#3 - { - #2 #3 \l_ior_internal_tl - \ior_if_eof:NF #3 - { - \exp_args:No #1 \l_ior_internal_tl - \ior_map_inline_loop:NNN #1#2#3 - } - } -\tl_new:N \l_ior_internal_tl +\cs_new_eq:NN \l_iow_line_length_int \l_iow_line_count_int % \end{macrocode} % \end{variable} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% \subsection{Messages} % +% \begin{macro}{\ior_to:NN, \ior_gto:NN, \ior_str_to:NN, \ior_str_gto:NN} +% The local variants are renames, while the global variants are +% deprecated and add the \TeX{} primitive \tn{global}. % \begin{macrocode} -\msg_kernel_new:nnnn { file } { file-not-found } - { File~'#1'~not~found. } - { - The~requested~file~could~not~be~found~in~the~current~directory,~ - in~the~TeX~search~path~or~in~the~LaTeX~search~path. - } -\msg_kernel_new:nnnn { file } { space-in-file-name } - { Space~in~file~name~'#1'. } - { - Spaces~are~not~permitted~in~files~loaded~by~LaTeX: \\ - Further~errors~may~follow! - } +\cs_new_eq:NN \ior_to:NN \ior_get:NN +\cs_new_protected_nopar:Npn \ior_gto:NN { \tex_global:D \ior_to:NN } +\cs_new_eq:NN \ior_str_to:NN \ior_get_str:NN +\cs_new_protected_nopar:Npn \ior_str_gto:NN { \tex_global:D \ior_str_to:NN } % \end{macrocode} -% -% \subsection{Deprecated functions} +% \end{macro} % % Deprecated on 2012-02-10, for removal by 2012-05-31. % % \begin{macro}{\iow_now_when_avail:Nn, \iow_now_when_avail:Nx} % For writing only if the stream requested is open at all. % \begin{macrocode} +%<*deprecated> \cs_new_protected:Npn \iow_now_when_avail:Nn #1 { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nn #1 } } \cs_new_protected:Npn \iow_now_when_avail:Nx #1 { \cs_if_free:NTF #1 { \use_none:n } { \iow_now:Nx #1 } } +%</deprecated> % \end{macrocode} % \end{macro} % |