From 6c6a334f0aa3b95572afe30fa2d17e634c7019ce Mon Sep 17 00:00:00 2001
From: Norbert Preining <norbert@preining.info>
Date: Fri, 1 Jan 2021 03:04:10 +0000
Subject: CTAN sync 202101010304

---
 macros/latex/base/ltfilehook.dtx | 174 +++++++++++++++++++++++++++++++++------
 1 file changed, 147 insertions(+), 27 deletions(-)

(limited to 'macros/latex/base/ltfilehook.dtx')

diff --git a/macros/latex/base/ltfilehook.dtx b/macros/latex/base/ltfilehook.dtx
index ecb499f347..c7ed13f041 100644
--- a/macros/latex/base/ltfilehook.dtx
+++ b/macros/latex/base/ltfilehook.dtx
@@ -31,8 +31,8 @@
 %%% From File: ltfilehook.dtx
 %
 %    \begin{macrocode}
-\providecommand\ltfilehookversion{v1.0c}
-\providecommand\ltfilehookdate{2020/10/18}
+\providecommand\ltfilehookversion{v1.0d}
+\providecommand\ltfilehookdate{2020/11/24}
 %    \end{macrocode}
 %
 %<*driver>
@@ -615,6 +615,62 @@
 %    \begin{macrocode}
 %</2ekernel|latexrelease>
 %<latexrelease>\EndIncludeInRelease
