% \iffalse meta-comment % %% File: l3file.dtx Copyright (C) 2009-2011 The LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this %% license or (at your option) any later version. The latest version %% of this license is in the file %% %% http://www.latex-project.org/lppl.txt %% %% This file is part of the "expl3 bundle" (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX3 Project. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} \GetIdInfo$Id: l3file.dtx 2478 2011-06-19 21:34:23Z joseph $ {L3 Experimental file operations} % %<*driver> \documentclass[full]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3file} package\\ File operations^^A % \thanks{This file describes v\ExplFileVersion, % last revised \ExplFileDate.}^^A % } % % \author{^^A % The \LaTeX3 Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released \ExplFileDate} % % \maketitle % % \begin{documentation} % % In contrast to the \pkg{l3io} module, which deals with the lowest % level of file management, the \pkg{l3file} module provides a higher % level interface for handling file contents. This involves providing % convenient wrappers around many of the functions in \pkg{l3io} % to make them more generally accessible. % % It is important to remember that \TeX{} will attempt to locate files using % both the operating system path and entries in the \TeX{} file database (most % \TeX{} systems use such a database). Thus the \enquote{current path} for % \TeX{} is somewhat broader than that for other programs. % % \section{File operation functions} % % \begin{variable}{\g_file_current_name_tl} % Contains the name of the current \LaTeX{} file. This variable % should not be modified: it is intended for information only. It % will be equal to \cs{c_job_name_tl} at the start of a \LaTeX{} % run and will be modified each time a file is read using % \cs{file_input:n}. % \end{variable} % % \begin{function}[TF]{\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{file_path_include:n}). The branching versions then leave % either \meta{true code} or \meta{false code} in the input stream, % as appropriate to the truth of the test and the variant of the % function chosen. % \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}{\file_add_path:nN} % \begin{syntax} % \cs{file_add_path:nN} \Arg{file name} \meta{tl 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{tl var} the % 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 be empty. % \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}{\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. % \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}{\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 for files % by the \cs{file_input:n} and \cs{file_if_exist:n} function. The % assignment is local. % \end{function} % % \begin{function}{\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 for files % by the \cs{file_input:n} and \cs{file_if_exist:n} function. The % assignment is local. % \end{function} % % \begin{function}{\file_list:} % \begin{syntax} % \cs{file_list:} % \end{syntax} % This function will list all files loaded using \cs{file_input:n} % in the log file. % \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} % % \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. % \end{variable} % % \begin{variable}{\l_file_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_search_path_saved_seq} % When loaded on top of \LaTeXe{}, there is a need to save the search % path so that \cs{input@path} can be used as appropriate. % \end{variable} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3file} implementation} % % \TestFiles{m3file001} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \package_check_loaded_expl: % % \end{macrocode} % % \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} %<*initex> \tex_everyjob:D \exp_after:wN { \tex_the:D \tex_everyjob:D \tl_gset:Nx \g_file_current_name_tl { \tex_jobname:D } } % %<*package> \tl_gset_eq:NN \g_file_current_name_tl \@currname % % \end{macrocode} % \end{variable} % % \begin{variable}{\g_file_stack_seq} % The input list of files is stored as a sequence stack. % \begin{macrocode} \seq_new:N \g_file_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{macrocode} %<*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 } % % \end{macrocode} % \end{variable} % % \begin{variable}{\l_file_name_tl} % Used to return the fully-qualified name of a file. % \begin{macrocode} \tl_new:N \l_file_name_tl % \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_file_search_path_saved_seq} % The current search path has to be saved for package use. % \begin{macrocode} %<*package> \seq_new:N \l_file_search_path_saved_seq % % \end{macrocode} % \end{variable} % % \begin{macro}{\file_add_path:nN} % \begin{variable}{\g_file_test_stream} % \begin{macro}[aux]{\file_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 % search has to be made looking at each potential path in turn. The first % location is of course treated as the correct one. If nothing is found, % |#2| is returned empty. % \begin{macrocode} \cs_new_protected_nopar:Npn \file_add_path:nN #1#2 { \ior_open:Nn \g_file_test_stream {#1} \ior_if_eof:NTF \g_file_test_stream { \file_add_path_search:nN {#1} #2 } { \ior_close:N \g_file_test_stream \tl_set:Nx #2 {#1} } } \cs_new_protected_nopar:Npn \file_add_path_search:nN #1#2 { \tl_clear:N #2 %<*package> \cs_if_exist:NT \input@path { \seq_set_eq:NN \l_file_search_path_saved_seq \l_file_search_path_seq \clist_map_inline:Nn \input@path { \seq_put_right:Nn \l_file_search_path_seq {##1} } } % \seq_map_inline:Nn \l_file_search_path_seq { \ior_open:Nn \g_file_test_stream { ##1 #1 } \ior_if_eof:NF \g_file_test_stream { \tl_set:Nx #2 { ##1 #1 } \seq_map_break: } } %<*package> \cs_if_exist:NT \input@path { \seq_set_eq:NN \l_file_search_path_seq \l_file_search_path_saved_seq } % \ior_close:N \g_file_test_stream } % \end{macrocode} % \end{macro} % \end{variable} % \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 will contain % something, whereas if the file was not located then the return value % will be empty. % \begin{macrocode} \prg_new_protected_conditional:Nnn \file_if_exist:n { T , F , TF } { \file_add_path:nN {#1} \l_file_name_tl \tl_if_empty:NTF \l_file_name_tl { \prg_return_false: } { \prg_return_true: } } % \end{macrocode} % \end{macro} % % \begin{macro}{\file_input:n} % Loading a file is done in a safe way, checking first that the file % exists and loading only if it does. % \begin{macrocode} \cs_new_protected_nopar:Npn \file_input:n #1 { \file_add_path:nN {#1} \l_file_name_tl \tl_if_empty:NF \l_file_name_tl { %<*initex> \seq_gput_right:Nx \g_file_record_seq {#1} % %<*package> \@addtofilelist {#1} % \seq_gpush:NV \g_file_stack_seq \g_file_current_name_tl \tl_gset:Nn \g_file_current_name_tl {#1} \exp_after:wN \tex_input:D \l_file_name_tl ~ \seq_gpop:NN \g_file_stack_seq \g_file_current_name_tl } } % \end{macrocode} % \end{macro} % % \begin{macro}{\file_path_include:n} % \begin{macro}{\file_path_remove:n} % Wrapper functions to manage the search path. % \begin{macrocode} \cs_new_protected_nopar:Npn \file_path_include:n #1 { \seq_if_in:NnF \l_file_search_path_seq {#1} { \seq_put_right:Nn \l_file_search_path_seq {#1} } } \cs_new_protected_nopar:Npn \file_path_remove:n #1 { \seq_remove_all:Nn \l_file_search_path_seq {#1} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\file_list:} % A function to list all files used to the log. % \begin{macrocode} \cs_new_protected_nopar:Npn \file_list: { \seq_remove_duplicates:N \g_file_record_seq \iow_log:n { *~File~List~* } \seq_map_inline:Nn \g_file_record_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. % \begin{macrocode} %<*package> \AtBeginDocument { \clist_map_inline:Nn \@filelist { \seq_put_right:Nn \g_file_record_seq {#1} } } % % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex