% \iffalse
%% File: l3file.dtx Copyright (C) 2009 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 LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%% 
%
%<*driver|package>
\RequirePackage{l3names}
%</driver|package>
%\fi
\GetIdInfo$Id: l3file.dtx 1352 2009-05-28 11:50:39Z morten $
  {L3 Experimental file loading}
%\iffalse
%<*driver>
%\fi
\ProvidesFile{\filename.\filenameext}
  [\filedate\space v\fileversion\space\filedescription]
%\iffalse
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{l3file.dtx}
\end{document}
%</driver>
% \fi
%
% \title{The \textsf{l3file} package\thanks{This file
%         has version number \fileversion, last
%         revised \filedate.}\\
% File Loading}
% \author{\Team}
% \date{\filedate}
% \maketitle
%
% \begin{documentation}
%
%\section{Loading files}
% 
% The need to test if a file is available and to load a file if found is 
% covered at a low level here.
% 
%\begin{function}{
%  \file_if_exist_p:n|
%  \file_if_exist:n / (TF)
%}
%  \begin{syntax}
%    "\file_if_exist:nTF" <file> <true code> <false code>
%  \end{syntax}
%  Tests if <file> exists.
%  \begin{texnote}
%    This is \LaTeXe's \cs{IfFileExists}, although it does not return
%    name of the file (\emph{cf.}~\cs{@filef@und}).
%  \end{texnote}
%\end{function} 
%
%\begin{function}{\file_add_path:nN}
%  \begin{syntax}
%    "\file_add_path:nN" <file> <tl~var.>
%  \end{syntax}
%  Searches for <file> on the \TeX\ path and using 
%  \cs{l_file_search_path_clist}. If <file> is found, <tl~var.> is set
%  to the file name plus any path information needed.  If <file> is not 
%  found, <tl~var.> will be blank.
%  \begin{texnote}
%    This is similar to obtaining \cs{@filef@und} from \LaTeXe's 
%    \cs{IfFileExists}.
%  \end{texnote}
%\end{function} 
%
%\begin{function}{\file_input:n}
%  \begin{syntax}
%    "\file_input:n" <file>
%  \end{syntax}
%  Inputs <file> if it found (according to the same rule as for
%  \cs{file_if_exist:n}.
%  \begin{texnote}
%    This acts in a similar way to \LaTeXe's \cs{input}, as it will not
%    lead to a \TeX\ loop if the file is not found.
%  \end{texnote}
%\end{function}
%
%\begin{function}{\file_input_no_record:n}
%  \begin{syntax}
%    "\file_input_no_record:n" <file>
%  \end{syntax}
%  Inputs <file> if it found (according to the same rule as for
%  \cs{file_if_exist:n}, but does not add it to 
%  \cs{g_file_record_clist}. The file is still added to 
%  \cs{g_file_record_full_clist}.
%  \begin{texnote}
%    This is similar to \LaTeXe's \cs{@input@}.
%  \end{texnote}
%\end{function}
%
%\begin{function}{
%  \file_input_no_check:n|
%  \file_input_no_check_no_record:n|
%}
%  \begin{syntax}
%    "\file_input_no_check:n" <file>
%  \end{syntax}
%  Inputs <file> directly without checking if it exists. The 
%  \texttt{no_record} version does not record the input in 
%  \begin{texnote}\cs{g_file_record_clist}.
%    These are simple wrappers around the \TeX\ \cs{input} primitive
%  \end{texnote}
%\end{function}
%
%\begin{function}{
%  \file_list:|
%  \file_list_full:|
%}
%  \begin{syntax}
%    "\file_list:" <file>
%  \end{syntax}
%  Lists files loaded in current \LaTeX\ run: the \texttt{full} version
%  lists all files.
%\end{function}
%
%\section{Variables and constants}
%
%\begin{variable}{
%  \g_file_record_clist|
%  \g_file_record_full_clist
%}
%  Used to track the files that have been loaded.
%\end{variable}
%
%\begin{variable}{\l_file_search_path_clist}
%  List of paths to search for a file in addition to those searched by
%  \TeX.
%  \begin{texnote}
%    This is \cs{input@path} in \LaTeXe.
%  \end{texnote}
%\end{variable}
%
%\begin{variable}{\l_file_test_read_stream}
%  Input stream used to carry out file tests.
%\end{variable}
%
%\begin{variable}{\l_file_tmp_bool}
%  Internal scratch switch.
%\end{variable}
%
%\begin{variable}{\l_file_tmp_tl}
%  Internal scratch token list variable.
%\end{variable}
% 
% \end{documentation}
% 
% \begin{implementation}
%
% \section{\pkg{l3file} implementation}
%
% The usual lead-off.
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage
  {\filename}{\filedate}{\fileversion}{\filedescription}
\package_check_loaded_expl:
%</package>
%<*initex|package>
%    \end{macrocode}
%
%\begin{macro}{\g_file_record_clist}
%\begin{macro}{\g_file_record_full_clist}
% When files are read with logging, the names are added here. There are
% two lists, one for everything and one for only those items which might
% later be listed (as in \LaTeXe's \cs{listfiles}).
%    \begin{macrocode}
\clist_new:N \g_file_record_clist
\clist_new:N \g_file_record_full_clist
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\l_file_search_path_clist}
% Checking input needs a stream to work with
%    \begin{macrocode}
\clist_new:N \l_file_search_path_clist
%    \end{macrocode}
%\end{macro}
%    
%\begin{macro}{\l_file_test_read_stream}
% Checking input needs a stream to work with
%    \begin{macrocode}
\ior_new:N \l_file_test_read_stream
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\l_file_tmp_bool}
% A flag is needed for internal purposes.
%    \begin{macrocode}
\bool_new:N \l_file_tmp_bool
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\l_file_tmp_tl}
% A scratch token list variable.
%    \begin{macrocode}
\tl_new:N \l_file_tmp_tl
%    \end{macrocode}
%\end{macro}
%   
%\begin{macro}{\file_if_exist_p:n} 
%\begin{macro}[TF]{\file_if_exist:n}
%\begin{macro}[aux]{\file_if_exist_path:n}
%\begin{macro}[aux]{\file_if_exist_aux:n}
% Checking if a file exists takes place in two parts. First, there is
% a simple check ``here''. If that fails, then there is a loop over
% the current search path.
%    \begin{macrocode}
\prg_new_conditional:Nnn \file_if_exist:n {p,TF,T,F} {
  \ior_open:Nn \l_file_test_read_stream {#1}
  \ior_if_eof:NTF \l_file_test_read_stream {
    \file_if_exist_path:n {#1}
  }{
    \ior_close:N \l_file_test_read_stream
    \prg_return_true:
  }
}
\cs_new_nopar:Nn \file_if_exist_path:n {
  \bool_set_false:N \l_file_tmp_bool
  \cs_set_nopar:Nn \file_if_exist_aux:n {
    \ior_open:Nn \l_file_test_read_stream { #1 ##1 }
    \ior_if_eof:NF \l_file_test_read_stream {
      \bool_set_true:N \l_file_tmp_bool
      \clist_map_break:
    }
  } 
%</initex|package>
%<*package>
  \cs_if_exist:NT \input@path {
    \cs_set_eq:NN \l_file_search_path_clist \input@path
  }
%</package>
%<*initex|package>
  \clist_map_function:NN \l_file_search_path_clist \file_if_exist_aux:n
  \ior_close:N \l_file_test_read_stream
  \bool_if:NTF \l_file_tmp_bool {
    \prg_return_true:
  }{
    \prg_return_false:
  }
}
\cs_new_nopar:Nn \file_if_exist_aux:n { }
%    \end{macrocode}
%\end{macro}    
%\end{macro}  
%\end{macro}  
%\end{macro} 
%
%\begin{macro}{\file_add_path:nN}
%\begin{macro}[aux]{\file_add_path_search:n}
%\begin{macro}[aux]{\file_add_path_aux:n}
% Checking if a file exists takes place in two parts. First, there is
% a simple check ``here''. If that fails, then there is a loop over
% the current search path.
%    \begin{macrocode}
\cs_new_nopar:Nn \file_add_path:nN {
  \tl_clear:N #2
  \ior_open:Nn \l_file_test_read_stream {#1}
  \ior_if_eof:NTF \l_file_test_read_stream {
    \file_add_path_search:nN {#1} #2
  }{
    \tl_set:Nn #2 {#1}
  }
  \ior_close:N \l_file_test_read_stream
}
\cs_new_nopar:Nn \file_add_path_search:nN {
  \cs_set_nopar:Nn \file_add_path_aux:n {
    \ior_open:Nn \l_file_test_read_stream { ##1 #1 }
    \ior_if_eof:NF \l_file_test_read_stream {
      \tl_set:Nn #2 { ##1 #1 }
      \clist_map_break:
    }
  } 
%</initex|package>
%<*package>
  \cs_if_exist:NT \input@path {
    \cs_set_eq:NN \l_file_search_path_clist \input@path
  }
%</package>
%<*initex|package>
  \clist_map_function:NN \l_file_search_path_clist \file_add_path_aux:n
}
\cs_new_nopar:Nn \file_add_path_aux:n { }
%    \end{macrocode}
%\end{macro}    
%\end{macro}  
%\end{macro} 
%
%\begin{macro}{\file_input:n}
%\begin{macro}{\file_input_no_record:n}
% \cs{file_add_path:nN} will return an empty token list variable if the 
% file is not found. This is used rather than \cs{file_if_exist:nT} here
% as it saves running the same loop twice.
%    \begin{macrocode}
\cs_new:Nn \file_input:n {
  \file_add_path:nN {#1} \l_file_tmp_tl
  \tl_if_empty:NF \l_file_tmp_tl {
    \file_input_no_check:n \l_file_tmp_tl
  }
}
\cs_new:Nn \file_input_no_record:n {
  \file_add_path:nN {#1} \l_file_tmp_tl
  \tl_if_empty:NF \l_file_tmp_tl {
    \file_input_no_check_no_record:n \l_file_tmp_tl
  }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%    
%\begin{macro}{\file_input_no_check:n}
% File input records what is going on before setting to work.
%    \begin{macrocode}
\cs_new_nopar:Nn \file_input_no_check:n {
  \clist_gput_right:Nx \g_file_record_clist {#1}
  \wlog{ADDING: #1}
%</initex|package>
%<*package>
  \@addtofilelist {#1}
%</package>
%<*initex|package>
  \clist_gput_right:Nx \g_file_record_full_clist {#1}
  \tex_input:D #1 ~
}
%    \end{macrocode}
%\end{macro}
%\begin{macro}{\file_input_no_check_no_record:n}
% Inputting a file without adding to the main record is basically the
% same: even in this case the file goes on the full log.
%    \begin{macrocode}
\cs_new_nopar:Nn \file_input_no_check_no_record:n {
  \clist_gput_right:Nx \g_file_record_full_clist {#1}
  \tex_input:D #1 ~
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\file_list:}
%\begin{macro}{\file_list_full:}
%\begin{macro}[aux]{\file_list:N}
% Two functions to list all files used to the log: the \texttt{full}
% version includes everything whereas the standard version uses the 
% shorter record.
%    \begin{macrocode}
\cs_new_nopar:Nn \file_list: {
  \file_list:N \g_file_record_clist
}
\cs_new_nopar:Nn \file_list_full: {
  \file_list:N \g_file_record_full_clist
}
\cs_new_nopar:Nn \file_list:N {
  \clist_remove_duplicates:N #1
  \iow_log:x { *~File~List~* }
  \clist_map_function:NN #1 \file_list_aux:n
  \iow_log:x { ************* }
}
\cs_new_nopar:Nn \file_list_aux:n {
  \iow_log:x { #1 }
}
%    \end{macrocode}
%\end{macro}
%\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.
%    \begin{macrocode}
%</initex|package>
%<*package>
%    \begin{macrocode}
\AtBeginDocument{
  \clist_put_right:NV \g_file_record_clist \@filelist
  \clist_put_right:NV \g_file_record_full_clist \@filelist
}
%</package>
%    \end{macrocode}
%
% \end{implementation}
% 
% \PrintIndex