+%    \end{macrocode}
+%
+%    When rolling forward the following expl3 functions may not be defined.
+%    If we roll back the code does nothing.
+% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)}
+%    \begin{macrocode}
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease>                 {\file_parse_full_name_apply:nN}{Roll forward help}%
+%<latexrelease>
+%<latexrelease>\ExplSyntaxOn
+%<latexrelease>\cs_if_exist:NF\file_parse_full_name_apply:nN
+%<latexrelease>{
+%<latexrelease>\cs_new:Npn \file_parse_full_name_apply:nN #1
+%<latexrelease>  {
+%<latexrelease>    \exp_args:Ne \__file_parse_full_name_auxi:nN
+%<latexrelease>      { \__kernel_file_name_sanitize:n {#1} }
+%<latexrelease>  }
+%<latexrelease>\cs_new:Npn \__file_parse_full_name_auxi:nN #1
+%<latexrelease>  {
+%<latexrelease>    \__file_parse_full_name_area:nw { } #1
+%<latexrelease>      / \s__file_stop
+%<latexrelease>  }
+%<latexrelease>\cs_new:Npn \__file_parse_full_name_area:nw #1 #2 / #3 \s__file_stop
+%<latexrelease>  {
+%<latexrelease>    \tl_if_empty:nTF {#3}
+%<latexrelease>      { \__file_parse_full_name_base:nw { } #2 . \s__file_stop {#1} }
+%<latexrelease>      { \__file_parse_full_name_area:nw { #1 / #2 } #3 \s__file_stop }
+%<latexrelease>  }
+%<latexrelease>\cs_new:Npn \__file_parse_full_name_base:nw #1 #2 . #3 \s__file_stop
+%<latexrelease>  {
+%<latexrelease>    \tl_if_empty:nTF {#3}
+%<latexrelease>      {
+%<latexrelease>        \tl_if_empty:nTF {#1}
+%<latexrelease>          {
+%<latexrelease>            \tl_if_empty:nTF {#2}
+%<latexrelease>              { \__file_parse_full_name_tidy:nnnN { } { } }
+%<latexrelease>              { \__file_parse_full_name_tidy:nnnN { .#2 } { } }
+%<latexrelease>          }
+%<latexrelease>          { \__file_parse_full_name_tidy:nnnN {#1} { .#2 } }
+%<latexrelease>      }
+%<latexrelease>      { \__file_parse_full_name_base:nw { #1 . #2 } #3 \s__file_stop }
+%<latexrelease>  }
+%<latexrelease>\cs_new:Npn \__file_parse_full_name_tidy:nnnN #1 #2 #3 #4
+%<latexrelease>  {
+%<latexrelease>    \exp_args:Nee #4
+%<latexrelease>      {
+%<latexrelease>        \str_if_eq:nnF {#3} { / } { \use_none:n }
+%<latexrelease>        #3 \prg_do_nothing:
+%<latexrelease>      }
+%<latexrelease>      { \use_none:n #1 \prg_do_nothing: }
+%<latexrelease>      {#2}
+%<latexrelease>  }
+%<latexrelease>}  
+%<latexrelease>\ExplSyntaxOff
+%<latexrelease>
+%<latexrelease>\EndIncludeInRelease
 %<*2ekernel>
 %    \end{macrocode}
 %
@@ -643,6 +699,8 @@
 %  kernel we  do this only now and not in \texttt{ltfiles}.
 %
 % \begin{macro}{\InputIfFileExists}
+% \begin{macro}{\@input@file@exists@with@hooks}
+% \begin{macro}{\unqu@tefilef@und}
 %    \cs{InputIfFileExists} loads any file if it is available so we
 %    have to add the hooks \texttt{file/before} and
 %    \texttt{file/after} in the right places. If the file doesn't
@@ -665,7 +723,7 @@
 %    If the file exists then \cs{CurrentFile} holds its name. But we
 %    can't rely on that still being true after the file has been
 %    processed. Thus for using the name in the file hooks we need to
-%    preserve the name and then restored it for the
+%    preserve the name and then restore it for the
 %    \texttt{file/after/...} hook.
 %
 %    The hook always refers to the file requested by the user.  The hook
@@ -683,33 +741,68 @@
 %    refer to the file by their name only.  The path to the file is
 %    returned in \cs{CurrentFilePath}.
 %    \begin{macrocode}
-      \edef\reserved@a{\@filef@und
+      \edef\reserved@a{%
         \@expl@@@filehook@file@pop@assign@@nnnn
           {\CurrentFilePathUsed}%
           {\CurrentFileUsed}%
           {\CurrentFilePath}%
-          {\CurrentFile}}%
+          {\CurrentFile}%
+%    \end{macrocode}
+%
+%    We pre-expand \cs{@filef@und} so that in case another file is
+%    loaded in the true branch of \cs{InputIfFileExists}, these don't
+%    change their value meanwhile. This isn't a worry with
+%    \cs[no-index]{CurrentFile...} because they are kept in a stack.
+%
+% \changes{v1.0d}{2020/11/20}
+%   {Move loading to \cs{@input@file@exists@with@hooks} and expand
+%    \cs{@filef@und} to avoid getting the wrong file name in the case of
+%    a substitution.}
+%    \begin{macrocode}
+        \noexpand\@input@file@exists@with@hooks{\@filef@und}}%
       \expandafter\@swaptwoargs\expandafter
         {\reserved@a}%
-        {%
-          #2%
-          \@addtofilelist{#1}%
-          \UseHook{file/before}%
+        {#2}%
+      \@expl@@@filehook@file@pop@@
+    }%
+}
+%    \end{macrocode}
+%
+% Before adding to the file list we need to make all (letter) characters
+% catcode~11, because several packages use constructions like
+% \begin{verbatim}
+% \filename@parse{<filename>}
+% \ifx\filename@ext\@clsextension
+%   ...
+% \fi
+% \end{verbatim}
+% and that doesn't work if \cs{filename@ext} is \cs{detokenize}d.
+% Making \cs{@clsextension} a string doesn't help much because some
+% packages define their own \cs[no-index]{<prefix>@someextension} with
+% normal catcodes.  This is not entirely correct because packages loaded
+% (somehow) with catcode~12 alphabetic tokens (say, as the result of
+% a \cs{string} or \cs{detokenize} command, or from a \TeX{} string like
+% \cs{jobname}) will have these character tokens incorrectly turned into
+% letter tokens.  This however is rare, so we'll go for the all-letters
+% approach (grepping the packages in \TeX{} Live didn't bring up any
+% obvious candidate for breaking with this catcode change).
+%    \begin{macrocode}
+\def\@input@file@exists@with@hooks#1{%
+  \edef\reserved@a{\unqu@tefilef@und#1\@nil}%
+  \@addtofilelist{\string@makeletter\reserved@a}%
+  \UseHook{file/before}%
 %    \end{macrocode}
 %    The current file name is available in \cs{CurrentFile} so we use
 %    that in the specific hook.
 %    \begin{macrocode}
-          \UseHook{file/before/\CurrentFile}%
-          \@@input
-        }%
+  \UseHook{file/before/\CurrentFile}%
+  \@@input #1% <- trailing space comes from \@filef@und
 %    \end{macrocode}
 %    And it is restored here so we can use it once more.
 %    \begin{macrocode}
-      \UseHook{file/after/\CurrentFile}%
-      \UseHook{file/after}%
-      \@expl@@@filehook@file@pop@@
-    }%
-}
+  \UseHook{file/after/\CurrentFile}%
+  \UseHook{file/after}}
+\def\unqu@tefilef@und"#1" \@nil{#1}
 %<latexrelease>\EndIncludeInRelease
 %</2ekernel|latexrelease>
 %    \end{macrocode}
@@ -737,6 +830,8 @@
 %<latexrelease>    {%
 %<latexrelease>  \expandafter\@swaptwoargs\expandafter
 %<latexrelease>      {\@filef@und}{#2\@addtofilelist{#1}\@@input}}}
+%<latexrelease>\let\@input@file@exists@with@hooks\@undefined
+%<latexrelease>\let\unqu@tefilef@und\@undefined
 %<latexrelease>\EndIncludeInRelease
 %    \end{macrocode}
 %
@@ -746,10 +841,14 @@
 %<latexrelease>\long\def \InputIfFileExists#1#2{%
 %<latexrelease>  \IfFileExists{#1}%
 %<latexrelease>    {#2\@addtofilelist{#1}\@@input \@filef@und}}
+%<latexrelease>\let\@input@file@exists@with@hooks\@undefined
+%<latexrelease>\let\unqu@tefilef@und\@undefined
 %<latexrelease>\EndIncludeInRelease
 %<*2ekernel>
 %    \end{macrocode}
 %  \end{macro}
+%  \end{macro}
+%  \end{macro}
 %
 %
 %
@@ -772,8 +871,8 @@
 %
 %
 % \begin{macro}{\@@_subst_add:nn,\@@_subst_remove:n,
-%               \@@_subst_file_normalize:n,\@@_subst_empty_name_chk:NN}
-%   \cs{@@_substitution_lthooadd:nn} declares a file substitution by
+%               \@@_subst_file_normalize:Nn,\@@_subst_empty_name_chk:NN}
+%   \cs{@@_subst_add:nn} declares a file substitution by
 %   doing a (global) definition of the form
 %   |\def|\cs{@file-subst@\meta{file}}|{|\meta{replacement}|}|.
 %   The file names are properly sanitised, and normalized with the same
@@ -787,8 +886,12 @@
     \group_begin:
       \cs_set:cpx { } { \exp_not:o { \cs:w\cs_end: } }
       \int_set:Nn \tex_escapechar:D { -1 }
-      \cs_gset:cpx { @file-subst@ \@@_subst_file_normalize:n {#1} }
-        { \@@_subst_file_normalize:n {#2} }
+      \cs_gset:cpx
+        {
+          @file-subst@
+          \@@_subst_file_normalize:Nn \use_ii_iii:nnn {#1}
+        }
+        { \@@_subst_file_normalize:Nn \@@_file_name_compose:nnn {#2} }
     \group_end:
   }
 \cs_new_protected:Npn \@@_subst_remove:n #1
@@ -796,14 +899,18 @@
     \group_begin:
       \cs_set:cpx { } { \exp_not:o { \cs:w\cs_end: } }
       \int_set:Nn \tex_escapechar:D { -1 }
-      \cs_undefine:c { @file-subst@ \@@_subst_file_normalize:n {#1} }
+      \cs_undefine:c
+        {
+          @file-subst@
+          \@@_subst_file_normalize:Nn \use_ii_iii:nnn {#1}
+        }
     \group_end:
   }
-\cs_new:Npn \@@_subst_file_normalize:n #1
+\cs_new:Npn \@@_subst_file_normalize:Nn #1 #2
   {
     \exp_after:wN \@@_subst_empty_name_chk:NN
       \cs:w \exp_after:wN \cs_end:
-        \cs:w \@@_file_parse_full_name:nN {#1} \use_ii_iii:nnn \cs_end:
+        \cs:w \@@_file_parse_full_name:nN {#2} #1 \cs_end:
   }
 \cs_new:Npn \@@_subst_empty_name_chk:NN #1 #2
   { \if_meaning:w #1 #2 .tex \else: \token_to_str:N #2 \fi: }
@@ -929,6 +1036,7 @@
        \if@tempswa \@expl@@@filehook@drop@extension@@N\@curr@file@reqd \fi}%
       {\if@tempswa \@expl@@@filehook@drop@extension@@N\@curr@file \fi
        \global\let\@curr@file@reqd\@curr@file}%
+    \@expl@@@filehook@clear@replacement@flag@@
   \endgroup}
 %</2ekernel|latexrelease>
 %<latexrelease>\EndIncludeInRelease
@@ -1079,18 +1187,25 @@
 %
 % \begin{macro}{flag @@_file_replaced}
 % \begin{macro}{\@@_if_file_replaced:TF}
+% \begin{macro}{\@@_clear_replacement_flag:}
 %   Since the file replacement is done expandably in a \cs{csname}, use
 %   a flag to remember if a substitution happened.  We use this in
 %   \cs{set@curr@file} to short-circuit some of it in case no
 %   substitution happened (by far the most common case, so it's worth
-%   optimising).
+%   optimising).  The flag raised during the file substitution algorithm
+%   must be explicitly cleared after the \cs{@@_if_file_replaced:TF}
+%   conditional is no longer needed, otherwise further uses of
+%   \cs{@@_if_file_replaced:TF} will wrongly return true.
 %    \begin{macrocode}
 \flag_new:n { @@_file_replaced }
 \cs_new:Npn \@@_if_file_replaced:TF #1 #2
-   { \flag_if_raised:nTF { @@_file_replaced } {#1} {#2} }
+  { \flag_if_raised:nTF { @@_file_replaced } {#1} {#2} }
+\cs_new_protected:Npn \@@_clear_replacement_flag:
+  { \flag_clear:n { @@_file_replaced } }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
+% \end{macro}
 %
 % \begin{macro}{\@@_file_subst_begin:nnn}
 %   First off, start by checking if the current file ($\meta{name} +
@@ -1343,7 +1458,12 @@
 \cs_new_eq:NN \@expl@@@filehook@if@file@replaced@@TF
               \__filehook_if_file_replaced:TF
 %    \end{macrocode}
-%    
+%
+%    \begin{macrocode}
+\cs_new_eq:NN \@expl@@@filehook@clear@replacement@flag@@
+              \__filehook_clear_replacement_flag:
+%    \end{macrocode}
+%
 %    \begin{macrocode}
 \cs_new_eq:NN \@expl@@@filehook@drop@extension@@N
               \__filehook_drop_extension:N
-- 
cgit v1.2.3

