diff options
author | Karl Berry <karl@freefriends.org> | 2021-05-07 20:16:16 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-05-07 20:16:16 +0000 |
commit | b95d7e12e4b85cb577f3efc950cf50413dfea72b (patch) | |
tree | 8f662c3a06c148b16917d9fe40bad41f7321dcfc /Master/texmf-dist/source/latex/l3kernel/l3file.dtx | |
parent | 3f20818aebef6486b55ca328825b002d7f87e396 (diff) |
l3 (7may21)
git-svn-id: svn://tug.org/texlive/trunk@59118 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3file.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3file.dtx | 341 |
1 files changed, 192 insertions, 149 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx index 76c21c537e7..eb025e0b16c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3file.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3file.dtx @@ -44,7 +44,7 @@ % }^^A % } % -% \date{Released 2021-02-18} +% \date{Released 2021-05-07} % % \maketitle % @@ -1128,11 +1128,11 @@ % \texttt{show-streams} takes care of translating |ior|/|iow| to % English. % \begin{macrocode} -\cs_new_protected:Npn \ior_show_list: { \@@_list:N \msg_show:nnxxxx } -\cs_new_protected:Npn \ior_log_list: { \@@_list:N \msg_log:nnxxxx } +\cs_new_protected:Npn \ior_show_list: { \@@_list:N \__kernel_msg_show:nnxxxx } +\cs_new_protected:Npn \ior_log_list: { \@@_list:N \__kernel_msg_log:nnxxxx } \cs_new_protected:Npn \@@_list:N #1 { - #1 { LaTeX / kernel } { show-streams } + #1 { kernel } { show-streams } { ior } { \prop_map_function:NN \g_@@_streams_prop @@ -1161,19 +1161,19 @@ % \begin{macrocode} \prg_new_conditional:Npnn \ior_if_eof:N #1 { p , T , F , TF } { - \cs_if_exist:NTF #1 - { - \int_compare:nTF { -1 < #1 < \c_@@_term_ior } - { - \if_eof:w #1 - \prg_return_true: - \else: - \prg_return_false: - \fi: - } - { \prg_return_true: } - } - { \prg_return_true: } + \if_int_compare:w -1 < #1 + \if_int_compare:w #1 < \c_@@_term_ior + \if_eof:w #1 + \prg_return_true: + \else: + \prg_return_false: + \fi: + \else: + \prg_return_true: + \fi: + \else: + \prg_return_true: + \fi: } % \end{macrocode} % \end{macro} @@ -1272,7 +1272,7 @@ % \begin{macro}{\@@_map_inline:NNn} % \begin{macro}{\@@_map_inline:NNNn} % \begin{macro}{\@@_map_inline_loop:NNN} -% Mapping to an input stream can be done on either a token or a string +% Mapping over an input stream can be done on either a token or a string % basis, hence the set up. Within that, there is a check to avoid reading % past the end of a file, hence the two applications of \cs{ior_if_eof:N} % and its lower-level analogue \cs{if_eof:w}. @@ -1524,11 +1524,11 @@ % \begin{macro}{\@@_list:N} % Done as for input, but with a copy of the auxiliary so the name is correct. % \begin{macrocode} -\cs_new_protected:Npn \iow_show_list: { \@@_list:N \msg_show:nnxxxx } -\cs_new_protected:Npn \iow_log_list: { \@@_list:N \msg_log:nnxxxx } +\cs_new_protected:Npn \iow_show_list: { \@@_list:N \__kernel_msg_show:nnxxxx } +\cs_new_protected:Npn \iow_log_list: { \@@_list:N \__kernel_msg_log:nnxxxx } \cs_new_protected:Npn \@@_list:N #1 { - #1 { LaTeX / kernel } { show-streams } + #1 { kernel } { show-streams } { iow } { \prop_map_function:NN \g_@@_streams_prop @@ -2426,102 +2426,126 @@ % \end{macro} % % \begin{macro}[EXP]{\__kernel_file_name_sanitize:n} -% \begin{macro}[EXP]{\__kernel_file_name_expand_loop:w} -% \begin{macro}[EXP]{\__kernel_file_name_expand_N_type:Nw} -% \begin{macro}[EXP]{\__kernel_file_name_expand_group:nw} -% \begin{macro}[EXP]{\__kernel_file_name_expand_space:w} -% \begin{macro}[EXP]{\__kernel_file_name_strip_quotes:n} -% \begin{macro}[EXP]{\__kernel_file_name_strip_quotes:nnnw} -% \begin{macro}[EXP]{\__kernel_file_name_strip_quotes:nnn} -% \begin{macro}[EXP]{\__kernel_file_name_trim_spaces:n} -% \begin{macro}[EXP]{\__kernel_file_name_trim_spaces:nw} -% \begin{macro}[EXP]{\__kernel_file_name_trim_spaces_aux:n} -% \begin{macro}[EXP]{\__kernel_file_name_trim_spaces_aux:w} -% Expanding the file name without expanding active characters is done -% using the same token-by-token approach as for example case changing. -% The finale outcome only need be \texttt{e}-type expandable, so there -% is no need for the shuffling that is seen in other locations. +% \begin{macro}[EXP]{ +% \@@_name_expand:n, +% \@@_name_expand_cleanup:Nw, +% \@@_name_expand_cleanup:w, +% \@@_name_expand_end:, +% \@@_name_expand_error:Nw, +% \@@_name_expand_error_aux:Nw, +% } +% \begin{macro}[EXP]{ +% \@@_name_strip_quotes:n, +% \@@_name_strip_quotes:nnnw, +% \@@_name_strip_quotes:nnn, +% } +% \begin{macro}[EXP]{ +% \@@_name_trim_spaces:n, +% \@@_name_trim_spaces:nw, +% \@@_name_trim_spaces_aux:n, +% \@@_name_trim_spaces_aux:w, +% } +% Expanding the file name uses a \tn{csname}-based approach, and +% relies on active characters (for example from UTF-8 characters) +% being properly set up to expand to a expansion-safe version using +% \cs{ifcsname}. This is less conservative than the token-by-token +% approach used before, but it is much faster. % \begin{macrocode} \cs_new:Npn \__kernel_file_name_sanitize:n #1 { - \exp_args:Ne \__kernel_file_name_trim_spaces:n + \exp_args:Ne \@@_name_trim_spaces:n { - \exp_args:Ne \__kernel_file_name_strip_quotes:n - { - \__kernel_file_name_expand_loop:w #1 - \q_@@_recursion_tail \q_@@_recursion_stop - } + \exp_args:Ne \@@_name_strip_quotes:n + { \@@_name_expand:n {#1} } } } -\cs_new:Npn \__kernel_file_name_expand_loop:w #1 \q_@@_recursion_stop +% \end{macrocode} +% +% We'll use \cs{cs:w} to start expanding the file name, and to avoid +% creating csnames equal to \tn{relax} with \enquote{common} names, +% there's a prefix |__file_name=| to the csname. There's also a guard +% token at the end so we can check if there was an error during the +% process and (try to) clean up gracefully. +% \begin{macrocode} +\cs_new:Npn \@@_name_expand:n #1 { - \tl_if_head_is_N_type:nTF {#1} - { \__kernel_file_name_expand_N_type:Nw } - { - \tl_if_head_is_group:nTF {#1} - { \__kernel_file_name_expand_group:nw } - { \__kernel_file_name_expand_space:w } - } - #1 \q_@@_recursion_stop + \exp_after:wN \@@_name_expand_cleanup:Nw + \cs:w @@_name = #1 \cs_end: + \@@_name_expand_end: } -\cs_new:Npn \__kernel_file_name_expand_N_type:Nw #1 +% \end{macrocode} +% With the csname built, we grab it, and grab the remaining tokens +% delimited by \cs{@@_name_expand_end:}. If there are any remaining +% tokens, something bad happened, so we'll call the error procedure +% \cs{@@_name_expand_error:Nw}. +% If everything went according to plan, then use \cs{token_to_str:N} +% on the csname built, and call \cs{@@_name_expand_cleanup:w} to +% remove the prefix we added a while back. +% \cs{@@_name_expand_cleanup:w} takes a leading argument so we don't +% have to bother about the value of \cs{tex_escapechar:D}. +% \begin{macrocode} +\cs_new:Npn \@@_name_expand_cleanup:Nw #1 #2 \@@_name_expand_end: { - \@@_if_recursion_tail_stop:N #1 - \bool_lazy_and:nnTF - { \token_if_expandable_p:N #1 } - { - \bool_not_p:n - { - \bool_lazy_any_p:n - { - { \token_if_protected_macro_p:N #1 } - { \token_if_protected_long_macro_p:N #1 } - { \token_if_active_p:N #1 } - } - } - } - { \exp_after:wN \__kernel_file_name_expand_loop:w #1 } - { - \token_to_str:N #1 - \__kernel_file_name_expand_loop:w - } + \tl_if_empty:nF {#2} + { \@@_name_expand_error:Nw #2 \@@_name_expand_end: } + \exp_after:wN \@@_name_expand_cleanup:w \token_to_str:N #1 } -\cs_new:Npx \__kernel_file_name_expand_group:nw #1 +\exp_last_unbraced:NNNNo +\cs_new:Npn \@@_name_expand_cleanup:w #1 \tl_to_str:n { @@_name = } { } +% \end{macrocode} +% In non-error cases \cs{@@_name_expand_end:} should not expand. It +% will only do so in case there is a \cs{csname} too much in the file +% name, so it will throw an error (while expanding), then insert the +% missing \cs{cs_end:} and yet another \cs{@@_name_expand_end:} that +% will be used as a delimiter by \cs{@@_name_expand_cleanup:Nw} (or +% that will expand again if yet another \cs{endcsname} is missing). +% \begin{macrocode} +\cs_new:Npn \@@_name_expand_end: { - \c_left_brace_str - \exp_not:N \__kernel_file_name_expand_loop:w - #1 - \c_right_brace_str + \__kernel_msg_expandable_error:nn + { kernel } { filename-missing-endcsname } + \cs_end: \@@_name_expand_end: + } +% \end{macrocode} +% Now to the error case. \cs{@@_name_expand_error:Nw} adds an extra +% \cs{cs_end:} so that in case there was an extra \tn{csname} in the +% file name, then \cs{@@_name_expand_error_aux:Nw} throws the error. +% \begin{macrocode} +\cs_new:Npn \@@_name_expand_error:Nw #1 #2 \@@_name_expand_end: + { \@@_name_expand_error_aux:Nw #1 #2 \cs_end: \@@_name_expand_end: } +\cs_new:Npn \@@_name_expand_error_aux:Nw #1 #2 \cs_end: #3 + \@@_name_expand_end: + { + \__kernel_msg_expandable_error:nnff + { kernel } { filename-chars-lost } + { \token_to_str:N #1 } { \exp_stop_f: #2 } } -\exp_last_unbraced:NNo - \cs_new:Npx \__kernel_file_name_expand_space:w \c_space_tl - { - \c_space_tl - \exp_not:N \__kernel_file_name_expand_loop:w - } % \end{macrocode} % Quoting file name uses basically the same approach as for % \texttt{luaquotejobname}: count the |"| tokens and remove them. % \begin{macrocode} -\cs_new:Npn \__kernel_file_name_strip_quotes:n #1 +\cs_new:Npn \@@_name_strip_quotes:n #1 { - \__kernel_file_name_strip_quotes:nnnw {#1} { 0 } { } - #1 " \q_@@_recursion_tail " \q_@@_recursion_stop + \@@_name_strip_quotes:nw { 0 } + #1 " \q_@@_recursion_tail " \q_@@_recursion_stop {#1} } -\cs_new:Npn \__kernel_file_name_strip_quotes:nnnw #1#2#3#4 " +\cs_new:Npn \@@_name_strip_quotes:nw #1#2 " { - \@@_if_recursion_tail_stop_do:nn {#4} - { \__kernel_file_name_strip_quotes:nnn {#1} {#2} {#3} } - \__kernel_file_name_strip_quotes:nnnw {#1} { #2 + 1 } { #3#4 } + \if_meaning:w \q_@@_recursion_tail #2 + \@@_name_strip_quotes_end:wnwn + \fi: + #2 + \@@_name_strip_quotes:nw { #1 + 1 } } -\cs_new:Npn \__kernel_file_name_strip_quotes:nnn #1#2#3 +\cs_new:Npn \@@_name_strip_quotes_end:wnwn \fi: #1 + \@@_name_strip_quotes:nw #2 \q_@@_recursion_stop #3 { - \int_if_even:nT {#2} + \fi: + \int_if_odd:nT {#2} { \__kernel_msg_expandable_error:nnn - { kernel } { unbalanced-quote-in-filename } {#1} + { kernel } { unbalanced-quote-in-filename } {#3} } - #3 } % \end{macrocode} % Spaces need to be trimmed from the start of the name and from the end of @@ -2530,40 +2554,32 @@ % the standard trimming function but deliberately prevent any spaces being % removed at the end. % \begin{macrocode} -\cs_new:Npn \__kernel_file_name_trim_spaces:n #1 - { \__kernel_file_name_trim_spaces:nw {#1} #1 . \q_@@_nil . \s_@@_stop } -\cs_new:Npn \__kernel_file_name_trim_spaces:nw #1#2 . #3 . #4 \s_@@_stop +\cs_new:Npn \@@_name_trim_spaces:n #1 + { \@@_name_trim_spaces:nw {#1} #1 . \q_@@_nil . \s_@@_stop } +\cs_new:Npn \@@_name_trim_spaces:nw #1#2 . #3 . #4 \s_@@_stop { \@@_quark_if_nil:nTF {#3} { - \exp_args:Ne \__kernel_file_name_trim_spaces_aux:n - { \tl_trim_spaces:n { #1 \s_@@_stop } } + \tl_trim_spaces_apply:nN { #1 \s_@@_stop } + \@@_name_trim_spaces_aux:n } { \tl_trim_spaces:n {#1} } } -\cs_new:Npn \__kernel_file_name_trim_spaces_aux:n #1 - { \__kernel_file_name_trim_spaces_aux:w #1 } -\cs_new:Npn \__kernel_file_name_trim_spaces_aux:w #1 \s_@@_stop {#1} +\cs_new:Npn \@@_name_trim_spaces_aux:n #1 + { \@@_name_trim_spaces_aux:w #1 } +\cs_new:Npn \@@_name_trim_spaces_aux:w #1 \s_@@_stop {#1} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % % \begin{macro}[EXP]{\__kernel_file_name_quote:n} -% \begin{macro}[EXP]{\__kernel_file_name_quote:nw} +% \begin{macro}[EXP]{\@@_name_quote:nw} % \begin{macrocode} \cs_new:Npn \__kernel_file_name_quote:n #1 - { \__kernel_file_name_quote:nw {#1} #1 ~ \q_@@_nil \s_@@_stop } -\cs_new:Npn \__kernel_file_name_quote:nw #1 #2 ~ #3 \s_@@_stop + { \@@_name_quote:nw {#1} #1 ~ \q_@@_nil \s_@@_stop } +\cs_new:Npn \@@_name_quote:nw #1 #2 ~ #3 \s_@@_stop { \@@_quark_if_nil:nTF {#3} { #1 } @@ -2643,14 +2659,17 @@ % \end{macro} % % \begin{macro}[EXP]{\file_full_name:n, \@@_full_name:n} +% \begin{macro}[EXP]{\@@_full_name_aux:nn} % \begin{macro}[EXP]{\@@_full_name_aux:Nnn} % \begin{macro}[EXP]{\@@_full_name_aux:nN} +% \begin{macro}[EXP]{\@@_full_name_aux:nnN} % \begin{macro}[EXP]{\@@_name_cleanup:w} % \begin{macro}[EXP]{\@@_name_end:} -% \begin{macro}[EXP]{\@@_name_ext_check:n} -% \begin{macro}[EXP]{\@@_name_ext_check:nw} -% \begin{macro}[EXP]{\@@_name_ext_check:nnw} % \begin{macro}[EXP]{\@@_name_ext_check:nn} +% \begin{macro}[EXP]{\@@_name_ext_check:nnw} +% \begin{macro}[EXP]{\@@_name_ext_check:nnnw} +% \begin{macro}[EXP]{\@@_name_ext_check:nnn} +% \begin{macro}[EXP]{\@@_name_ext_check:nnnn} % File searching can be carried out if the \tn{pdffilesize} primitive % or an equivalent is available. That of course means we need to % arrange for everything else to here to be done by expansion too. @@ -2666,25 +2685,29 @@ % First, we check of the file is just here: no mapping so we do not % need the break part of the broader auxiliary. We are using the fact % that the primitive here returns nothing if the file is entirely absent. +% To avoid unnecessary filesystem lookups, the result of \tn{pdffilesize} +% is kept available as an argument. % For package mode, \tn{input@path} is a token list not a sequence. % \begin{macrocode} \cs_new:Npn \@@_full_name:n #1 { \tl_if_blank:nF {#1} + { \exp_args:Nne \@@_full_name_aux:nn {#1} { \@@_size:n {#1} } } + } +\cs_new:Npn \@@_full_name_aux:nn #1 #2 + { + \tl_if_blank:nTF {#2} { - \tl_if_blank:eTF { \@@_size:n {#1} } + \seq_map_tokens:Nn \l_file_search_path_seq + { \@@_full_name_aux:Nnn \seq_map_break:n {#1} } + \cs_if_exist:NT \input@path { - \seq_map_tokens:Nn \l_file_search_path_seq - { \@@_full_name_aux:Nnn \seq_map_break:n {#1} } - \cs_if_exist:NT \input@path - { - \tl_map_tokens:Nn \input@path - { \@@_full_name_aux:Nnn \tl_map_break:n {#1} } - } - \@@_name_end: + \tl_map_tokens:Nn \input@path + { \@@_full_name_aux:Nnn \tl_map_break:n {#1} } } - { \@@_ext_check:n {#1} } + \@@_name_end: } + { \@@_ext_check:nn {#1} {#2} } } % \end{macrocode} % Two pars to the auxiliary here so we can avoid doing quoting @@ -2692,13 +2715,15 @@ % \begin{macrocode} \cs_new:Npn \@@_full_name_aux:Nnn #1#2#3 { \exp_args:Ne \@@_full_name_aux:nN { \tl_to_str:n {#3} / #2 } #1 } -\cs_new:Npn \@@_full_name_aux:nN #1 #2 +\cs_new:Npn \@@_full_name_aux:nN #1 + { \exp_args:Nne \@@_full_name_aux:nnN {#1} { \@@_size:n {#1} } } +\cs_new:Npn \@@_full_name_aux:nnN #1 #2 #3 { - \tl_if_blank:eF { \@@_size:n {#1} } + \tl_if_blank:nF {#2} { - #2 + #3 { - \@@_ext_check:n {#1} + \@@_ext_check:nn {#1} {#2} \@@_name_cleanup:w } } @@ -2710,35 +2735,37 @@ % there is a little clean up to do here. First, make sure we are not in the % directory part, saving that. Then check for an extension. % \begin{macrocode} -\cs_new:Npn \@@_ext_check:n #1 - { \@@_ext_check:nw { / } #1 / \q_@@_nil / \s_@@_stop } -\cs_new:Npn \@@_ext_check:nw #1 #2 / #3 / #4 \s_@@_stop +\cs_new:Npn \@@_ext_check:nn #1 #2 +{ \@@_ext_check:nnw {#2} { / } #1 / \q_@@_nil / \s_@@_stop } +\cs_new:Npn \@@_ext_check:nnw #1 #2 #3 / #4 / #5 \s_@@_stop { - \@@_quark_if_nil:nTF {#3} + \@@_quark_if_nil:nTF {#4} { - \exp_args:No \@@_ext_check:nnw - { \use_none:n #1 } {#2} #2 . \q_@@_nil . \s_@@_stop + \exp_args:No \@@_ext_check:nnnw + { \use_none:n #2 } {#1} {#3} #3 . \q_@@_nil . \s_@@_stop } - { \@@_ext_check:nw { #1 #2 / } #3 / #4 \s_@@_stop } + { \@@_ext_check:nnw {#1} { #2 #3 / } #4 / #5 \s_@@_stop } } -\cs_new:Npx \@@_ext_check:nnw #1#2#3 . #4 . #5 \s_@@_stop +\cs_new:Npx \@@_ext_check:nnnw #1#2#3#4 . #5 . #6 \s_@@_stop { - \exp_not:N \@@_quark_if_nil:nTF {#4} + \exp_not:N \@@_quark_if_nil:nTF {#5} { - \exp_not:N \@@_ext_check:nn - { #1 #2 } { #1 #2 \tl_to_str:n { .tex } } + \exp_not:N \@@_ext_check:nnn + { #1 #3 \tl_to_str:n { .tex } } { #1 #3 } {#2} } - { #1 #2 } + { #1 #3 } } -\cs_new:Npn \@@_ext_check:nn #1#2 +\cs_new:Npn \@@_ext_check:nnn #1 + { \exp_args:Nne \@@_ext_check:nnnn {#1} { \@@_size:n {#1} } } +\cs_new:Npn \@@_ext_check:nnnn #1#2#3#4 { - \tl_if_blank:eTF { \@@_size:n {#2} } - {#1} + \tl_if_blank:nTF {#2} + {#3} { \int_compare:nNnTF - { \@@_size:n {#1} } = { \@@_size:n {#2} } - {#2} + {#4} = {#2} {#1} + {#3} } } % \end{macrocode} @@ -2769,6 +2796,9 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}{\file_get_full_name:nN, \file_get_full_name:VN} % \begin{macro}[TF]{\file_get_full_name:nN, \file_get_full_name:VN} @@ -3360,8 +3390,8 @@ % \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 \file_show_list: { \@@_list:N \__kernel_msg_show:nnxxxx } +\cs_new_protected:Npn \file_log_list: { \@@_list:N \__kernel_msg_log:nnxxxx } \cs_new_protected:Npn \@@_list:N #1 { \seq_clear:N \l_@@_tmp_seq @@ -3372,7 +3402,7 @@ } \seq_concat:NNN \l_@@_tmp_seq \l_@@_tmp_seq \g_@@_record_seq \seq_remove_duplicates:N \l_@@_tmp_seq - #1 { LaTeX/kernel } { file-list } + #1 { kernel } { file-list } { \seq_map_function:NN \l_@@_tmp_seq \@@_list_aux:n } { } { } { } } @@ -3614,6 +3644,19 @@ #1 \\ ............. } +\__kernel_msg_new:nnnn { kernel } { filename-chars-lost } + { #1~invalid~in~file~name.~Lost:~#2. } + { + There~was~an~invalid~token~in~the~file~name~that~caused~ + the~characters~following~it~to~be~lost. + } +\__kernel_msg_new:nnnn { kernel } { filename-missing-endcsname } + { Missing~\iow_char:N\\endcsname~inserted~in~filename. } + { + The~file~name~had~more~\iow_char:N\\csname~commands~than~ + \iow_char:N\\endcsname~ones.~LaTeX~will~add~the~missing~ + \iow_char:N\\endcsname~and~try~to~continue~as~best~as~it~can. + } \__kernel_msg_new:nnnn { kernel } { unbalanced-quote-in-filename } { Unbalanced~quotes~in~file~name~'#1'. } { |