summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3file.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3file.dtx1248
1 files changed, 602 insertions, 646 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
index 76a88d152d4..25449f418c5 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
@@ -42,7 +42,7 @@
% }^^A
% }
%
-% \date{Released 2018/03/05}
+% \date{Released 2018-04-30}
%
% \maketitle
%
@@ -67,112 +67,7 @@
% using |"| tokens if they contain spaces: as a result, |"| tokens are
% \emph{not} permitted in file names.
%
-% \section{File operation functions}
-%
-% \begin{variable}[added = 2017-06-21]
-% {
-% \g_file_curr_dir_str,
-% \g_file_curr_name_str,
-% \g_file_curr_ext_str
-% }
-% Contain the directory, name and extension of the current file. The
-% directory is empty if the file was loaded without an explicit
-% path (\emph{i.e.}~if it is in the \TeX{} search path), and does
-% \emph{not} end in |/| other than the case that it is exactly equal
-% to the root directory. The \meta{name} and \meta{ext} parts together
-% make up the file name, thus the \meta{name} part may be thought of
-% as the \enquote{job name} for the current file. Note that \TeX{} does
-% not provide information on the \meta{ext} part for the main (top
-% level) file and that this file always has an empty \meta{dir} component.
-% Also, the \meta{name} here will be equal to \cs{c_sys_jobname_str},
-% which may be different from the real file name (if set using
-% |--jobname|, for example).
-% \end{variable}
-%
-% \begin{variable}[added = 2017-06-18]{\l_file_search_path_seq}
-% Each entry is the path to a directory which should be searched when
-% seeking a file. Each path can be relative or absolute, and should
-% not include the trailing slash. The entries are not expanded when
-% used so may contain active characters but should not feature any
-% variable content. Spaces need not be quoted.
-%
-% \begin{texnote}
-% When working as a package in \LaTeXe{}, \pkg{expl3} will
-% automatically append the current \tn{input@path} to the
-% set of values from \cs{l_file_search_path_seq}.
-% \end{texnote}
-% \end{variable}
-%
-% \begin{function}[TF, updated = 2012-02-10]{\file_if_exist:n}
-% \begin{syntax}
-% \cs{file_if_exist:nTF} \Arg{file name} \Arg{true code} \Arg{false code}
-% \end{syntax}
-% Searches for \meta{file name} using the current \TeX{} search
-% path and the additional paths controlled by
-% \cs{l_file_search_path_seq}.
-% \end{function}
-%
-% \begin{function}[updated = 2017-06-26]
-% {\file_get_full_name:nN, \file_get_full_name:VN}
-% \begin{syntax}
-% \cs{file_get_full_name:nN} \Arg{file name} \meta{str var}
-% \end{syntax}
-% Searches for \meta{file name} in the path as detailed for
-% \cs{file_if_exist:nTF}, and if found sets the \meta{str var} the
-% fully-qualified name of the file, \emph{i.e.}~the path and file name.
-% This includes an extension |.tex| when the given \meta{file name}
-% has no extension but the file found has that extension.
-% If the file is not found then the \meta{str var} is empty.
-% \end{function}
-%
-% \begin{function}[added = 2017-06-23, updated = 2017-06-26]
-% {\file_parse_full_name:nNNN}
-% \begin{syntax}
-% \cs{file_parse_full_name:nNNN} \Arg{full name} \meta{dir} \meta{name} \meta{ext}
-% \end{syntax}
-% Parses the \meta{full name} and splits it into three parts, each of
-% which is returned by setting the appropriate local string variable:
-% \begin{itemize}
-% \item The \meta{dir}: everything up to the last |/| (path separator)
-% in the \meta{file path}. As with system \texttt{PATH} variables
-% and related functions, the \meta{dir} does \emph{not} include the
-% trailing |/| unless it points to the root directory. If there is no path (only
-% a file name), \meta{dir} is empty.
-% \item The \meta{name}: everything after the last |/| up to the last |.|,
-% where both of those characters are optional. The \meta{name} may
-% contain multiple |.| characters. It is empty if \meta{full name}
-% consists only of a directory name.
-% \item The \meta{ext}: everything after the last |.| (including the dot).
-% The \meta{ext} is empty if there is no |.| after the last |/|.
-% \end{itemize}
-% This function does not expand the \meta{full name} before turning it
-% to a string. It assume that the \meta{full name} either contains no
-% quote (|"|) characters or is surrounded by a pair of quotes.
-% \end{function}
-%
-% \begin{function}[updated = 2017-06-26]{\file_input:n}
-% \begin{syntax}
-% \cs{file_input:n} \Arg{file name}
-% \end{syntax}
-% Searches for \meta{file name} in the path as detailed for
-% \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 is raised if the file is not found.
-% \end{function}
-%
-% \begin{function}{\file_show_list:, \file_log_list:}
-% \begin{syntax}
-% \cs{file_show_list:}
-% \cs{file_log_list:}
-% \end{syntax}
-% These functions list all files loaded by \LaTeXe{} commands that
-% populate \tn{@filelist} or by \cs{file_input:n}. While
-% \cs{file_show_list:} displays the list in the terminal,
-% \cs{file_log_list:} outputs it to the log file only.
-% \end{function}
-%
-% \subsection{Input--output stream management}
+% \section{Input--output stream management}
%
% As \TeX{} engines have a limited number of input and output streams, direct
% use of the streams by the programmer is not supported in \LaTeX3. Instead, an
@@ -597,7 +492,7 @@
% 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.
+% and \hologo{MiKTeX} systems.
% \end{variable}
%
% \subsection{Constant input--output streams, and variables}
@@ -647,74 +542,109 @@
% \end{texnote}
% \end{function}
%
-% \subsection{Internal file functions and variables}
+% \section{File operation functions}
%
-% \begin{variable}{\g__file_internal_ior}
-% Used to test for the existence of files when opening.
+% \begin{variable}[added = 2017-06-21]
+% {
+% \g_file_curr_dir_str,
+% \g_file_curr_name_str,
+% \g_file_curr_ext_str
+% }
+% Contain the directory, name and extension of the current file. The
+% directory is empty if the file was loaded without an explicit
+% path (\emph{i.e.}~if it is in the \TeX{} search path), and does
+% \emph{not} end in |/| other than the case that it is exactly equal
+% to the root directory. The \meta{name} and \meta{ext} parts together
+% make up the file name, thus the \meta{name} part may be thought of
+% as the \enquote{job name} for the current file. Note that \TeX{} does
+% not provide information on the \meta{ext} part for the main (top
+% level) file and that this file always has an empty \meta{dir} component.
+% Also, the \meta{name} here will be equal to \cs{c_sys_jobname_str},
+% which may be different from the real file name (if set using
+% |--jobname|, for example).
% \end{variable}
%
-% \begin{variable}{\l__file_base_name_str, \l__file_full_name_str}
-% Used to store and transfer the file name (including extension)
-% and (partial) file path whilst reading files. (The file base is the
-% base name plus any preceding directory name.)
+% \begin{variable}[added = 2017-06-18]{\l_file_search_path_seq}
+% Each entry is the path to a directory which should be searched when
+% seeking a file. Each path can be relative or absolute, and should
+% not include the trailing slash. The entries are not expanded when
+% used so may contain active characters but should not feature any
+% variable content. Spaces need not be quoted.
+%
+% \begin{texnote}
+% When working as a package in \LaTeXe{}, \pkg{expl3} will
+% automatically append the current \tn{input@path} to the
+% set of values from \cs{l_file_search_path_seq}.
+% \end{texnote}
% \end{variable}
%
-% \begin{function}[added = 2017-06-25]{\__file_missing:n}
+% \begin{function}[TF, updated = 2012-02-10]{\file_if_exist:n}
% \begin{syntax}
-% \cs{__file_missing:n} \Arg{name}
+% \cs{file_if_exist:nTF} \Arg{file name} \Arg{true code} \Arg{false code}
% \end{syntax}
-% Expands the \meta{name} as per \cs{__file_name_sanitize:nN} then
-% produces an error message indicating that that file was not found.
+% Searches for \meta{file name} using the current \TeX{} search
+% path and the additional paths controlled by
+% \cs{l_file_search_path_seq}.
% \end{function}
%
-% \begin{function}[added = 2017-06-19]{\__file_name_sanitize:nN}
+% \begin{function}[updated = 2017-06-26]
+% {\file_get_full_name:nN, \file_get_full_name:VN}
% \begin{syntax}
-% \cs{__file_name_sanitize:nN} \Arg{name} \meta{str var}
+% \cs{file_get_full_name:nN} \Arg{file name} \meta{str var}
% \end{syntax}
-% Exhaustively-expands the \meta{name} with the exception of any
-% 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{str var} is then set to the \meta{sanitized name}.
+% Searches for \meta{file name} in the path as detailed for
+% \cs{file_if_exist:nTF}, and if found sets the \meta{str var} the
+% fully-qualified name of the file, \emph{i.e.}~the path and file name.
+% This includes an extension |.tex| when the given \meta{file name}
+% has no extension but the file found has that extension.
+% If the file is not found then the \meta{str var} is empty.
% \end{function}
%
-% \begin{function}[added = 2017-06-19, updated = 2017-06-25]
-% {\__file_name_quote:nN}
+% \begin{function}[added = 2017-06-23, updated = 2017-06-26]
+% {\file_parse_full_name:nNNN}
% \begin{syntax}
-% \cs{__file_name_quote:nN} \Arg{name} \meta{str var}
+% \cs{file_parse_full_name:nNNN} \Arg{full name} \meta{dir} \meta{name} \meta{ext}
% \end{syntax}
-% Expands the \meta{name} (without special-casing active tokens), then
-% sets the \meta{str var} to the \meta{name} quoted using |"| at each
-% end if required by the presence of spaces in the \meta{name}. Any existing
-% |"| tokens is removed and if their number is odd an error is raised.
+% Parses the \meta{full name} and splits it into three parts, each of
+% which is returned by setting the appropriate local string variable:
+% \begin{itemize}
+% \item The \meta{dir}: everything up to the last |/| (path separator)
+% in the \meta{file path}. As with system \texttt{PATH} variables
+% and related functions, the \meta{dir} does \emph{not} include the
+% trailing |/| unless it points to the root directory. If there is no path (only
+% a file name), \meta{dir} is empty.
+% \item The \meta{name}: everything after the last |/| up to the last |.|,
+% where both of those characters are optional. The \meta{name} may
+% contain multiple |.| characters. It is empty if \meta{full name}
+% consists only of a directory name.
+% \item The \meta{ext}: everything after the last |.| (including the dot).
+% The \meta{ext} is empty if there is no |.| after the last |/|.
+% \end{itemize}
+% This function does not expand the \meta{full name} before turning it
+% to a string. It assume that the \meta{full name} either contains no
+% quote (|"|) characters or is surrounded by a pair of quotes.
% \end{function}
%
-% \subsection{Internal input--output functions}
-%
-% \begin{function}[added = 2012-01-23]{\__ior_open:Nn, \__ior_open:No}
+% \begin{function}[updated = 2017-06-26]{\file_input:n}
% \begin{syntax}
-% \cs{__ior_open:Nn} \meta{stream} \Arg{file name}
+% \cs{file_input:n} \Arg{file name}
% \end{syntax}
-% 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_get_full_name:nN},
+% Searches for \meta{file name} in the path as detailed for
+% \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 is raised if the file is not found.
% \end{function}
%
-% \begin{function}[added = 2014-08-23]{\__iow_with:Nnn}
+% \begin{function}{\file_show_list:, \file_log_list:}
% \begin{syntax}
-% \cs{__iow_with:Nnn} \meta{integer} \Arg{value} \Arg{code}
+% \cs{file_show_list:}
+% \cs{file_log_list:}
% \end{syntax}
-% If the \meta{integer} is equal to the \meta{value} then this
-% function simply runs the \meta{code}. Otherwise it saves the
-% current value of the \meta{integer}, sets it to the \meta{value},
-% runs the \meta{code}, and restores the \meta{integer} to its former
-% value. This is used to ensure that the \tn{newlinechar} is~$10$
-% when writing to a stream, which lets \cs{iow_newline:} work, and
-% that \tn{errorcontextlines} is $-1$ when displaying a message.
+% These functions list all files loaded by \LaTeXe{} commands that
+% populate \tn{@filelist} or by \cs{file_input:n}. While
+% \cs{file_show_list:} displays the list in the terminal,
+% \cs{file_log_list:} outputs it to the log file only.
% \end{function}
%
% \end{documentation}
@@ -729,427 +659,6 @@
%<*initex|package>
% \end{macrocode}
%
-% \begin{macrocode}
-%<@@=file>
-% \end{macrocode}
-%
-% \subsection{File operations}
-%
-% \begin{variable}
-% {
-% \g_file_curr_dir_str ,
-% \g_file_curr_ext_str ,
-% \g_file_curr_name_str
-% }
-% The name of the current file should be available at all times.
-% For the format the file name needs to be picked up at the start of the
-% run. In \LaTeXe{} package mode the current file name is collected from
-% \tn{@currname}.
-% \begin{macrocode}
-\str_new:N \g_file_curr_dir_str
-\str_new:N \g_file_curr_ext_str
-\str_new:N \g_file_curr_name_str
-%<*initex>
-\tex_everyjob:D \exp_after:wN
- {
- \tex_the:D \tex_everyjob:D
- \str_gset:Nx \g_file_curr_name_str { \tex_jobname:D }
- }
-%</initex>
-%<*package>
-\cs_if_exist:NT \@currname
- { \str_gset_eq:NN \g_file_curr_name_str \@currname }
-%</package>
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\g_@@_stack_seq}
-% The input list of files is stored as a sequence stack. In package
-% mode we can recover the information from the details held by
-% \LaTeXe{} (we must be in the preamble and loaded using \tn{usepackage}
-% or \tn{RequirePackage}). As \LaTeXe{} doesn't store directory and
-% name separately, we stick to the same convention here.
-% \begin{macrocode}
-\seq_new:N \g_@@_stack_seq
-%<*package>
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1#2#3
- {
- \tl_if_blank:nTF {#1}
- {
- \cs_set:Npn \@@_tmp:w ##1 " ##2 " ##3 \q_stop { { } {##2} { } }
- \seq_gput_right:Nx \g_@@_stack_seq
- {
- \exp_after:wN \@@_tmp:w \tex_jobname:D
- " \tex_jobname:D " \q_stop
- }
- }
- {
- \seq_gput_right:Nn \g_@@_stack_seq { { } {#1} {#2} }
- \@@_tmp:w
- }
- }
- \cs_if_exist:NT \@currnamestack
- { \exp_after:wN \@@_tmp:w \@currnamestack }
-\group_end:
-%</package>
-% \end{macrocode}
-% \end{variable}
-%
-% \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_@@_record_seq \g_file_curr_name_str
- }
-%</initex>
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_tmp_tl}
-% Used as a short-term scratch variable.
-% \begin{macrocode}
-\tl_new:N \l_@@_tmp_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l__file_base_name_str, \l__file_full_name_str}
-% For storing the basename and full path whilst passing data internally.
-% \begin{macrocode}
-\str_new:N \l__file_base_name_str
-\str_new:N \l__file_full_name_str
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_dir_str, \l_@@_ext_str, \l_@@_name_str}
-% Used in parsing a path into parts: in contrast to the above, these are
-% never used outside of the current module.
-% \begin{macrocode}
-\str_new:N \l_@@_dir_str
-\str_new:N \l_@@_ext_str
-\str_new:N \l_@@_name_str
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_file_search_path_seq}
-% The current search path.
-% \begin{macrocode}
-\seq_new:N \l_file_search_path_seq
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_tmp_seq}
-% Scratch space for comma list conversion in package mode.
-% \begin{macrocode}
-%<*package>
-\seq_new:N \l_@@_tmp_seq
-%</package>
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\__file_name_sanitize:nN}
-% \begin{macro}{\__file_name_quote:nN}
-% \begin{macro}{\@@_name_sanitize_aux:n}
-% For converting a token list to a string where active characters are treated
-% as strings from the start. The logic to the quoting normalisation is the
-% same as used by \texttt{lualatexquotejobname}: check for balanced |"|, and
-% assuming they balance strip all of them out before quoting the entire name
-% if it contains spaces.
-% \begin{macrocode}
-\cs_new_protected:Npn \__file_name_sanitize:nN #1#2
- {
- \group_begin:
- \seq_map_inline:Nn \l_char_active_seq
- {
- \tl_set:Nx \l_@@_tmp_tl { \iow_char:N ##1 }
- \char_set_active_eq:NN ##1 \l_@@_tmp_tl
- }
- \tl_set:Nx \l_@@_tmp_tl {#1}
- \tl_set:Nx \l_@@_tmp_tl
- { \tl_to_str:N \l_@@_tmp_tl }
- \exp_args:NNNV \group_end:
- \str_set:Nn #2 \l_@@_tmp_tl
- }
-\cs_new_protected:Npn \__file_name_quote:nN #1#2
- {
- \str_set:Nx #2 {#1}
- \int_if_even:nF
- { 0 \tl_map_function:NN #2 \@@_name_quote_aux:n }
- {
- \__kernel_msg_error:nnx
- { kernel } { unbalanced-quote-in-filename } {#2}
- }
- \tl_remove_all:Nn #2 { " }
- \tl_if_in:NnT #2 { ~ }
- { \str_set:Nx #2 { " \exp_not:V #2 " } }
- }
-\cs_new:Npn \@@_name_quote_aux:n #1
- { \token_if_eq_charcode:NNT #1 " { + 1 } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\file_get_full_name:nN, \file_get_full_name:VN}
-% \begin{macro}{\@@_get_full_name_search:nN}
-% The way to test if a file exists is to try to open it: if it does
-% not exist then \TeX{} reports end-of-file. A search is made
-% looking at each potential path in turn (starting from the current
-% directory). The first location is of course treated as the correct
-% one: this is done by jumping to \cs{__prg_break_point:}. If nothing
-% is found, |#2| is returned empty. A special case when there is no
-% extension is that once the first location is found we test the
-% existence of the file with |.tex| extension in that directory, and
-% if it exists we include the |.tex| extension in the result.
-% \begin{macrocode}
-\cs_new_protected:Npn \file_get_full_name:nN #1#2
- {
- \__file_name_sanitize:nN {#1} \l__file_base_name_str
- \@@_get_full_name_search:nN { } \use:n
- \seq_map_inline:Nn \l_file_search_path_seq
- { \@@_get_full_name_search:nN { ##1 / } \seq_map_break:n }
-%<*package>
- \cs_if_exist:NT \input@path
- {
- \tl_map_inline:Nn \input@path
- { \@@_get_full_name_search:nN { ##1 } \tl_map_break:n }
- }
-%</package>
- \str_clear:N \l__file_full_name_str
- \__prg_break_point:
- \str_if_empty:NF \l__file_full_name_str
- {
- \exp_args:NV \file_parse_full_name:nNNN \l__file_full_name_str
- \l_@@_dir_str \l_@@_name_str \l_@@_ext_str
- \str_if_empty:NT \l_@@_ext_str
- {
- \__ior_open:No \g_@@_internal_ior
- { \l__file_full_name_str .tex }
- \ior_if_eof:NF \g_@@_internal_ior
- { \str_put_right:Nn \l__file_full_name_str { .tex } }
- }
- }
- \str_set_eq:NN #2 \l__file_full_name_str
- \ior_close:N \g_@@_internal_ior
- }
-\cs_generate_variant:Nn \file_get_full_name:nN { V }
-\cs_new_protected:Npn \@@_get_full_name_search:nN #1#2
- {
- \__file_name_quote:nN
- { \tl_to_str:n {#1} \l__file_base_name_str }
- \l__file_full_name_str
- \__ior_open:No \g_@@_internal_ior \l__file_full_name_str
- \ior_if_eof:NF \g_@@_internal_ior { #2 { \__prg_break: } }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[TF]{\file_if_exist:n}
-% 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 contains
-% something, whereas if the file was not located then the return value
-% is empty.
-% \begin{macrocode}
-\prg_new_protected_conditional:Npnn \file_if_exist:n #1 { T , F , TF }
- {
- \file_get_full_name:nN {#1} \l__file_full_name_str
- \str_if_empty:NTF \l__file_full_name_str
- { \prg_return_false: }
- { \prg_return_true: }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\__file_missing:n}
-% An error message for a missing file, also used in \cs{ior_open:Nn}.
-% \begin{macrocode}
-\cs_new_protected:Npn \__file_missing:n #1
- {
- \__file_name_sanitize:nN {#1} \l__file_base_name_str
- \__kernel_msg_error:nnx { kernel } { file-not-found }
- { \l__file_base_name_str }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\file_input:n}
-% \begin{macro}{\@@_input:n, \@@_input:V}
-% \begin{macro}{\@@_input_push:n}
-% \begin{macro}{\@@_input_pop:}
-% \begin{macro}{\@@_input_pop:nnn}
-% Loading a file is done in a safe way, checking first that the file
-% 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_get_full_name:nN {#1} \l__file_full_name_str
- \str_if_empty:NTF \l__file_full_name_str
- { \__file_missing:n {#1} }
- { \@@_input:V \l__file_full_name_str }
- }
-\cs_new_protected:Npn \@@_input:n #1
- {
-%<*initex>
- \seq_gput_right:Nn \g_@@_record_seq {#1}
-%</initex>
-%<*package>
- \clist_if_exist:NTF \@filelist
- { \@addtofilelist {#1} }
- { \seq_gput_right:Nn \g_@@_record_seq {#1} }
-%</package>
- \@@_input_push:n {#1}
- \tex_input:D #1 \c_space_tl
- \@@_input_pop:
- }
-\cs_generate_variant:Nn \@@_input:n { V }
-% \end{macrocode}
-% Keeping a track of the file data is easy enough: we store the separated
-% parts so we do not need to parse them twice.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_input_push:n #1
- {
- \seq_gpush:Nx \g_@@_stack_seq
- {
- { \g_file_curr_dir_str }
- { \g_file_curr_name_str }
- { \g_file_curr_ext_str }
- }
- \file_parse_full_name:nNNN {#1}
- \l_@@_dir_str \l_@@_name_str \l_@@_ext_str
- \str_gset_eq:NN \g_file_curr_dir_str \l_@@_dir_str
- \str_gset_eq:NN \g_file_curr_name_str \l_@@_name_str
- \str_gset_eq:NN \g_file_curr_ext_str \l_@@_ext_str
- }
-\cs_new_protected:Npn \@@_input_pop:
- {
- \seq_gpop:NN \g_@@_stack_seq \l_@@_tmp_tl
- \exp_after:wN \@@_input_pop:nnn \l_@@_tmp_tl
- }
-\cs_new_protected:Npn \@@_input_pop:nnn #1#2#3
- {
- \str_gset:Nn \g_file_curr_dir_str {#1}
- \str_gset:Nn \g_file_curr_name_str {#2}
- \str_gset:Nn \g_file_curr_ext_str {#3}
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\file_parse_full_name:nNNN}
-% \begin{macro}
-% {\@@_parse_full_name_auxi:w, \@@_parse_full_name_split:nNNNTF}
-% Parsing starts by stripping off any surrounding quotes. Then find
-% the directory |#4| by splitting at the last~|/|. (The auxiliary
-% returns \texttt{true}/\texttt{false} depending on whether it found
-% the delimiter.) We correct for the case of a file in the root |/|,
-% as in that case we wish to keep the trailing (and only) slash. Then
-% split the base name |#5| at the last dot. If there was indeed a
-% dot, |#5| contains the name and |#6| the extension without the dot,
-% which we add back for convenience. In the special case of no
-% extension given, the auxiliary stored the name into |#6|, we just
-% have to move it to |#5|.
-% \begin{macrocode}
-\cs_new_protected:Npn \file_parse_full_name:nNNN #1#2#3#4
- {
- \exp_after:wN \@@_parse_full_name_auxi:w
- \tl_to_str:n { #1 " #1 " } \q_stop #2#3#4
- }
-\cs_new_protected:Npn \@@_parse_full_name_auxi:w #1 " #2 " #3 \q_stop #4#5#6
- {
- \@@_parse_full_name_split:nNNNTF {#2} / #4 #5
- { \str_if_empty:NT #4 { \str_set:Nn #4 { / } } }
- { }
- \exp_args:No \@@_parse_full_name_split:nNNNTF {#5} . #5 #6
- { \str_put_left:Nn #6 { . } }
- {
- \str_set_eq:NN #5 #6
- \str_clear:N #6
- }
- }
-\cs_new_protected:Npn \@@_parse_full_name_split:nNNNTF #1#2#3#4
- {
- \cs_set_protected:Npn \@@_tmp:w ##1 ##2 #2 ##3 \q_stop
- {
- \tl_if_empty:nTF {##3}
- {
- \str_set:Nn #4 {##2}
- \tl_if_empty:nTF {##1}
- {
- \str_clear:N #3
- \use_ii:nn
- }
- {
- \str_set:Nx #3 { \str_tail:n {##1} }
- \use_i:nn
- }
- }
- { \@@_tmp:w { ##1 #2 ##2 } ##3 \q_stop }
- }
- \@@_tmp:w { } #1 #2 \q_stop
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\file_show_list:, \file_log_list:, \@@_list:N}
-% \begin{macro}[EXP]{\@@_list_aux:n}
-% 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
-% this list of file names into account (we capture it
-% \cs{AtBeginDocument} into \cs{g_@@_record_seq}), turning it to a
-% string (this does not affect the commas of this comma list).
-% \begin{macrocode}
-\cs_new_protected:Npn \file_show_list: { \@@_list:N \msg_show:nnxxxx }
-\cs_new_protected:Npn \file_log_list: { \@@_list:N \msg_log:nnxxxx }
-\cs_new_protected:Npn \@@_list:N #1
- {
- \seq_clear:N \l_@@_tmp_seq
-%<*package>
- \clist_if_exist:NT \@filelist
- {
- \exp_args:NNx \seq_set_from_clist:Nn \l_@@_tmp_seq
- { \tl_to_str:N \@filelist }
- }
-%</package>
- \seq_concat:NNN \l_@@_tmp_seq \l_@@_tmp_seq \g_@@_record_seq
- \seq_remove_duplicates:N \l_@@_tmp_seq
- #1 { LaTeX/kernel } { file-list }
- { \seq_map_function:NN \l_@@_tmp_seq \@@_list_aux:n } { } { } { }
- }
-\cs_new:Npn \@@_list_aux:n #1 { \iow_newline: #1 }
-% \end{macrocode}
-% \end{macro}
-% \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. File names recorded in
-% \cs{@filelist} must be turned to strings before being added to
-% \cs{g_@@_record_seq}.
-% \begin{macrocode}
-%<*package>
-\AtBeginDocument
- {
- \exp_args:NNx \seq_set_from_clist:Nn \l_@@_tmp_seq
- { \tl_to_str:N \@filelist }
- \seq_gconcat:NNN \g_@@_record_seq \g_@@_record_seq \l_@@_tmp_seq
- }
-%</package>
-% \end{macrocode}
-%
% \subsection{Input operations}
%
% \begin{macrocode}
@@ -1195,15 +704,14 @@
% underlying mechanism needs to be queried. For \LaTeXe{} and plain \TeX{}
% this data is stored in |\count16|: with the \pkg{etex} package loaded
% we need to subtract $1$ as the register holds the number of the next
-% stream to use. In Con\TeX{}t, we need to look at |\count38| but there
+% stream to use. In \ConTeXt{}, we need to look at |\count38| but there
% is no subtraction: like the original plain \TeX{}/\LaTeXe{} mechanism
% it holds the value of the \emph{last} stream allocated.
% \begin{macrocode}
\prop_new:N \g_@@_streams_prop
%<*package>
-\int_step_inline:nnnn
+\int_step_inline:nnn
{ 0 }
- { 1 }
{
\cs_if_exist:NTF \normalend
{ \tex_count:D 38 ~ }
@@ -1242,11 +750,18 @@
% Use the conditional version, with an error if the file is not found.
% \begin{macrocode}
\cs_new_protected:Npn \ior_open:Nn #1#2
- { \ior_open:NnF #1 {#2} { \__file_missing:n {#2} } }
+ { \ior_open:NnF #1 {#2} { \__kernel_file_missing:n {#2} } }
\cs_generate_variant:Nn \ior_open:Nn { c }
% \end{macrocode}
% \end{macro}
%
+% \begin{variable}{\l_@@_file_name_str}
+% Data storage.
+% \begin{macrocode}
+\str_new:N \l_@@_file_name_str
+% \end{macrocode}
+% \end{variable}
+%
% \begin{macro}[TF]{\ior_open:Nn, \ior_open:cn}
% An auxiliary searches for the file in the \TeX{}, \LaTeXe{} and
% \LaTeX3 paths. Then pass the file found to the lower-level function
@@ -1255,11 +770,11 @@
% \begin{macrocode}
\prg_new_protected_conditional:Npnn \ior_open:Nn #1#2 { T , F , TF }
{
- \file_get_full_name:nN {#2} \l__file_full_name_str
- \str_if_empty:NTF \l__file_full_name_str
+ \file_get_full_name:nN {#2} \l_@@_file_name_str
+ \str_if_empty:NTF \l_@@_file_name_str
{ \prg_return_false: }
{
- \@@_open:No #1 \l__file_full_name_str
+ \__kernel_ior_open:No #1 \l_@@_file_name_str
\prg_return_true:
}
}
@@ -1283,7 +798,7 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_open:Nn, \@@_open:No}
+% \begin{macro}{\__kernel_ior_open:Nn, \__kernel_ior_open:No}
% \begin{macro}{\@@_open_stream:Nn}
% The stream allocation itself uses the fact that there is a list of all of
% those available, so allocation is simply a question of using the number at
@@ -1293,7 +808,7 @@
% are tracked, so we first try those. If that fails, ask plain \TeX{} or \LaTeXe{}
% for a new stream and use that number (after a bit of conversion).
% \begin{macrocode}
-\cs_new_protected:Npn \@@_open:Nn #1#2
+\cs_new_protected:Npn \__kernel_ior_open:Nn #1#2
{
\ior_close:N #1
\seq_gpop:NNTF \g_@@_streams_seq \l_@@_stream_tl
@@ -1309,7 +824,7 @@
}
%</package>
}
-\cs_generate_variant:Nn \@@_open:Nn { No }
+\cs_generate_variant:Nn \__kernel_ior_open:Nn { No }
\cs_new_protected:Npn \@@_open_stream:Nn #1#2
{
\tex_global:D \tex_chardef:D #1 = \l_@@_stream_tl \scan_stop:
@@ -1412,16 +927,16 @@
%
% \begin{macro}{\ior_str_get:NN}
% Reading as strings is a more complicated wrapper, as we wish to
-% remove the endline character.
+% remove the endline character and restore it afterwards.
% \begin{macrocode}
\cs_new_protected:Npn \ior_str_get:NN #1#2
{
- \use:x
+ \exp_args:Nno \use:n
{
\int_set:Nn \tex_endlinechar:D { -1 }
- \exp_not:n { \etex_readline:D #1 to #2 }
- \int_set:Nn \tex_endlinechar:D { \int_use:N \tex_endlinechar:D }
- }
+ \etex_readline:D #1 to #2
+ \int_set:Nn \tex_endlinechar:D
+ } { \int_use:N \tex_endlinechar:D }
}
% \end{macrocode}
% \end{macro}
@@ -1430,9 +945,9 @@
% Usual map breaking functions.
% \begin{macrocode}
\cs_new:Npn \ior_map_break:
- { \__prg_map_break:Nn \ior_map_break: { } }
+ { \prg_map_break:Nn \ior_map_break: { } }
\cs_new:Npn \ior_map_break:n
- { \__prg_map_break:Nn \ior_map_break: }
+ { \prg_map_break:Nn \ior_map_break: }
% \end{macrocode}
% \end{macro}
%
@@ -1453,16 +968,16 @@
{ \@@_map_inline:NNn \ior_str_get:NN }
\cs_new_protected:Npn \@@_map_inline:NNn
{
- \int_gincr:N \g__prg_map_int
+ \int_gincr:N \g__kernel_prg_map_int
\exp_args:Nc \@@_map_inline:NNNn
- { __prg_map_ \int_use:N \g__prg_map_int :n }
+ { @@_map_ \int_use:N \g__kernel_prg_map_int :n }
}
\cs_new_protected:Npn \@@_map_inline:NNNn #1#2#3#4
{
\cs_gset_protected:Npn #1 ##1 {#4}
\ior_if_eof:NF #3 { \@@_map_inline_loop:NNN #1#2#3 }
- \__prg_break_point:Nn \ior_map_break:
- { \int_gdecr:N \g__prg_map_int }
+ \prg_break_point:Nn \ior_map_break:
+ { \int_gdecr:N \g__kernel_prg_map_int }
}
\cs_new_protected:Npn \@@_map_inline_loop:NNN #1#2#3
{
@@ -1481,13 +996,6 @@
% \end{macro}
% \end{macro}
%
-% \begin{variable}{\g__file_internal_ior}
-% Needed by the higher-level code, but cannot be created until here.
-% \begin{macrocode}
-\ior_new:N \g__file_internal_ior
-% \end{macrocode}
-% \end{variable}
-%
% \subsection{Output operations}
%
% \begin{macrocode}
@@ -1510,30 +1018,30 @@
\int_const:Nn \c_log_iow { -1 }
\int_const:Nn \c_term_iow
{
- \cs_if_exist:NTF \luatex_directlua:D
- {
- \int_compare:nNnTF \luatex_luatexversion:D > { 80 }
- { 128 }
- { 16 }
- }
+ \bool_lazy_and:nnTF
+ { \sys_if_engine_luatex_p: }
+ { \int_compare_p:nNn \luatex_luatexversion:D > { 80 } }
+ { 128 }
{ 16 }
}
% \end{macrocode}
% \end{variable}
%
% \begin{variable}{\g_@@_streams_seq}
-% A list of the currently-available output streams to be used as a stack.
+% A list of the currently-available output streams to be used as a
+% stack. The stream $18$ is special, as \tn{write}18 is used to
+% denote commands to be sent to the OS\@.
% \begin{macrocode}
\seq_new:N \g_@@_streams_seq
%<*initex>
-\use:x
+\exp_args:Nnx \use:n
+ { \seq_gset_split:Nnn \g_@@_streams_seq { } }
{
- \exp_not:n { \seq_gset_split:Nnn \g_@@_streams_seq { } }
- {
- \int_step_function:nnnN { 0 } { 1 } { \c_term_iow }
- \prg_do_nothing:
- }
+ \int_step_function:nnN { 0 } { \c_term_iow }
+ \prg_do_nothing:
}
+\int_compare:nNnF \c_term_iow < { 18 }
+ { \seq_gremove_all:Nn \g_@@_streams_seq { 18 } }
%</initex>
% \end{macrocode}
% \end{variable}
@@ -1551,9 +1059,8 @@
% \begin{macrocode}
\prop_new:N \g_@@_streams_prop
%<*package>
-\int_step_inline:nnnn
+\int_step_inline:nnn
{ 0 }
- { 1 }
{
\cs_if_exist:NTF \normalend
{ \tex_count:D 39 ~ }
@@ -1599,6 +1106,13 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{variable}{\l_@@_file_name_str}
+% Data storage.
+% \begin{macrocode}
+\str_new:N \l_@@_file_name_str
+% \end{macrocode}
+% \end{variable}
+%
% \begin{macro}{\iow_open:Nn, \iow_open:cn}
% \begin{macro}{\@@_open_stream:Nn, \@@_open_stream:NV}
% The same idea as for reading, but without the path and without the need
@@ -1606,10 +1120,10 @@
% \begin{macrocode}
\cs_new_protected:Npn \iow_open:Nn #1#2
{
- \__file_name_sanitize:nN {#2} \l__file_base_name_str
+ \__kernel_file_name_sanitize:nN {#2} \l_@@_file_name_str
\iow_close:N #1
\seq_gpop:NNTF \g_@@_streams_seq \l_@@_stream_tl
- { \@@_open_stream:NV #1 \l__file_base_name_str }
+ { \@@_open_stream:NV #1 \l_@@_file_name_str }
%<*initex>
{ \__kernel_msg_fatal:nn { kernel } { output-streams-exhausted } }
%</initex>
@@ -1617,7 +1131,7 @@
{
\@@_new:N #1
\tl_set:Nx \l_@@_stream_tl { \int_eval:n {#1} }
- \@@_open_stream:NV #1 \l__file_base_name_str
+ \@@_open_stream:NV #1 \l_@@_file_name_str
}
%</package>
}
@@ -1697,20 +1211,20 @@
%
% \subsubsection{Immediate writing}
%
-% \begin{macro}{\@@_with:Nnn}
-% \begin{macro}{\@@_with_aux:nNnn}
+% \begin{macro}{\__kernel_iow_with:Nnn}
+% \begin{macro}{\@@_with:nNnn}
% If the integer~|#1| is equal to~|#2|, just leave~|#3| in the input
% stream. Otherwise, pass the old value to an auxiliary, which sets
% the integer to the new value, runs the code, and restores the
% integer.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_with:Nnn #1#2
+\cs_new_protected:Npn \__kernel_iow_with:Nnn #1#2
{
\int_compare:nNnTF {#1} = {#2}
{ \use:n }
- { \exp_args:No \@@_with_aux:nNnn { \int_use:N #1 } #1 {#2} }
+ { \exp_args:No \@@_with:nNnn { \int_use:N #1 } #1 {#2} }
}
-\cs_new_protected:Npn \@@_with_aux:nNnn #1#2#3#4
+\cs_new_protected:Npn \@@_with:nNnn #1#2#3#4
{
\int_set:Nn #2 {#3}
#4
@@ -1728,14 +1242,14 @@
% get the |Nx| variant, because it differs in subtle ways from
% \texttt{x}-expansion, namely, macro parameter characters would not
% need to be doubled. We set the \tn{newlinechar} to~$10$ using
-% \cs{@@_with:Nnn} to support formats such as plain \TeX{}: otherwise,
+% \cs{__kernel_iow_with:Nnn} to support formats such as plain \TeX{}: otherwise,
% \cs{iow_newline:} would not work. We do not do this for
% \cs{iow_shipout:Nn} or \cs{iow_shipout_x:Nn}, as \TeX{} looks at the
% value of the \tn{newlinechar} at shipout time in those cases.
% \begin{macrocode}
\cs_new_protected:Npn \iow_now:Nn #1#2
{
- \@@_with:Nnn \tex_newlinechar:D { `\^^J }
+ \__kernel_iow_with:Nnn \tex_newlinechar:D { `\^^J }
{ \tex_immediate:D \tex_write:D #1 { \exp_not:n {#2} } }
}
\cs_generate_variant:Nn \iow_now:Nn { c, Nx, cx }
@@ -1781,7 +1295,7 @@
% 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{}.
+% \TeX{}Live and \hologo{MiKTeX}.
% \begin{macrocode}
\int_new:N \l_iow_line_count_int
\int_set:Nn \l_iow_line_count_int { 78 }
@@ -1819,8 +1333,9 @@
\cs_new_protected:Npn \@@_set_indent:n #1
{
\tl_set:Nx \l_@@_one_indent_tl
- { \exp_args:No \__str_to_other_fast:n { \tl_to_str:n {#1} } }
- \int_set:Nn \l_@@_one_indent_int { \str_count:N \l_@@_one_indent_tl }
+ { \exp_args:No \__kernel_str_to_other_fast:n { \tl_to_str:n {#1} } }
+ \int_set:Nn \l_@@_one_indent_int
+ { \str_count:N \l_@@_one_indent_tl }
\exp_last_unbraced:NNo
\cs_set:Npn \@@_unindent:w \l_@@_one_indent_tl { }
}
@@ -1940,10 +1455,14 @@
% \verb*|\ | uses an \enquote{other} space rather than a normal space,
% because the latter might be absorbed by \TeX{} to end a number or
% other \texttt{f}-type expansions.
+% Use \cs{conditionally@traceoff} if defined; it is introduced by the
+% \pkg{trace} package and suppresses uninteresting tracing of the
+% wrapping code.
% \begin{macrocode}
\cs_new_protected:Npn \iow_wrap:nnnN #1#2#3#4
{
\group_begin:
+%<package> \use:c { conditionally@traceoff }
\int_set:Nn \tex_escapechar:D { -1 }
\cs_set:Npx \{ { \token_to_str:N \{ }
\cs_set:Npx \# { \token_to_str:N \# }
@@ -2004,7 +1523,7 @@
{
\tl_set:Nx \l_@@_wrap_tl
{
- \exp_args:No \__str_to_other_fast:n \l_@@_wrap_tl
+ \exp_args:No \__kernel_str_to_other_fast:n \l_@@_wrap_tl
\c_@@_wrap_end_marker_tl
}
\tl_set:Nx \l_@@_wrap_tl
@@ -2115,7 +1634,7 @@
\tex_edef:D \l_@@_line_part_tl { \if_false: } \fi:
#1
\exp_after:wN \@@_wrap_line_loop:w
- \__int_value:w \__int_eval:w
+ \int_value:w \int_eval:w
}
\cs_new:Npn \@@_wrap_line_loop:w #1 ; #2#3#4#5#6#7#8#9
{
@@ -2124,7 +1643,7 @@
\fi:
#2 #3 #4 #5 #6 #7 #8 #9
\exp_after:wN \@@_wrap_line_loop:w
- \__int_value:w \__int_eval:w #1 - 8 ;
+ \int_value:w \int_eval:w #1 - 8 ;
}
\cs_new:Npn \@@_wrap_line_aux:Nw #1#2#3 \exp_after:wN #4 ;
{
@@ -2148,7 +1667,7 @@
\cs_new:Npn \@@_wrap_line_end:NnnnnnnnN #1#2#3#4#5#6#7#8#9
{
#2 #3 #4 #5 #6 #7 #8
- \use_none:nnnnn \__int_eval:w 8 - ; #9
+ \use_none:nnnnn \int_eval:w 8 - ; #9
\token_if_eq_charcode:NNTF \c_space_token #9
{ \@@_wrap_line_end:nw { } }
{ \if_false: { \fi: } \@@_wrap_break:w #9 }
@@ -2160,7 +1679,7 @@
\@@_wrap_next_line:w
}
\cs_new:Npn \@@_wrap_end_chunk:w
- #1 \__int_eval:w #2 - #3 ; #4#5 \q_stop
+ #1 \int_eval:w #2 - #3 ; #4#5 \q_stop
{
\if_false: { \fi: }
\exp_args:Nf \@@_wrap_next:nw { \int_eval:n { #2 - #4 } }
@@ -2333,15 +1852,452 @@
% \begin{macro}[EXP]{\@@_wrap_trim:N, \@@_wrap_trim:w}
% Remove one trailing \enquote{other} space from the argument.
% \begin{macrocode}
-\cs_set_protected:Npn \@@_tmp:w #1
+\cs_new:Npn \@@_wrap_trim:N #1
+ { \tl_if_empty:NF #1 { \exp_after:wN \@@_wrap_trim:w #1 \q_stop } }
+\exp_last_unbraced:NNNNo
+ \cs_new:Npn \@@_wrap_trim:w #1 \c_catcode_other_space_tl \q_stop {#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%<@@=file>
+% \end{macrocode}
+%
+% \subsection{File operations}
+%
+% \begin{variable}{\g_@@_internal_ior}
+% A reserved stream to test for file existence.
+% \begin{macrocode}
+\ior_new:N \g_@@_internal_ior
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}
+% {
+% \g_file_curr_dir_str ,
+% \g_file_curr_ext_str ,
+% \g_file_curr_name_str
+% }
+% The name of the current file should be available at all times.
+% For the format the file name needs to be picked up at the start of the
+% run. In \LaTeXe{} package mode the current file name is collected from
+% \tn{@currname}.
+% \begin{macrocode}
+\str_new:N \g_file_curr_dir_str
+\str_new:N \g_file_curr_ext_str
+\str_new:N \g_file_curr_name_str
+%<*initex>
+\tex_everyjob:D \exp_after:wN
{
- \cs_new:Npn \@@_wrap_trim:N ##1
- { \tl_if_empty:NF ##1 { \exp_after:wN \@@_wrap_trim:w ##1 \q_stop } }
- \cs_new:Npn \@@_wrap_trim:w ##1 #1 \q_stop {##1}
+ \tex_the:D \tex_everyjob:D
+ \str_gset:Nx \g_file_curr_name_str { \tex_jobname:D }
+ }
+%</initex>
+%<*package>
+\cs_if_exist:NT \@currname
+ { \str_gset_eq:NN \g_file_curr_name_str \@currname }
+%</package>
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\g_@@_stack_seq}
+% The input list of files is stored as a sequence stack. In package
+% mode we can recover the information from the details held by
+% \LaTeXe{} (we must be in the preamble and loaded using \tn{usepackage}
+% or \tn{RequirePackage}). As \LaTeXe{} doesn't store directory and
+% name separately, we stick to the same convention here.
+% \begin{macrocode}
+\seq_new:N \g_@@_stack_seq
+%<*package>
+\group_begin:
+ \cs_set_protected:Npn \@@_tmp:w #1#2#3
+ {
+ \tl_if_blank:nTF {#1}
+ {
+ \cs_set:Npn \@@_tmp:w ##1 " ##2 " ##3 \q_stop
+ { { } {##2} { } }
+ \seq_gput_right:Nx \g_@@_stack_seq
+ {
+ \exp_after:wN \@@_tmp:w \tex_jobname:D
+ " \tex_jobname:D " \q_stop
+ }
+ }
+ {
+ \seq_gput_right:Nn \g_@@_stack_seq { { } {#1} {#2} }
+ \@@_tmp:w
+ }
+ }
+ \cs_if_exist:NT \@currnamestack
+ { \exp_after:wN \@@_tmp:w \@currnamestack }
+\group_end:
+%</package>
+% \end{macrocode}
+% \end{variable}
+%
+% \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_@@_record_seq \g_file_curr_name_str
+ }
+%</initex>
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_tmp_tl}
+% Used as a short-term scratch variable.
+% \begin{macrocode}
+\tl_new:N \l_@@_tmp_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_base_name_str, \l_@@_full_name_str}
+% For storing the basename and full path whilst passing data internally.
+% \begin{macrocode}
+\str_new:N \l_@@_base_name_str
+\str_new:N \l_@@_full_name_str
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_dir_str, \l_@@_ext_str, \l_@@_name_str}
+% Used in parsing a path into parts: in contrast to the above, these are
+% never used outside of the current module.
+% \begin{macrocode}
+\str_new:N \l_@@_dir_str
+\str_new:N \l_@@_ext_str
+\str_new:N \l_@@_name_str
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_file_search_path_seq}
+% The current search path.
+% \begin{macrocode}
+\seq_new:N \l_file_search_path_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_tmp_seq}
+% Scratch space for comma list conversion in package mode.
+% \begin{macrocode}
+%<*package>
+\seq_new:N \l_@@_tmp_seq
+%</package>
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\__kernel_file_name_sanitize:nN}
+% \begin{macro}{\@@_name_quote:nN}
+% \begin{macro}{\@@_name_sanitize_aux:n}
+% For converting a token list to a string where active characters are treated
+% as strings from the start. The logic to the quoting normalisation is the
+% same as used by \texttt{lualatexquotejobname}: check for balanced |"|, and
+% assuming they balance strip all of them out before quoting the entire name
+% if it contains spaces.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_file_name_sanitize:nN #1#2
+ {
+ \group_begin:
+ \seq_map_inline:Nn \l_char_active_seq
+ {
+ \tl_set:Nx \l_@@_tmp_tl { \iow_char:N ##1 }
+ \char_set_active_eq:NN ##1 \l_@@_tmp_tl
+ }
+ \tl_set:Nx \l_@@_tmp_tl {#1}
+ \tl_set:Nx \l_@@_tmp_tl
+ { \tl_to_str:N \l_@@_tmp_tl }
+ \exp_args:NNNV \group_end:
+ \str_set:Nn #2 \l_@@_tmp_tl
+ }
+\cs_new_protected:Npn \@@_name_quote:nN #1#2
+ {
+ \str_set:Nx #2 {#1}
+ \int_if_even:nF
+ { 0 \tl_map_function:NN #2 \@@_name_quote_aux:n }
+ {
+ \__kernel_msg_error:nnx
+ { kernel } { unbalanced-quote-in-filename } {#2}
+ }
+ \tl_remove_all:Nn #2 { " }
+ \tl_if_in:NnT #2 { ~ }
+ { \str_set:Nx #2 { " \exp_not:V #2 " } }
+ }
+\cs_new:Npn \@@_name_quote_aux:n #1
+ { \token_if_eq_charcode:NNT #1 " { + 1 } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\file_get_full_name:nN, \file_get_full_name:VN}
+% \begin{macro}{\@@_get_full_name_search:nN}
+% The way to test if a file exists is to try to open it: if it does
+% not exist then \TeX{} reports end-of-file. A search is made
+% looking at each potential path in turn (starting from the current
+% directory). The first location is of course treated as the correct
+% one: this is done by jumping to \cs{prg_break_point:}. If nothing
+% is found, |#2| is returned empty. A special case when there is no
+% extension is that once the first location is found we test the
+% existence of the file with |.tex| extension in that directory, and
+% if it exists we include the |.tex| extension in the result.
+% \begin{macrocode}
+\cs_new_protected:Npn \file_get_full_name:nN #1#2
+ {
+ \__kernel_file_name_sanitize:nN {#1} \l_@@_base_name_str
+ \@@_get_full_name_search:nN { } \use:n
+ \seq_map_inline:Nn \l_file_search_path_seq
+ { \@@_get_full_name_search:nN { ##1 / } \seq_map_break:n }
+%<*package>
+ \cs_if_exist:NT \input@path
+ {
+ \tl_map_inline:Nn \input@path
+ { \@@_get_full_name_search:nN { ##1 } \tl_map_break:n }
+ }
+%</package>
+ \str_clear:N \l_@@_full_name_str
+ \prg_break_point:
+ \str_if_empty:NF \l_@@_full_name_str
+ {
+ \exp_args:NV \file_parse_full_name:nNNN \l_@@_full_name_str
+ \l_@@_dir_str \l_@@_name_str \l_@@_ext_str
+ \str_if_empty:NT \l_@@_ext_str
+ {
+ \__kernel_ior_open:No \g_@@_internal_ior
+ { \l_@@_full_name_str .tex }
+ \ior_if_eof:NF \g_@@_internal_ior
+ { \str_put_right:Nn \l_@@_full_name_str { .tex } }
+ }
+ }
+ \str_set_eq:NN #2 \l_@@_full_name_str
+ \ior_close:N \g_@@_internal_ior
+ }
+\cs_generate_variant:Nn \file_get_full_name:nN { V }
+\cs_new_protected:Npn \@@_get_full_name_search:nN #1#2
+ {
+ \@@_name_quote:nN
+ { \tl_to_str:n {#1} \l_@@_base_name_str }
+ \l_@@_full_name_str
+ \__kernel_ior_open:No \g_@@_internal_ior \l_@@_full_name_str
+ \ior_if_eof:NF \g_@@_internal_ior { #2 { \prg_break: } }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[TF]{\file_if_exist:n}
+% 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 contains
+% something, whereas if the file was not located then the return value
+% is empty.
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \file_if_exist:n #1 { T , F , TF }
+ {
+ \file_get_full_name:nN {#1} \l_@@_full_name_str
+ \str_if_empty:NTF \l_@@_full_name_str
+ { \prg_return_false: }
+ { \prg_return_true: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_file_missing:n}
+% An error message for a missing file, also used in \cs{ior_open:Nn}.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_file_missing:n #1
+ {
+ \__kernel_file_name_sanitize:nN {#1} \l_@@_base_name_str
+ \__kernel_msg_error:nnx { kernel } { file-not-found }
+ { \l_@@_base_name_str }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\file_input:n}
+% \begin{macro}{\@@_input:n, \@@_input:V}
+% \begin{macro}{\@@_input_push:n, \__kernel_file_input_push:n}
+% \begin{macro}{\@@_input_pop:, \__kernel_file_input_pop:}
+% \begin{macro}{\@@_input_pop:nnn}
+% Loading a file is done in a safe way, checking first that the file
+% 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_get_full_name:nN {#1} \l_@@_full_name_str
+ \str_if_empty:NTF \l_@@_full_name_str
+ { \__kernel_file_missing:n {#1} }
+ { \@@_input:V \l_@@_full_name_str }
+ }
+\cs_new_protected:Npn \@@_input:n #1
+ {
+%<*initex>
+ \seq_gput_right:Nn \g_@@_record_seq {#1}
+%</initex>
+%<*package>
+ \clist_if_exist:NTF \@filelist
+ { \@addtofilelist {#1} }
+ { \seq_gput_right:Nn \g_@@_record_seq {#1} }
+%</package>
+ \@@_input_push:n {#1}
+ \tex_input:D #1 \c_space_tl
+ \@@_input_pop:
+ }
+\cs_generate_variant:Nn \@@_input:n { V }
+% \end{macrocode}
+% Keeping a track of the file data is easy enough: we store the separated
+% parts so we do not need to parse them twice.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_input_push:n #1
+ {
+ \seq_gpush:Nx \g_@@_stack_seq
+ {
+ { \g_file_curr_dir_str }
+ { \g_file_curr_name_str }
+ { \g_file_curr_ext_str }
+ }
+ \file_parse_full_name:nNNN {#1}
+ \l_@@_dir_str \l_@@_name_str \l_@@_ext_str
+ \str_gset_eq:NN \g_file_curr_dir_str \l_@@_dir_str
+ \str_gset_eq:NN \g_file_curr_name_str \l_@@_name_str
+ \str_gset_eq:NN \g_file_curr_ext_str \l_@@_ext_str
+ }
+%<*package>
+\cs_new_eq:NN \__kernel_file_input_push:n \__file_input_push:n
+%</package>
+\cs_new_protected:Npn \@@_input_pop:
+ {
+ \seq_gpop:NN \g_@@_stack_seq \l_@@_tmp_tl
+ \exp_after:wN \@@_input_pop:nnn \l_@@_tmp_tl
+ }
+%<*package>
+\cs_new_eq:NN \__kernel_file_input_pop: \__file_input_pop:
+%</package>
+\cs_new_protected:Npn \@@_input_pop:nnn #1#2#3
+ {
+ \str_gset:Nn \g_file_curr_dir_str {#1}
+ \str_gset:Nn \g_file_curr_name_str {#2}
+ \str_gset:Nn \g_file_curr_ext_str {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\file_parse_full_name:nNNN}
+% \begin{macro}
+% {\@@_parse_full_name_auxi:w, \@@_parse_full_name_split:nNNNTF}
+% Parsing starts by stripping off any surrounding quotes. Then find
+% the directory |#4| by splitting at the last~|/|. (The auxiliary
+% returns \texttt{true}/\texttt{false} depending on whether it found
+% the delimiter.) We correct for the case of a file in the root |/|,
+% as in that case we wish to keep the trailing (and only) slash. Then
+% split the base name |#5| at the last dot. If there was indeed a
+% dot, |#5| contains the name and |#6| the extension without the dot,
+% which we add back for convenience. In the special case of no
+% extension given, the auxiliary stored the name into |#6|, we just
+% have to move it to |#5|.
+% \begin{macrocode}
+\cs_new_protected:Npn \file_parse_full_name:nNNN #1#2#3#4
+ {
+ \exp_after:wN \@@_parse_full_name_auxi:w
+ \tl_to_str:n { #1 " #1 " } \q_stop #2#3#4
+ }
+\cs_new_protected:Npn \@@_parse_full_name_auxi:w
+ #1 " #2 " #3 \q_stop #4#5#6
+ {
+ \@@_parse_full_name_split:nNNNTF {#2} / #4 #5
+ { \str_if_empty:NT #4 { \str_set:Nn #4 { / } } }
+ { }
+ \exp_args:No \@@_parse_full_name_split:nNNNTF {#5} . #5 #6
+ { \str_put_left:Nn #6 { . } }
+ {
+ \str_set_eq:NN #5 #6
+ \str_clear:N #6
+ }
+ }
+\cs_new_protected:Npn \@@_parse_full_name_split:nNNNTF #1#2#3#4
+ {
+ \cs_set_protected:Npn \@@_tmp:w ##1 ##2 #2 ##3 \q_stop
+ {
+ \tl_if_empty:nTF {##3}
+ {
+ \str_set:Nn #4 {##2}
+ \tl_if_empty:nTF {##1}
+ {
+ \str_clear:N #3
+ \use_ii:nn
+ }
+ {
+ \str_set:Nx #3 { \str_tail:n {##1} }
+ \use_i:nn
+ }
+ }
+ { \@@_tmp:w { ##1 #2 ##2 } ##3 \q_stop }
+ }
+ \@@_tmp:w { } #1 #2 \q_stop
}
-\exp_args:NV \@@_tmp:w \c_catcode_other_space_tl
% \end{macrocode}
% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\file_show_list:, \file_log_list:, \@@_list:N}
+% \begin{macro}[EXP]{\@@_list_aux:n}
+% 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
+% this list of file names into account (we capture it
+% \cs{AtBeginDocument} into \cs{g_@@_record_seq}), turning it to a
+% string (this does not affect the commas of this comma list).
+% \begin{macrocode}
+\cs_new_protected:Npn \file_show_list: { \@@_list:N \msg_show:nnxxxx }
+\cs_new_protected:Npn \file_log_list: { \@@_list:N \msg_log:nnxxxx }
+\cs_new_protected:Npn \@@_list:N #1
+ {
+ \seq_clear:N \l_@@_tmp_seq
+%<*package>
+ \clist_if_exist:NT \@filelist
+ {
+ \exp_args:NNx \seq_set_from_clist:Nn \l_@@_tmp_seq
+ { \tl_to_str:N \@filelist }
+ }
+%</package>
+ \seq_concat:NNN \l_@@_tmp_seq \l_@@_tmp_seq \g_@@_record_seq
+ \seq_remove_duplicates:N \l_@@_tmp_seq
+ #1 { LaTeX/kernel } { file-list }
+ { \seq_map_function:NN \l_@@_tmp_seq \@@_list_aux:n }
+ { } { } { }
+ }
+\cs_new:Npn \@@_list_aux:n #1 { \iow_newline: #1 }
+% \end{macrocode}
+% \end{macro}
+% \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. File names recorded in
+% \cs{@filelist} must be turned to strings before being added to
+% \cs{g_@@_record_seq}.
+% \begin{macrocode}
+%<*package>
+\AtBeginDocument
+ {
+ \exp_args:NNx \seq_set_from_clist:Nn \l_@@_tmp_seq
+ { \tl_to_str:N \@filelist }
+ \seq_gconcat:NNN
+ \g_@@_record_seq
+ \g_@@_record_seq
+ \l_@@_tmp_seq
+ }
+%</package>
+% \end{macrocode}
%
% \subsection{Messages}
%
@@ -2399,7 +2355,7 @@
\tl_gset:Nn \g_file_current_name_tl { \g_file_curr_name_str }
\__kernel_deprecation_code:nn
{
- \__deprecation_error:Nnn \g_file_current_name_tl
+ \__kernel_deprecation_error:Nnn \g_file_current_name_tl
{ \g_file_curr_name_str } { 2018-12-31 }
}
{ \tex_def:D \g_file_current_name_tl { \g_file_curr_name_str } }
@@ -2414,16 +2370,16 @@
{ \seq_put_right:Nn \l_file_search_path_seq }
\cs_new_protected:Npn \file_path_include:n #1
{
- \__file_name_sanitize:nN {#1} \l__file_full_name_str
- \seq_if_in:NVF \l_file_search_path_seq \l__file_full_name_str
- { \seq_put_right:NV \l_file_search_path_seq \l__file_full_name_str }
+ \__kernel_file_name_sanitize:nN {#1} \l_@@_full_name_str
+ \seq_if_in:NVF \l_file_search_path_seq \l_@@_full_name_str
+ { \seq_put_right:NV \l_file_search_path_seq \l_@@_full_name_str }
}
\__kernel_patch_deprecation:nnNNpn { 2018-12-31 }
{ \seq_remove_all:Nn \l_file_search_path_seq }
\cs_new_protected:Npn \file_path_remove:n #1
{
- \__file_name_sanitize:nN {#1} \l__file_full_name_str
- \seq_remove_all:NV \l_file_search_path_seq \l__file_full_name_str
+ \__kernel_file_name_sanitize:nN {#1} \l_@@_full_name_str
+ \seq_remove_all:NV \l_file_search_path_seq \l_@@_full_name_str
}
% \end{macrocode}
% \end{macro}