% \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|package>
%<*driver>
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \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:
%</package>
%    \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 }
  }
%</initex>
%<*package>
\tl_gset_eq:NN \g_file_current_name_tl \@currname
%</package>
%    \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
  }
%</initex>
%    \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
%</package>
%    \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} }
      }
%</package>
    \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 }
%</package>
    \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}
%</initex>
%<*package>
        \@addtofilelist {#1}
%</package>
        \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} }
  }
%</package>
%    \end{macrocode}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex