summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3file.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3file.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3file.dtx341
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'. }
{