summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3msg.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3msg.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3msg.dtx2097
1 files changed, 2097 insertions, 0 deletions
diff --git a/macros/latex/contrib/l3kernel/l3msg.dtx b/macros/latex/contrib/l3kernel/l3msg.dtx
new file mode 100644
index 0000000000..d005a8131f
--- /dev/null
+++ b/macros/latex/contrib/l3kernel/l3msg.dtx
@@ -0,0 +1,2097 @@
+% \iffalse meta-comment
+%
+%% File: l3msg.dtx
+%
+% Copyright (C) 2009-2019 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
+%
+% https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3kernel bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3msg} package\\ Messages^^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 2019-08-25}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% Messages need to be passed to the user by modules, either when errors
+% occur or to indicate how the code is proceeding. The \pkg{l3msg}
+% module provides a consistent method for doing this (as opposed to
+% writing directly to the terminal or log).
+%
+% The system used by \pkg{l3msg} to create messages divides the process
+% into two distinct parts. Named messages are created in the first part
+% of the process; at this stage, no decision is made about the type of
+% output that the message will produce. The second part of the process
+% is actually producing a message. At this stage a choice of message
+% \emph{class} has to be made, for example \texttt{error},
+% \texttt{warning} or \texttt{info}.
+%
+% By separating out the creation and use of messages, several benefits
+% are available. First, the messages can be altered later without
+% needing details of where they are used in the code. This makes it
+% possible to alter the language used, the detail level and so on.
+% Secondly, the output which results from a given message can be
+% altered. This can be done on a message class, module or message name
+% basis. In this way, message behaviour can be altered and messages can
+% be entirely suppressed.
+%
+% \section{Creating new messages}
+%
+% All messages have to be created before they can be used.
+% The text of messages is automatically wrapped to the length
+% available in the console. As a result, formatting is only needed
+% where it helps to show meaning. In particular, |\\| may be
+% used to force a new line and \verb*|\ | forces an explicit space.
+% Additionally, |\{|, |\#|, |\}|, |\%| and |\~| can be used to produce
+% the corresponding character.
+%
+% Messages may be subdivided \emph{by one level} using the~|/|
+% character. This is used within the message filtering system to allow
+% for example the \LaTeX{} kernel messages to belong to the module
+% \texttt{LaTeX} while still being filterable at a more granular level.
+% Thus for example
+% \begin{verbatim}
+% \msg_new:nnnn { mymodule } { submodule / message } ...
+% \end{verbatim}
+% will allow to filter out specifically messages from the \texttt{submodule}.
+%
+% \begin{function}[updated = 2011-08-16]{\msg_new:nnnn, \msg_new:nnn}
+% \begin{syntax}
+% \cs{msg_new:nnnn} \Arg{module} \Arg{message} \Arg{text} \Arg{more text}
+% \end{syntax}
+% Creates a \meta{message} for a given \meta{module}.
+% The message is defined to first give \meta{text} and then
+% \meta{more text} if the user requests it. If no \meta{more text} is
+% available then a standard text is given instead. Within \meta{text}
+% and \meta{more text} four parameters (|#1| to |#4|) can be used:
+% these will be supplied at the time the message is
+% used. An error is raised if the \meta{message} already exists.
+% \end{function}
+%
+% \begin{function}{\msg_set:nnnn, \msg_set:nnn, \msg_gset:nnnn, \msg_gset:nnn}
+% \begin{syntax}
+% \cs{msg_set:nnnn} \Arg{module} \Arg{message} \Arg{text} \Arg{more text}
+% \end{syntax}
+% Sets up the text for a \meta{message} for a given \meta{module}.
+% The message is defined to first give \meta{text} and then
+% \meta{more text} if the user requests it. If no \meta{more text} is
+% available then a standard text is given instead. Within \meta{text}
+% and \meta{more text} four parameters (|#1| to |#4|) can be used:
+% these will be supplied at the time the message is used.
+% \end{function}
+%
+% \begin{function}[EXP, pTF, added = 2012-03-03]{\msg_if_exist:nn}
+% \begin{syntax}
+% \cs{msg_if_exist_p:nn} \Arg{module} \Arg{message}
+% \cs{msg_if_exist:nnTF} \Arg{module} \Arg{message} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests whether the \meta{message} for the \meta{module} is currently
+% defined.
+% \end{function}
+%
+% \section{Contextual information for messages}
+%
+% \begin{function}[rEXP]{\msg_line_context:}
+% \begin{syntax}
+% \cs{msg_line_context:}
+% \end{syntax}
+% Prints the current line number when a message is given, and
+% thus suitable for giving context to messages. The number itself
+% is proceeded by the text |on line|.
+% \end{function}
+%
+% \begin{function}[EXP]{\msg_line_number:}
+% \begin{syntax}
+% \cs{msg_line_number:}
+% \end{syntax}
+% Prints the current line number when a message is given.
+% \end{function}
+%
+% \begin{function}[EXP]{\msg_fatal_text:n}
+% \begin{syntax}
+% \cs{msg_fatal_text:n} \Arg{module}
+% \end{syntax}
+% Produces the standard text
+% \begin{quote}
+% \ttfamily
+% Fatal Package \meta{module} Error
+% \end{quote}
+% This function can be redefined to alter the language in which the
+% message is given, using |#1| as the name of the \meta{module} to
+% be included.
+% \end{function}
+%
+% \begin{function}[EXP]{\msg_critical_text:n}
+% \begin{syntax}
+% \cs{msg_critical_text:n} \Arg{module}
+% \end{syntax}
+% Produces the standard text
+% \begin{quote}
+% \ttfamily
+% Critical Package \meta{module} Error
+% \end{quote}
+% This function can be redefined to alter the language in which the
+% message is given, using |#1| as the name of the \meta{module} to
+% be included.
+% \end{function}
+%
+% \begin{function}[EXP]{\msg_error_text:n}
+% \begin{syntax}
+% \cs{msg_error_text:n} \Arg{module}
+% \end{syntax}
+% Produces the standard text
+% \begin{quote}
+% \ttfamily
+% Package \meta{module} Error
+% \end{quote}
+% This function can be redefined to alter the language in which the
+% message is given, using |#1| as the name of the \meta{module} to
+% be included.
+% \end{function}
+%
+% \begin{function}[EXP]{\msg_warning_text:n}
+% \begin{syntax}
+% \cs{msg_warning_text:n} \Arg{module}
+% \end{syntax}
+% Produces the standard text
+% \begin{quote}
+% \ttfamily
+% Package \meta{module} Warning
+% \end{quote}
+% This function can be redefined to alter the language in which the
+% message is given, using |#1| as the name of the \meta{module} to
+% be included. The \meta{type} of \meta{module} may be adjusted:
+% |Package| is the standard outcome: see \cs{msg_module_type:n}.
+% \end{function}
+%
+% \begin{function}[EXP]{\msg_info_text:n}
+% \begin{syntax}
+% \cs{msg_info_text:n} \Arg{module}
+% \end{syntax}
+% Produces the standard text:
+% \begin{quote}
+% \ttfamily
+% Package \meta{module} Info
+% \end{quote}
+% This function can be redefined to alter the language in which the
+% message is given, using |#1| as the name of the \meta{module} to
+% be included. The \meta{type} of \meta{module} may be adjusted:
+% |Package| is the standard outcome: see \cs{msg_module_type:n}.
+% \end{function}
+%
+% \begin{function}[EXP, added = 2018-10-10]{\msg_module_name:n}
+% \begin{syntax}
+% \cs{msg_module_name:n} \Arg{module}
+% \end{syntax}
+% Expands to the public name of the \meta{module} as defined by
+% \cs{g_msg_module_name_prop} (or otherwise leaves the \meta{module}
+% unchanged).
+% \end{function}
+%
+% \begin{function}[EXP, added = 2018-10-10]{\msg_module_type:n}
+% \begin{syntax}
+% \cs{msg_module_type:n} \Arg{module}
+% \end{syntax}
+% Expands to the description which applies to the \meta{module},
+% for example a |Package| or |Class|. The information here is defined
+% in \cs{g_msg_module_type_prop}, and will default to |Package| if an
+% entry is not present.
+% \end{function}
+%
+% \begin{function}[EXP,updated = 2018-09-30]{\msg_see_documentation_text:n}
+% \begin{syntax}
+% \cs{msg_see_documentation_text:n} \Arg{module}
+% \end{syntax}
+% Produces the standard text
+% \begin{quote}
+% \ttfamily
+%
+% See the \meta{module} documentation for further information.
+% \end{quote}
+% This function can be redefined to alter the language in which the
+% message is given, using |#1| as the name of the \meta{module} to
+% be included. The name of the \meta{module} may be altered by use of
+% \cs{g_msg_module_documentation_prop}
+% \end{function}
+%
+% \begin{variable}[added = 2018-10-10]{\g_msg_module_name_prop}
+% Provides a mapping between the module name used for messages, and that
+% for documentation. For example, \LaTeX{}3 core messages are stored in
+% the reserved |LaTeX| tree, but are printed as |LaTeX3|.
+% \end{variable}
+%
+% \begin{variable}[added = 2018-10-10]{\g_msg_module_type_prop}
+% Provides a mapping between the module name used for messages, and that
+% type of module. For example, for \LaTeX{}3 core messages, an empty entry
+% is set here meaning that they are not described using the standard
+% |Package| text.
+% \end{variable}
+%
+% \section{Issuing messages}
+%
+% Messages behave differently depending on the message class. In all cases,
+% the message may be issued supplying~$0$ to~$4$ arguments. If the number of
+% arguments supplied here does not match the number in the definition of the
+% message, extra arguments are ignored, or empty arguments added (of
+% course the sense of the message may be impaired). The four arguments are
+% converted to strings before being added to the message text: the
+% \texttt{x}-type variants should be used to expand material.
+%
+% \begin{function}[updated = 2012-08-11]
+% {
+% \msg_fatal:nnnnnn ,
+% \msg_fatal:nnnnn ,
+% \msg_fatal:nnnn ,
+% \msg_fatal:nnn ,
+% \msg_fatal:nn ,
+% \msg_fatal:nnxxxx ,
+% \msg_fatal:nnxxx ,
+% \msg_fatal:nnxx ,
+% \msg_fatal:nnx
+% }
+% \begin{syntax}
+% \cs{msg_fatal:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
+% \end{syntax}
+% Issues \meta{module} error \meta{message}, passing \meta{arg one} to
+% \meta{arg four} to the text-creating functions. After issuing a
+% fatal error the \TeX{} run halts. No PDF file will be produced in
+% this case (DVI mode runs may produce a truncated DVI file).
+% \end{function}
+%
+% \begin{function}[updated = 2012-08-11]
+% {
+% \msg_critical:nnnnnn ,
+% \msg_critical:nnnnn ,
+% \msg_critical:nnnn ,
+% \msg_critical:nnn ,
+% \msg_critical:nn ,
+% \msg_critical:nnxxxx ,
+% \msg_critical:nnxxx ,
+% \msg_critical:nnxx ,
+% \msg_critical:nnx
+% }
+% \begin{syntax}
+% \cs{msg_critical:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
+% \end{syntax}
+% Issues \meta{module} error \meta{message}, passing \meta{arg one} to
+% \meta{arg four} to the text-creating functions. After issuing a
+% critical error, \TeX{} stops reading the current input file.
+% This may halt the \TeX{} run (if the current file is the main file)
+% or may abort reading a sub-file.
+% \begin{texnote}
+% The \TeX{} \tn{endinput} primitive is used to exit the file. In
+% particular, the rest of the current line remains in the input
+% stream.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}[updated = 2012-08-11]
+% {
+% \msg_error:nnnnnn ,
+% \msg_error:nnnnn ,
+% \msg_error:nnnn ,
+% \msg_error:nnn ,
+% \msg_error:nn ,
+% \msg_error:nnxxxx ,
+% \msg_error:nnxxx ,
+% \msg_error:nnxx ,
+% \msg_error:nnx
+% }
+% \begin{syntax}
+% \cs{msg_error:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
+% \end{syntax}
+% Issues \meta{module} error \meta{message}, passing \meta{arg one} to
+% \meta{arg four} to the text-creating functions. The error
+% interrupts processing and issues the text at the terminal. After user
+% input, the run continues.
+% \end{function}
+%
+% \begin{function}[updated = 2012-08-11]
+% {
+% \msg_warning:nnnnnn ,
+% \msg_warning:nnnnn ,
+% \msg_warning:nnnn ,
+% \msg_warning:nnn ,
+% \msg_warning:nn ,
+% \msg_warning:nnxxxx ,
+% \msg_warning:nnxxx ,
+% \msg_warning:nnxx ,
+% \msg_warning:nnx
+% }
+% \begin{syntax}
+% \cs{msg_warning:nnxxxx} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
+% \end{syntax}
+% Issues \meta{module} warning \meta{message}, passing \meta{arg one}
+% to \meta{arg four} to the text-creating functions. The warning text
+% is added to the log file and the terminal, but the \TeX{} run
+% is not interrupted.
+% \end{function}
+%
+% \begin{function}[updated = 2012-08-11]
+% {
+% \msg_info:nnnnnn ,
+% \msg_info:nnnnn ,
+% \msg_info:nnnn ,
+% \msg_info:nnn ,
+% \msg_info:nn ,
+% \msg_info:nnxxxx ,
+% \msg_info:nnxxx ,
+% \msg_info:nnxx ,
+% \msg_info:nnx
+% }
+% \begin{syntax}
+% \cs{msg_info:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
+% \end{syntax}
+% Issues \meta{module} information \meta{message}, passing
+% \meta{arg one} to \meta{arg four} to the text-creating functions.
+% The information text is added to the log file.
+% \end{function}
+%
+% \begin{function}[updated = 2012-08-11]
+% {
+% \msg_log:nnnnnn ,
+% \msg_log:nnnnn ,
+% \msg_log:nnnn ,
+% \msg_log:nnn ,
+% \msg_log:nn ,
+% \msg_log:nnxxxx ,
+% \msg_log:nnxxx ,
+% \msg_log:nnxx ,
+% \msg_log:nnx
+% }
+% \begin{syntax}
+% \cs{msg_log:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
+% \end{syntax}
+% Issues \meta{module} information \meta{message}, passing
+% \meta{arg one} to \meta{arg four} to the text-creating functions.
+% The information text is added to the log file: the output
+% is briefer than \cs{msg_info:nnnnnn}.
+% \end{function}
+%
+% \begin{function}[updated = 2012-08-11]
+% {
+% \msg_none:nnnnnn ,
+% \msg_none:nnnnn ,
+% \msg_none:nnnn ,
+% \msg_none:nnn ,
+% \msg_none:nn ,
+% \msg_none:nnxxxx ,
+% \msg_none:nnxxx ,
+% \msg_none:nnxx ,
+% \msg_none:nnx
+% }
+% \begin{syntax}
+% \cs{msg_none:nnnnnn} \Arg{module} \Arg{message} \Arg{arg one} \Arg{arg two} \Arg{arg three} \Arg{arg four}
+% \end{syntax}
+% Does nothing: used as a message class to prevent any output at
+% all (see the discussion of message redirection).
+% \end{function}
+%
+% \section{Redirecting messages}
+%
+% Each message has a \enquote{name}, which can be used to alter the behaviour
+% of the message when it is given. Thus we might have
+% \begin{verbatim}
+% \msg_new:nnnn { module } { my-message } { Some~text } { Some~more~text }
+% \end{verbatim}
+% to define a message, with
+% \begin{verbatim}
+% \msg_error:nn { module } { my-message }
+% \end{verbatim}
+% when it is used. With no filtering, this raises an error. However, we
+% could alter the behaviour with
+% \begin{verbatim}
+% \msg_redirect_class:nn { error } { warning }
+% \end{verbatim}
+% to turn all errors into warnings, or with
+% \begin{verbatim}
+% \msg_redirect_module:nnn { module } { error } { warning }
+% \end{verbatim}
+% to alter only messages from that module, or even
+% \begin{verbatim}
+% \msg_redirect_name:nnn { module } { my-message } { warning }
+% \end{verbatim}
+% to target just one message. Redirection applies first to individual messages,
+% then to messages from one module and finally to messages of one class. Thus
+% it is possible to select out an individual message for special treatment
+% even if the entire class is already redirected.
+%
+% Multiple redirections are possible. Redirections can be cancelled by
+% providing an empty argument for the target class. Redirection to a
+% missing class raises an error immediately. Infinite loops are
+% prevented by eliminating the redirection starting from the target of
+% the redirection that caused the loop to appear. Namely, if
+% redirections are requested as $A \to B$, $B \to C$ and $C \to A$ in
+% this order, then the $A \to B$ redirection is cancelled.
+%
+% \begin{function}[updated = 2012-04-27]{\msg_redirect_class:nn}
+% \begin{syntax}
+% \cs{msg_redirect_class:nn} \Arg{class one} \Arg{class two}
+% \end{syntax}
+% Changes the behaviour of messages of \meta{class one} so that they
+% are processed using the code for those of \meta{class two}.
+% \end{function}
+%
+% \begin{function}[updated = 2012-04-27]{\msg_redirect_module:nnn}
+% \begin{syntax}
+% \cs{msg_redirect_module:nnn} \Arg{module} \Arg{class one} \Arg{class two}
+% \end{syntax}
+% Redirects message of \meta{class one} for \meta{module} to act as
+% though they were from \meta{class two}. Messages of \meta{class one}
+% from sources other than \meta{module} are not affected by this
+% redirection. This function can be used to make some messages
+% \enquote{silent} by default. For example, all of the
+% \texttt{warning} messages of \meta{module} could be turned off with:
+% \begin{verbatim}
+% \msg_redirect_module:nnn { module } { warning } { none }
+% \end{verbatim}
+% \end{function}
+%
+% \begin{function}[updated = 2012-04-27]{\msg_redirect_name:nnn}
+% \begin{syntax}
+% \cs{msg_redirect_name:nnn} \Arg{module} \Arg{message} \Arg{class}
+% \end{syntax}
+% Redirects a specific \meta{message} from a specific \meta{module} to
+% act as a member of \meta{class} of messages. No further redirection
+% is performed. This function can be used to make a selected message
+% \enquote{silent} without changing global parameters:
+% \begin{verbatim}
+% \msg_redirect_name:nnn { module } { annoying-message } { none }
+% \end{verbatim}
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3msg} implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<@@=msg>
+% \end{macrocode}
+%
+% \begin{variable}{\l_@@_internal_tl}
+% A general scratch for the module.
+% \begin{macrocode}
+\tl_new:N \l_@@_internal_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_name_str, \l_@@_text_str}
+% Used to save module info when creating messages.
+% \begin{macrocode}
+\str_new:N \l_@@_name_str
+\str_new:N \l_@@_text_str
+% \end{macrocode}
+% \end{variable}
+%
+% \subsection{Creating messages}
+%
+% Messages are created and used separately, so there two parts to
+% the code here. First, a mechanism for creating message text.
+% This is pretty simple, as there is not actually a lot to do.
+%
+% \begin{variable}{\c_@@_text_prefix_tl, \c_@@_more_text_prefix_tl}
+% Locations for the text of messages.
+% \begin{macrocode}
+\tl_const:Nn \c_@@_text_prefix_tl { msg~text~>~ }
+\tl_const:Nn \c_@@_more_text_prefix_tl { msg~extra~text~>~ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[EXP,pTF]{\msg_if_exist:nn}
+% Test whether the control sequence containing the message text exists
+% or not.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \msg_if_exist:nn #1#2 { p , T , F , TF }
+ {
+ \cs_if_exist:cTF { \c_@@_text_prefix_tl #1 / #2 }
+ { \prg_return_true: } { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_chk_if_free:nn}
+% This auxiliary is similar to \cs{__kernel_chk_if_free_cs:N}, and is used when
+% defining messages with \cs{msg_new:nnnn}.
+% \begin{macrocode}
+\__kernel_patch:nnNNpn { }
+ {
+ \__kernel_debug_log:x
+ { Defining~message~ #1 / #2 ~\msg_line_context: }
+ }
+\cs_new_protected:Npn \@@_chk_free:nn #1#2
+ {
+ \msg_if_exist:nnT {#1} {#2}
+ {
+ \__kernel_msg_error:nnxx { kernel } { message-already-defined }
+ {#1} {#2}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\msg_new:nnnn, \msg_new:nnn}
+% \begin{macro}{\msg_gset:nnnn, \msg_gset:nnn}
+% \begin{macro}{\msg_set:nnnn, \msg_set:nnn}
+% Setting a message simply means saving the appropriate text
+% into two functions. A sanity check first.
+% \begin{macrocode}
+\cs_new_protected:Npn \msg_new:nnnn #1#2
+ {
+ \@@_chk_free:nn {#1} {#2}
+ \msg_gset:nnnn {#1} {#2}
+ }
+\cs_new_protected:Npn \msg_new:nnn #1#2#3
+ { \msg_new:nnnn {#1} {#2} {#3} { } }
+\cs_new_protected:Npn \msg_set:nnnn #1#2#3#4
+ {
+ \cs_set:cpn { \c_@@_text_prefix_tl #1 / #2 }
+ ##1##2##3##4 {#3}
+ \cs_set:cpn { \c_@@_more_text_prefix_tl #1 / #2 }
+ ##1##2##3##4 {#4}
+ }
+\cs_new_protected:Npn \msg_set:nnn #1#2#3
+ { \msg_set:nnnn {#1} {#2} {#3} { } }
+\cs_new_protected:Npn \msg_gset:nnnn #1#2#3#4
+ {
+ \cs_gset:cpn { \c_@@_text_prefix_tl #1 / #2 }
+ ##1##2##3##4 {#3}
+ \cs_gset:cpn { \c_@@_more_text_prefix_tl #1 / #2 }
+ ##1##2##3##4 {#4}
+ }
+\cs_new_protected:Npn \msg_gset:nnn #1#2#3
+ { \msg_gset:nnnn {#1} {#2} {#3} { } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Messages: support functions and text}
+%
+% \begin{variable}
+% {
+% \c_@@_coding_error_text_tl ,
+% \c_@@_continue_text_tl ,
+% \c_@@_critical_text_tl ,
+% \c_@@_fatal_text_tl ,
+% \c_@@_help_text_tl ,
+% \c_@@_no_info_text_tl ,
+% \c_@@_on_line_text_tl ,
+% \c_@@_return_text_tl ,
+% \c_@@_trouble_text_tl
+% }
+% Simple pieces of text for messages.
+% \begin{macrocode}
+\tl_const:Nn \c_@@_coding_error_text_tl
+ {
+ This~is~a~coding~error.
+ \\ \\
+ }
+\tl_const:Nn \c_@@_continue_text_tl
+ { Type~<return>~to~continue }
+\tl_const:Nn \c_@@_critical_text_tl
+ { Reading~the~current~file~'\g_file_curr_name_str'~will~stop. }
+\tl_const:Nn \c_@@_fatal_text_tl
+ { This~is~a~fatal~error:~LaTeX~will~abort. }
+\tl_const:Nn \c_@@_help_text_tl
+ { For~immediate~help~type~H~<return> }
+\tl_const:Nn \c_@@_no_info_text_tl
+ {
+ LaTeX~does~not~know~anything~more~about~this~error,~sorry.
+ \c_@@_return_text_tl
+ }
+\tl_const:Nn \c_@@_on_line_text_tl { on~line }
+\tl_const:Nn \c_@@_return_text_tl
+ {
+ \\ \\
+ Try~typing~<return>~to~proceed.
+ \\
+ If~that~doesn't~work,~type~X~<return>~to~quit.
+ }
+\tl_const:Nn \c_@@_trouble_text_tl
+ {
+ \\ \\
+ More~errors~will~almost~certainly~follow: \\
+ the~LaTeX~run~should~be~aborted.
+ }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\msg_line_number:, \msg_line_context:}
+% For writing the line number nicely. \cs{msg_line_context:} was set up
+% earlier, so this is not \texttt{new}.
+% \begin{macrocode}
+\cs_new:Npn \msg_line_number: { \int_use:N \tex_inputlineno:D }
+\cs_gset:Npn \msg_line_context:
+ {
+ \c_@@_on_line_text_tl
+ \c_space_tl
+ \msg_line_number:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Showing messages: low level mechanism}
+%
+% \begin{macro}{\@@_interrupt:Nnnn}
+% \begin{macro}{\@@_no_more_text:nnnn}
+% The low-level interruption macro is rather opaque, unfortunately.
+% Depending on the availability of more information there is a choice
+% of how to set up the further help. We feed the extra help text and
+% the message itself to a wrapping auxiliary, in this order because we
+% must first setup \TeX{}'s \tn{errhelp} register before issuing an
+% \tn{errmessage}. To deal with the various cases of critical or fatal
+% errors with and without help text, there is a bit of argument-passing
+% to do.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_interrupt:NnnnN #1#2#3#4#5
+ {
+ \str_set:Nx \l_@@_text_str { #1 {#2} }
+ \str_set:Nx \l_@@_name_str { \msg_module_name:n {#2} }
+ \cs_if_eq:cNTF
+ { \c_@@_more_text_prefix_tl #2 / #3 }
+ \@@_no_more_text:nnnn
+ {
+ \@@_interrupt_wrap:nnn
+ { \use:c { \c_@@_text_prefix_tl #2 / #3 } #4 }
+ { \c_@@_continue_text_tl }
+ {
+ \c_@@_no_info_text_tl
+ \tl_if_empty:NF #5
+ { \\ \\ #5 }
+ }
+ }
+ {
+ \@@_interrupt_wrap:nnn
+ { \use:c { \c_@@_text_prefix_tl #2 / #3 } #4 }
+ { \c_@@_help_text_tl }
+ {
+ \use:c { \c_@@_more_text_prefix_tl #2 / #3 } #4
+ \tl_if_empty:NF #5
+ { \\ \\ #5 }
+ }
+ }
+ }
+\cs_new:Npn \@@_no_more_text:nnnn #1#2#3#4 { }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_interrupt_wrap:nnn}
+% \begin{macro}{\@@_interrupt_text:n, \@@_interrupt_more_text:n}
+% First setup \TeX{}'s \tn{errhelp} register with the extra help |#1|,
+% then build a nice-looking error message with |#2|. Everything is
+% done using \texttt{x}-type expansion as the new line markers are
+% different for the two type of text and need to be correctly set up.
+% The auxiliary \cs{@@_interrupt_more_text:n} receives its argument
+% as a line-wrapped string, which is thus unaffected by expansion.
+% We ave to split the main text into two parts as only the \enquote{message}
+% itself is wrapped with a leader: the generic help is wrapped at full
+% width. We also have to allow for the two characters used by \tn{errmessage}
+% itself.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_interrupt_wrap:nnn #1#2#3
+ {
+ \iow_wrap:nnnN { \\ #3 } { } { } \@@_interrupt_more_text:n
+ \group_begin:
+ \int_sub:Nn \l_iow_line_count_int { 2 }
+ \iow_wrap:nxnN { \l_@@_text_str : ~ #1 }
+ {
+ ( \l_@@_name_str )
+ \prg_replicate:nn
+ {
+ \str_count:N \l_@@_text_str
+ - \str_count:N \l_@@_name_str
+ + 2
+ }
+ { ~ }
+ }
+ { } \@@_interrupt_text:n
+ \iow_wrap:nnnN { \l_@@_internal_tl \\ \\ #2 } { } { }
+ \@@_interrupt:n
+ }
+\cs_new_protected:Npn \@@_interrupt_text:n #1
+ {
+ \group_end:
+ \tl_set:Nn \l_@@_internal_tl {#1}
+ }
+\cs_new_protected:Npn \@@_interrupt_more_text:n #1
+ { \exp_args:Nx \tex_errhelp:D { #1 \iow_newline: } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_interrupt:n}
+% The business end of the process starts by producing some visual
+% separation of the message from the main part of the log. The error
+% message needs to be printed with everything made
+% \enquote{invisible}: \TeX{}'s own information involves the macro in
+% which \tn{errmessage} is called, and the end of the argument of the
+% \tn{errmessage}, including the closing brace. We use an active |!|
+% to call the \tn{errmessage} primitive, and end its argument with
+% \cs{use_none:n} \Arg{spaces} which fills the output with spaces. Two
+% trailing closing braces are turned into spaces to hide them as well.
+% The group in which we alter the definition of the active |!| is
+% closed before producing the message: this ensures that tokens
+% inserted by typing |I| in the command-line are inserted after
+% the message is entirely cleaned up.
+%
+% The \cs{__kernel_iow_with:Nnn} auxiliary, defined in \pkg{l3file}, expects
+% an \meta{integer variable}, an integer \meta{value}, and some
+% \meta{code}. It runs the \meta{code} after ensuring that the
+% \meta{integer variable} takes the given \meta{value}, then restores
+% the former value of the \meta{integer variable} if needed. We use
+% it to ensure that the \tn{newlinechar} is $10$, as needed for
+% \cs{iow_newline:} to work, and that \tn{errorcontextlines} is $-1$,
+% to avoid showing irrelevant context. Note that restoring the former
+% value of these integers requires inserting tokens after the
+% \tn{errmessage}, which go in the way of tokens which could be
+% inserted by the user. This is unavoidable.
+% \begin{macrocode}
+\group_begin:
+ \char_set_lccode:nn { 38 } { 32 } % &
+ \char_set_lccode:nn { 46 } { 32 } % .
+ \char_set_lccode:nn { 123 } { 32 } % {
+ \char_set_lccode:nn { 125 } { 32 } % }
+ \char_set_catcode_active:N \&
+\tex_lowercase:D
+ {
+ \group_end:
+ \cs_new_protected:Npn \@@_interrupt:n #1
+ {
+ \iow_term:n { }
+ \__kernel_iow_with:Nnn \tex_newlinechar:D { `\^^J }
+ {
+ \__kernel_iow_with:Nnn \tex_errorcontextlines:D { -1 }
+ {
+ \group_begin:
+ \cs_set_protected:Npn &
+ {
+ \tex_errmessage:D
+ {
+ #1
+ \use_none:n
+ { ............................................ }
+ }
+ }
+ \exp_after:wN
+ \group_end:
+ &
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Displaying messages}
+%
+% \LaTeX{} is handling error messages and so the \TeX{} ones are disabled.
+% This is already done by the \LaTeXe{} kernel, so to avoid messing up any
+% deliberate change by a user this is only set in format mode.
+% \begin{macrocode}
+%<*initex>
+\int_gset:Nn \tex_errorcontextlines:D { -1 }
+%</initex>
+% \end{macrocode}
+%
+% \begin{macro}[EXP]
+% {
+% \msg_fatal_text:n ,
+% \msg_critical_text:n ,
+% \msg_error_text:n ,
+% \msg_warning_text:n ,
+% \msg_info_text:n
+% }
+% \begin{macro}[EXP]{\@@_text:nn}
+% \begin{macro}[EXP]{\@@_text:n}
+% A function for issuing messages: both the text and order could
+% in principle vary. The module name may be empty for kernel messages,
+% hence the slightly contorted code path for a space.
+% \begin{macrocode}
+\cs_new:Npn \msg_fatal_text:n #1
+ {
+ Fatal ~
+ \msg_error_text:n {#1}
+ }
+\cs_new:Npn \msg_critical_text:n #1
+ {
+ Critical ~
+ \msg_error_text:n {#1}
+ }
+\cs_new:Npn \msg_error_text:n #1
+ { \@@_text:nn {#1} { Error } }
+\cs_new:Npn \msg_warning_text:n #1
+ { \@@_text:nn {#1} { Warning } }
+\cs_new:Npn \msg_info_text:n #1
+ { \@@_text:nn {#1} { Info } }
+\cs_new:Npn \@@_text:nn #1#2
+ {
+ \exp_args:Nf \@@_text:n { \msg_module_type:n {#1} }
+ \msg_module_name:n {#1} ~
+ #2
+ }
+\cs_new:Npn \@@_text:n #1
+ {
+ \tl_if_blank:nF {#1}
+ { #1 ~ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{variable}{\g_msg_module_name_prop, \g_msg_module_type_prop}
+% For storing public module information: the kernel data is set up
+% in advance.
+% \begin{macrocode}
+\prop_new:N \g_msg_module_name_prop
+\prop_gput:Nnn \g_msg_module_name_prop { LaTeX } { LaTeX3 }
+\prop_new:N \g_msg_module_type_prop
+\prop_gput:Nnn \g_msg_module_type_prop { LaTeX } { }
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[EXP]{\msg_module_type:n}
+% Contextual footer information, with the potential to give modules an
+% alternative name.
+% \begin{macrocode}
+\cs_new:Npn \msg_module_type:n #1
+ {
+ \prop_if_in:NnTF \g_msg_module_type_prop {#1}
+ { \prop_item:Nn \g_msg_module_type_prop {#1} }
+%<*initex>
+ { Module }
+%</initex>
+%<*package>
+ { Package }
+%</package>
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\msg_module_name:n, \msg_see_documentation_text:n}
+% Contextual footer information, with the potential to give modules an
+% alternative name.
+% \begin{macrocode}
+\cs_new:Npn \msg_module_name:n #1
+ {
+ \prop_if_in:NnTF \g_msg_module_name_prop {#1}
+ { \prop_item:Nn \g_msg_module_name_prop {#1} }
+ {#1}
+ }
+\cs_new:Npn \msg_see_documentation_text:n #1
+ {
+ See~the~ \msg_module_name:n {#1} ~
+ documentation~for~further~information.
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_class_new:nn}
+% \begin{macrocode}
+\group_begin:
+ \cs_set_protected:Npn \@@_class_new:nn #1#2
+ {
+ \prop_new:c { l_@@_redirect_ #1 _prop }
+ \cs_new_protected:cpn { @@_ #1 _code:nnnnnn }
+ ##1##2##3##4##5##6 {#2}
+ \cs_new_protected:cpn { msg_ #1 :nnnnnn } ##1##2##3##4##5##6
+ {
+ \use:x
+ {
+ \exp_not:n { \@@_use:nnnnnnn {#1} {##1} {##2} }
+ { \tl_to_str:n {##3} } { \tl_to_str:n {##4} }
+ { \tl_to_str:n {##5} } { \tl_to_str:n {##6} }
+ }
+ }
+ \cs_new_protected:cpx { msg_ #1 :nnnnn } ##1##2##3##4##5
+ { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} {##4} {##5} { } }
+ \cs_new_protected:cpx { msg_ #1 :nnnn } ##1##2##3##4
+ { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} {##4} { } { } }
+ \cs_new_protected:cpx { msg_ #1 :nnn } ##1##2##3
+ { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} {##3} { } { } { } }
+ \cs_new_protected:cpx { msg_ #1 :nn } ##1##2
+ { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} { } { } { } { } }
+ \cs_new_protected:cpx { msg_ #1 :nnxxxx } ##1##2##3##4##5##6
+ {
+ \use:x
+ {
+ \exp_not:N \exp_not:n
+ { \exp_not:c { msg_ #1 :nnnnnn } {##1} {##2} }
+ {##3} {##4} {##5} {##6}
+ }
+ }
+ \cs_new_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5
+ { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } }
+ \cs_new_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4
+ { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } }
+ \cs_new_protected:cpx { msg_ #1 :nnx } ##1##2##3
+ { \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \msg_fatal:nnnnnn ,
+% \msg_fatal:nnnnn ,
+% \msg_fatal:nnnn ,
+% \msg_fatal:nnn ,
+% \msg_fatal:nn ,
+% \msg_fatal:nnxxxx ,
+% \msg_fatal:nnxxx ,
+% \msg_fatal:nnxx ,
+% \msg_fatal:nnx
+% }
+% \begin{macro}{\@@_fatal_exit:}
+% For fatal errors, after the error message \TeX{} bails out. We force
+% a bail out rather than using \tn{end} as this means it does not
+% matter if we are in a context where normally the run cannot end.
+% \begin{macrocode}
+ \@@_class_new:nn { fatal }
+ {
+ \@@_interrupt:NnnnN
+ \msg_fatal_text:n {#1} {#2}
+ { {#3} {#4} {#5} {#6} }
+ \c_@@_fatal_text_tl
+ \@@_fatal_exit:
+ }
+ \cs_new_protected:Npn \@@_fatal_exit:
+ {
+ \tex_batchmode:D
+ \tex_read:D -1 to \l_@@_internal_tl
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \msg_critical:nnnnnn ,
+% \msg_critical:nnnnn ,
+% \msg_critical:nnnn ,
+% \msg_critical:nnn ,
+% \msg_critical:nn ,
+% \msg_critical:nnxxxx ,
+% \msg_critical:nnxxx ,
+% \msg_critical:nnxx ,
+% \msg_critical:nnx
+% }
+% Not quite so bad: just end the current file.
+% \begin{macrocode}
+ \@@_class_new:nn { critical }
+ {
+ \@@_interrupt:NnnnN
+ \msg_critical_text:n {#1} {#2}
+ { {#3} {#4} {#5} {#6} }
+ \c_@@_critical_text_tl
+ \tex_endinput:D
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \msg_error:nnnnnn ,
+% \msg_error:nnnnn ,
+% \msg_error:nnnn ,
+% \msg_error:nnn ,
+% \msg_error:nn ,
+% \msg_error:nnxxxx ,
+% \msg_error:nnxxx ,
+% \msg_error:nnxx ,
+% \msg_error:nnx
+% }
+% For an error, the interrupt routine is called. We check if there is
+% a \enquote{more text} by comparing that control sequence with a
+% permanently empty text.
+% \begin{macrocode}
+ \@@_class_new:nn { error }
+ {
+ \@@_interrupt:NnnnN
+ \msg_error_text:n {#1} {#2}
+ { {#3} {#4} {#5} {#6} }
+ \c_empty_tl
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \msg_warning:nnnnnn ,
+% \msg_warning:nnnnn ,
+% \msg_warning:nnnn ,
+% \msg_warning:nnn ,
+% \msg_warning:nn ,
+% \msg_warning:nnxxxx ,
+% \msg_warning:nnxxx ,
+% \msg_warning:nnxx ,
+% \msg_warning:nnx
+% }
+% Warnings are printed to the terminal.
+% \begin{macrocode}
+ \@@_class_new:nn { warning }
+ {
+ \str_set:Nx \l_@@_text_str { \msg_warning_text:n {#1} }
+ \str_set:Nx \l_@@_name_str { \msg_module_name:n {#1} }
+ \iow_term:n { }
+ \iow_wrap:nxnN
+ {
+ \l_@@_text_str : ~
+ \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6}
+ }
+ {
+ ( \l_@@_name_str )
+ \prg_replicate:nn
+ {
+ \str_count:N \l_@@_text_str
+ - \str_count:N \l_@@_name_str
+ }
+ { ~ }
+ }
+ { } \iow_term:n
+ \iow_term:n { }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \msg_info:nnnnnn ,
+% \msg_info:nnnnn ,
+% \msg_info:nnnn ,
+% \msg_info:nnn ,
+% \msg_info:nn ,
+% \msg_info:nnxxxx ,
+% \msg_info:nnxxx ,
+% \msg_info:nnxx ,
+% \msg_info:nnx
+% }
+% Information only goes into the log.
+% \begin{macrocode}
+ \@@_class_new:nn { info }
+ {
+ \str_set:Nx \l_@@_text_str { \msg_info_text:n {#1} }
+ \str_set:Nx \l_@@_name_str { \msg_module_name:n {#1} }
+ \iow_log:n { }
+ \iow_wrap:nxnN
+ {
+ \l_@@_text_str : ~
+ \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6}
+ }
+ {
+ ( \l_@@_name_str )
+ \prg_replicate:nn
+ {
+ \str_count:N \l_@@_text_str
+ - \str_count:N \l_@@_name_str
+ }
+ { ~ }
+ }
+ { } \iow_log:n
+ \iow_log:n { }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \msg_log:nnnnnn ,
+% \msg_log:nnnnn ,
+% \msg_log:nnnn ,
+% \msg_log:nnn ,
+% \msg_log:nn ,
+% \msg_log:nnxxxx ,
+% \msg_log:nnxxx ,
+% \msg_log:nnxx ,
+% \msg_log:nnx
+% }
+% \enquote{Log} data is very similar to information, but with no extras
+% added.
+% \begin{macrocode}
+ \@@_class_new:nn { log }
+ {
+ \iow_wrap:nnnN
+ { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} }
+ { } { } \iow_log:n
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \msg_none:nnnnnn ,
+% \msg_none:nnnnn ,
+% \msg_none:nnnn ,
+% \msg_none:nnn ,
+% \msg_none:nn ,
+% \msg_none:nnxxxx ,
+% \msg_none:nnxxx ,
+% \msg_none:nnxx ,
+% \msg_none:nnx
+% }
+% The \texttt{none} message type is needed so that input can be gobbled.
+% \begin{macrocode}
+ \@@_class_new:nn { none } { }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \msg_show:nnnnnn ,
+% \msg_show:nnnnn ,
+% \msg_show:nnnn ,
+% \msg_show:nnn ,
+% \msg_show:nn ,
+% \msg_show:nnxxxx ,
+% \msg_show:nnxxx ,
+% \msg_show:nnxx ,
+% \msg_show:nnx
+% }
+% \begin{macro}{\@@_show:n, \@@_show:w, \@@_show_dot:w, \@@_show:nn}
+% The \texttt{show} message type is used for \cs{seq_show:N} and
+% similar complicated data structures. Wrap the given text with a
+% trailing dot (important later) then pass it to \cs{@@_show:n}. If
+% there is |\\>~| (or if the whole thing starts with |>~|) we split
+% there, print the first part and show the second part using
+% \tn{showtokens} (the \cs{exp_after:wN} ensure a nice display). Note
+% that that primitive adds a leading |>~| and trailing dot. That is
+% why we included a trailing dot before wrapping and removed it
+% afterwards. If there is no |\\>~| do the same but with an empty
+% second part which adds a spurious but inevitable |>~.|
+% \begin{macrocode}
+ \@@_class_new:nn { show }
+ {
+ \iow_wrap:nnnN
+ { \use:c { \c_@@_text_prefix_tl #1 / #2 } {#3} {#4} {#5} {#6} }
+ { } { } \@@_show:n
+ }
+ \cs_new_protected:Npn \@@_show:n #1
+ {
+ \tl_if_in:nnTF { ^^J #1 } { ^^J > ~ }
+ {
+ \tl_if_in:nnTF { #1 \q_mark } { . \q_mark }
+ { \@@_show_dot:w } { \@@_show:w }
+ ^^J #1 \q_stop
+ }
+ { \@@_show:nn { ? #1 } { } }
+ }
+ \cs_new:Npn \@@_show_dot:w #1 ^^J > ~ #2 . \q_stop
+ { \@@_show:nn {#1} {#2} }
+ \cs_new:Npn \@@_show:w #1 ^^J > ~ #2 \q_stop
+ { \@@_show:nn {#1} {#2} }
+ \cs_new_protected:Npn \@@_show:nn #1#2
+ {
+ \tl_if_empty:nF {#1}
+ { \exp_args:No \iow_term:n { \use_none:n #1 } }
+ \tl_set:Nn \l_@@_internal_tl {#2}
+ \__kernel_iow_with:Nnn \tex_newlinechar:D { 10 }
+ {
+ \__kernel_iow_with:Nnn \tex_errorcontextlines:D { -1 }
+ {
+ \tex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN
+ { \exp_after:wN \l_@@_internal_tl }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% End the group to eliminate \cs{@@_class_new:nn}.
+% \begin{macrocode}
+\group_end:
+% \end{macrocode}
+%
+% \begin{macro}{\@@_class_chk_exist:nT}
+% Checking that a message class exists. We build this from
+% \cs{cs_if_free:cTF} rather than \cs{cs_if_exist:cTF} because that
+% avoids reading the second argument earlier than necessary.
+% \begin{macrocode}
+\cs_new:Npn \@@_class_chk_exist:nT #1
+ {
+ \cs_if_free:cTF { @@_ #1 _code:nnnnnn }
+ { \__kernel_msg_error:nnx { kernel } { message-class-unknown } {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_class_tl, \l_@@_current_class_tl}
+% Support variables needed for the redirection system.
+% \begin{macrocode}
+\tl_new:N \l_@@_class_tl
+\tl_new:N \l_@@_current_class_tl
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_redirect_prop}
+% For redirection of individually-named messages
+% \begin{macrocode}
+\prop_new:N \l_@@_redirect_prop
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_hierarchy_seq}
+% During redirection, split the message name into a sequence:
+% |{/module/submodule}|, |{/module}|, and |{}|.
+% \begin{macrocode}
+\seq_new:N \l_@@_hierarchy_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_class_loop_seq}
+% Classes encountered when following redirections to check for loops.
+% \begin{macrocode}
+\seq_new:N \l_@@_class_loop_seq
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\@@_use:nnnnnnn}
+% \begin{macro}
+% {
+% \@@_use_redirect_name:n , \@@_use_hierarchy:nwwN ,
+% \@@_use_redirect_module:n, \@@_use_code:
+% }
+% Actually using a message is a multi-step process. First, some
+% safety checks on the message and class requested. The code and
+% arguments are then stored to avoid passing them around. The
+% assignment to \cs{@@_use_code:} is similar to \cs{tl_set:Nn}.
+% The message is eventually produced with whatever \cs{l_@@_class_tl}
+% is when \cs{@@_use_code:} is called.
+% Here is also a good place to suppress tracing output if the
+% \pkg{trace} package is loaded since all (non-expandable) messages go
+% through this auxiliary.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_use:nnnnnnn #1#2#3#4#5#6#7
+ {
+%<package> \cs_if_exist_use:N \conditionally@traceoff
+ \msg_if_exist:nnTF {#2} {#3}
+ {
+ \@@_class_chk_exist:nT {#1}
+ {
+ \tl_set:Nn \l_@@_current_class_tl {#1}
+ \cs_set_protected:Npx \@@_use_code:
+ {
+ \exp_not:n
+ {
+ \use:c { @@_ \l_@@_class_tl _code:nnnnnn }
+ {#2} {#3} {#4} {#5} {#6} {#7}
+ }
+ }
+ \@@_use_redirect_name:n { #2 / #3 }
+ }
+ }
+ { \__kernel_msg_error:nnxx { kernel } { message-unknown } {#2} {#3} }
+%<package> \cs_if_exist_use:N \conditionally@traceon
+ }
+\cs_new_protected:Npn \@@_use_code: { }
+% \end{macrocode}
+% The first check is for a individual message redirection. If this
+% applies then no further redirection is attempted. Otherwise, split
+% the message name into \meta{module}, \meta{submodule} and \meta{message}
+% (with an
+% arbitrary number of slashes), and store |{/module/submodule}|,
+% |{/module}| and |{}| into \cs{l_@@_hierarchy_seq}. We then
+% map through this sequence, applying the most specific redirection.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_use_redirect_name:n #1
+ {
+ \prop_get:NnNTF \l_@@_redirect_prop { / #1 } \l_@@_class_tl
+ { \@@_use_code: }
+ {
+ \seq_clear:N \l_@@_hierarchy_seq
+ \@@_use_hierarchy:nwwN { }
+ #1 \q_mark \@@_use_hierarchy:nwwN
+ / \q_mark \use_none_delimit_by_q_stop:w
+ \q_stop
+ \@@_use_redirect_module:n { }
+ }
+ }
+\cs_new_protected:Npn \@@_use_hierarchy:nwwN #1#2 / #3 \q_mark #4
+ {
+ \seq_put_left:Nn \l_@@_hierarchy_seq {#1}
+ #4 { #1 / #2 } #3 \q_mark #4
+ }
+% \end{macrocode}
+% At this point, the items of \cs{l_@@_hierarchy_seq} are the
+% various levels at which we should look for a redirection.
+% Redirections which are less specific than the argument of
+% \cs{@@_use_redirect_module:n} are not attempted. This argument is
+% empty for a class redirection, \texttt{/module} for a module
+% redirection, \emph{etc.} Loop through the sequence to find the most
+% specific redirection, with module |##1|. The loop is interrupted
+% after testing for a redirection for |##1| equal to the argument |#1|
+% (least specific redirection allowed). When a redirection is found,
+% break the mapping, then if the redirection targets the same class,
+% output the code with that class, and otherwise set the target as the
+% new current class, and search for further redirections. Those
+% redirections should be at least as specific as |##1|.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_use_redirect_module:n #1
+ {
+ \seq_map_inline:Nn \l_@@_hierarchy_seq
+ {
+ \prop_get:cnNTF { l_@@_redirect_ \l_@@_current_class_tl _prop }
+ {##1} \l_@@_class_tl
+ {
+ \seq_map_break:n
+ {
+ \tl_if_eq:NNTF \l_@@_current_class_tl \l_@@_class_tl
+ { \@@_use_code: }
+ {
+ \tl_set_eq:NN \l_@@_current_class_tl \l_@@_class_tl
+ \@@_use_redirect_module:n {##1}
+ }
+ }
+ }
+ {
+ \str_if_eq:nnT {##1} {#1}
+ {
+ \tl_set_eq:NN \l_@@_class_tl \l_@@_current_class_tl
+ \seq_map_break:n { \@@_use_code: }
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\msg_redirect_name:nnn}
+% Named message always use the given class even if that class is
+% redirected further. An empty target class cancels any existing
+% redirection for that message.
+% \begin{macrocode}
+\cs_new_protected:Npn \msg_redirect_name:nnn #1#2#3
+ {
+ \tl_if_empty:nTF {#3}
+ { \prop_remove:Nn \l_@@_redirect_prop { / #1 / #2 } }
+ {
+ \@@_class_chk_exist:nT {#3}
+ { \prop_put:Nnn \l_@@_redirect_prop { / #1 / #2 } {#3} }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\msg_redirect_class:nn, \msg_redirect_module:nnn}
+% \begin{macro}{\@@_redirect:nnn, \@@_redirect_loop_chk:nnn}
+% \begin{macro}{\@@_redirect_loop_list:n}
+% If the target class is empty, eliminate the corresponding
+% redirection. Otherwise, add the redirection. We must then check
+% for a loop: as an initialization, we start by storing the initial
+% class in \cs{l_@@_current_class_tl}.
+% \begin{macrocode}
+\cs_new_protected:Npn \msg_redirect_class:nn
+ { \@@_redirect:nnn { } }
+\cs_new_protected:Npn \msg_redirect_module:nnn #1
+ { \@@_redirect:nnn { / #1 } }
+\cs_new_protected:Npn \@@_redirect:nnn #1#2#3
+ {
+ \@@_class_chk_exist:nT {#2}
+ {
+ \tl_if_empty:nTF {#3}
+ { \prop_remove:cn { l_@@_redirect_ #2 _prop } {#1} }
+ {
+ \@@_class_chk_exist:nT {#3}
+ {
+ \prop_put:cnn { l_@@_redirect_ #2 _prop } {#1} {#3}
+ \tl_set:Nn \l_@@_current_class_tl {#2}
+ \seq_clear:N \l_@@_class_loop_seq
+ \@@_redirect_loop_chk:nnn {#2} {#3} {#1}
+ }
+ }
+ }
+ }
+% \end{macrocode}
+% Since multiple redirections can only happen with increasing
+% specificity, a loop requires that all steps are of the same
+% specificity. The new redirection can thus only create a loop with
+% other redirections for the exact same module, |#1|, and not
+% submodules. After some initialization above, follow redirections
+% with \cs{l_@@_class_tl}, and keep track in
+% \cs{l_@@_class_loop_seq} of the various classes encountered. A
+% redirection from a class to itself, or the absence of redirection
+% both mean that there is no loop. A redirection to the initial class
+% marks a loop. To break it, we must decide which redirection to
+% cancel. The user most likely wants the newly added redirection to
+% hold with no further redirection. We thus remove the redirection
+% starting from |#2|, target of the new redirection. Note that no
+% message is emitted by any of the underlying functions: otherwise we
+% may get an infinite loop because of a message from the message
+% system itself.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_redirect_loop_chk:nnn #1#2#3
+ {
+ \seq_put_right:Nn \l_@@_class_loop_seq {#1}
+ \prop_get:cnNT { l_@@_redirect_ #1 _prop } {#3} \l_@@_class_tl
+ {
+ \str_if_eq:VnF \l_@@_class_tl {#1}
+ {
+ \tl_if_eq:NNTF \l_@@_class_tl \l_@@_current_class_tl
+ {
+ \prop_put:cnn { l_@@_redirect_ #2 _prop } {#3} {#2}
+ \__kernel_msg_warning:nnxxxx
+ { kernel } { message-redirect-loop }
+ { \seq_item:Nn \l_@@_class_loop_seq { 1 } }
+ { \seq_item:Nn \l_@@_class_loop_seq { 2 } }
+ {#3}
+ {
+ \seq_map_function:NN \l_@@_class_loop_seq
+ \@@_redirect_loop_list:n
+ { \seq_item:Nn \l_@@_class_loop_seq { 1 } }
+ }
+ }
+ { \@@_redirect_loop_chk:onn \l_@@_class_tl {#2} {#3} }
+ }
+ }
+ }
+\cs_generate_variant:Nn \@@_redirect_loop_chk:nnn { o }
+\cs_new:Npn \@@_redirect_loop_list:n #1 { {#1} ~ => ~ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Kernel-specific functions}
+%
+% \begin{macro}{\__kernel_msg_new:nnnn, \__kernel_msg_new:nnn}
+% \begin{macro}{\__kernel_msg_set:nnnn, \__kernel_msg_set:nnn}
+% The kernel needs some messages of its own. These are created using
+% pre-built functions. Two functions are provided: one more general
+% and one which only has the short text part.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_msg_new:nnnn #1#2
+ { \msg_new:nnnn { LaTeX } { #1 / #2 } }
+\cs_new_protected:Npn \__kernel_msg_new:nnn #1#2
+ { \msg_new:nnn { LaTeX } { #1 / #2 } }
+\cs_new_protected:Npn \__kernel_msg_set:nnnn #1#2
+ { \msg_set:nnnn { LaTeX } { #1 / #2 } }
+\cs_new_protected:Npn \__kernel_msg_set:nnn #1#2
+ { \msg_set:nnn { LaTeX } { #1 / #2 } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_kernel_class_new:nN}
+% \begin{macro}{\@@_kernel_class_new_aux:nN}
+% All the functions for kernel messages come in variants ranging
+% from~$0$ to~$4$ arguments. Those with less than~$4$ arguments are
+% defined in terms of the $4$-argument variant, in a way very similar
+% to \cs{@@_class_new:nn}. This auxiliary is destroyed at the end of
+% the group.
+% \begin{macrocode}
+\group_begin:
+ \cs_set_protected:Npn \@@_kernel_class_new:nN #1
+ { \@@_kernel_class_new_aux:nN { __kernel_msg_ #1 } }
+ \cs_set_protected:Npn \@@_kernel_class_new_aux:nN #1#2
+ {
+ \cs_new_protected:cpn { #1 :nnnnnn } ##1##2##3##4##5##6
+ {
+ \use:x
+ {
+ \exp_not:n { #2 { LaTeX } { ##1 / ##2 } }
+ { \tl_to_str:n {##3} } { \tl_to_str:n {##4} }
+ { \tl_to_str:n {##5} } { \tl_to_str:n {##6} }
+ }
+ }
+ \cs_new_protected:cpx { #1 :nnnnn } ##1##2##3##4##5
+ { \exp_not:c { #1 :nnnnnn } {##1} {##2} {##3} {##4} {##5} { } }
+ \cs_new_protected:cpx { #1 :nnnn } ##1##2##3##4
+ { \exp_not:c { #1 :nnnnnn } {##1} {##2} {##3} {##4} { } { } }
+ \cs_new_protected:cpx { #1 :nnn } ##1##2##3
+ { \exp_not:c { #1 :nnnnnn } {##1} {##2} {##3} { } { } { } }
+ \cs_new_protected:cpx { #1 :nn } ##1##2
+ { \exp_not:c { #1 :nnnnnn } {##1} {##2} { } { } { } { } }
+ \cs_new_protected:cpx { #1 :nnxxxx } ##1##2##3##4##5##6
+ {
+ \use:x
+ {
+ \exp_not:N \exp_not:n
+ { \exp_not:c { #1 :nnnnnn } {##1} {##2} }
+ {##3} {##4} {##5} {##6}
+ }
+ }
+ \cs_new_protected:cpx { #1 :nnxxx } ##1##2##3##4##5
+ { \exp_not:c { #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { } }
+ \cs_new_protected:cpx { #1 :nnxx } ##1##2##3##4
+ { \exp_not:c { #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { } }
+ \cs_new_protected:cpx { #1 :nnx } ##1##2##3
+ { \exp_not:c { #1 :nnxxxx } {##1} {##2} {##3} { } { } { } }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \__kernel_msg_fatal:nnnnnn ,
+% \__kernel_msg_fatal:nnnnn ,
+% \__kernel_msg_fatal:nnnn ,
+% \__kernel_msg_fatal:nnn ,
+% \__kernel_msg_fatal:nn ,
+% \__kernel_msg_fatal:nnxxxx ,
+% \__kernel_msg_fatal:nnxxx ,
+% \__kernel_msg_fatal:nnxx ,
+% \__kernel_msg_fatal:nnx ,
+% \__kernel_msg_error:nnnnnn ,
+% \__kernel_msg_error:nnnnn ,
+% \__kernel_msg_error:nnnn ,
+% \__kernel_msg_error:nnn ,
+% \__kernel_msg_error:nn ,
+% \__kernel_msg_error:nnxxxx ,
+% \__kernel_msg_error:nnxxx ,
+% \__kernel_msg_error:nnxx ,
+% \__kernel_msg_error:nnx
+% }
+% Neither fatal kernel errors nor kernel errors can be redirected. We
+% directly use the code for (non-kernel) fatal errors and errors,
+% adding the \enquote{\LaTeX{}} module name. Three functions are
+% already defined by \pkg{l3basics}; we need to undefine them to avoid
+% errors.
+% \begin{macrocode}
+ \@@_kernel_class_new:nN { fatal } \@@_fatal_code:nnnnnn
+ \cs_undefine:N \__kernel_msg_error:nnxx
+ \cs_undefine:N \__kernel_msg_error:nnx
+ \cs_undefine:N \__kernel_msg_error:nn
+ \@@_kernel_class_new:nN { error } \@@_error_code:nnnnnn
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \__kernel_msg_warning:nnnnnn ,
+% \__kernel_msg_warning:nnnnn ,
+% \__kernel_msg_warning:nnnn ,
+% \__kernel_msg_warning:nnn ,
+% \__kernel_msg_warning:nn ,
+% \__kernel_msg_warning:nnxxxx ,
+% \__kernel_msg_warning:nnxxx ,
+% \__kernel_msg_warning:nnxx ,
+% \__kernel_msg_warning:nnx ,
+% \__kernel_msg_info:nnnnnn ,
+% \__kernel_msg_info:nnnnn ,
+% \__kernel_msg_info:nnnn ,
+% \__kernel_msg_info:nnn ,
+% \__kernel_msg_info:nn ,
+% \__kernel_msg_info:nnxxxx ,
+% \__kernel_msg_info:nnxxx ,
+% \__kernel_msg_info:nnxx ,
+% \__kernel_msg_info:nnx
+% }
+% Kernel messages which can be redirected simply use the machinery for
+% normal messages, with the module name \enquote{\LaTeX{}}.
+% \begin{macrocode}
+ \@@_kernel_class_new:nN { warning } \msg_warning:nnxxxx
+ \@@_kernel_class_new:nN { info } \msg_info:nnxxxx
+% \end{macrocode}
+% \end{macro}
+%
+% End the group to eliminate \cs{@@_kernel_class_new:nN}.
+% \begin{macrocode}
+\group_end:
+% \end{macrocode}
+%
+% Error messages needed to actually implement the message system
+% itself.
+% \begin{macrocode}
+\__kernel_msg_new:nnnn { kernel } { message-already-defined }
+ { Message~'#2'~for~module~'#1'~already~defined. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~was~asked~to~define~a~new~message~called~'#2'\\
+ by~the~module~'#1':~this~message~already~exists.
+ \c_@@_return_text_tl
+ }
+\__kernel_msg_new:nnnn { kernel } { message-unknown }
+ { Unknown~message~'#2'~for~module~'#1'. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~was~asked~to~display~a~message~called~'#2'\\
+ by~the~module~'#1':~this~message~does~not~exist.
+ \c_@@_return_text_tl
+ }
+\__kernel_msg_new:nnnn { kernel } { message-class-unknown }
+ { Unknown~message~class~'#1'. }
+ {
+ LaTeX~has~been~asked~to~redirect~messages~to~a~class~'#1':\\
+ this~was~never~defined.
+ \c_@@_return_text_tl
+ }
+\__kernel_msg_new:nnnn { kernel } { message-redirect-loop }
+ {
+ Message~redirection~loop~caused~by~ {#1} ~=>~ {#2}
+ \tl_if_empty:nF {#3} { ~for~module~' \use_none:n #3 ' } .
+ }
+ {
+ Adding~the~message~redirection~ {#1} ~=>~ {#2}
+ \tl_if_empty:nF {#3} { ~for~the~module~' \use_none:n #3 ' } ~
+ created~an~infinite~loop\\\\
+ \iow_indent:n { #4 \\\\ }
+ }
+% \end{macrocode}
+%
+% Messages for earlier kernel modules plus a few for \pkg{l3keys} which
+% cover coding errors.
+% \begin{macrocode}
+\__kernel_msg_new:nnnn { kernel } { bad-number-of-arguments }
+ { Function~'#1'~cannot~be~defined~with~#2~arguments. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~define~a~function~'#1'~with~
+ #2~arguments.~
+ TeX~allows~between~0~and~9~arguments~for~a~single~function.
+ }
+\__kernel_msg_new:nnn { kernel } { char-active }
+ { Cannot~generate~active~chars. }
+\__kernel_msg_new:nnn { kernel } { char-invalid-catcode }
+ { Invalid~catcode~for~char~generation. }
+\__kernel_msg_new:nnn { kernel } { char-null-space }
+ { Cannot~generate~null~char~as~a~space. }
+\__kernel_msg_new:nnn { kernel } { char-out-of-range }
+ { Charcode~requested~out~of~engine~range. }
+\__kernel_msg_new:nnn { kernel } { char-space }
+ { Cannot~generate~space~chars. }
+\__kernel_msg_new:nnnn { kernel } { command-already-defined }
+ { Control~sequence~#1~already~defined. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~create~a~new~control~sequence~'#1'~
+ but~this~name~has~already~been~used~elsewhere. \\ \\
+ The~current~meaning~is:\\
+ \ \ #2
+ }
+\__kernel_msg_new:nnnn { kernel } { command-not-defined }
+ { Control~sequence~#1~undefined. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~use~a~control~sequence~'#1':\\
+ this~has~not~been~defined~yet.
+ }
+\__kernel_msg_new:nnnn { kernel } { empty-search-pattern }
+ { Empty~search~pattern. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~replace~an~empty~pattern~by~'#1':~that~
+ would~lead~to~an~infinite~loop!
+ }
+\__kernel_msg_new:nnnn { kernel } { out-of-registers }
+ { No~room~for~a~new~#1. }
+ {
+ TeX~only~supports~\int_use:N \c_max_register_int \ %
+ of~each~type.~All~the~#1~registers~have~been~used.~
+ This~run~will~be~aborted~now.
+ }
+\__kernel_msg_new:nnnn { kernel } { non-base-function }
+ { Function~'#1'~is~not~a~base~function }
+ {
+ \c_@@_coding_error_text_tl
+ Functions~defined~through~\iow_char:N\\cs_new:Nn~must~have~
+ a~signature~consisting~of~only~normal~arguments~'N'~and~'n'.~
+ To~define~variants~use~\iow_char:N\\cs_generate_variant:Nn~
+ and~to~define~other~functions~use~\iow_char:N\\cs_new:Npn.
+ }
+\__kernel_msg_new:nnnn { kernel } { missing-colon }
+ { Function~'#1'~contains~no~':'. }
+ {
+ \c_@@_coding_error_text_tl
+ Code-level~functions~must~contain~':'~to~separate~the~
+ argument~specification~from~the~function~name.~This~is~
+ needed~when~defining~conditionals~or~variants,~or~when~building~a~
+ parameter~text~from~the~number~of~arguments~of~the~function.
+ }
+\__kernel_msg_new:nnnn { kernel } { overflow }
+ { Integers~larger~than~2^{30}-1~cannot~be~stored~in~arrays. }
+ {
+ An~attempt~was~made~to~store~#3~
+ \tl_if_empty:nF {#2} { at~position~#2~ } in~the~array~'#1'.~
+ The~largest~allowed~value~#4~will~be~used~instead.
+ }
+\__kernel_msg_new:nnnn { kernel } { out-of-bounds }
+ { Access~to~an~entry~beyond~an~array's~bounds. }
+ {
+ An~attempt~was~made~to~access~or~store~data~at~position~#2~of~the~
+ array~'#1',~but~this~array~has~entries~at~positions~from~1~to~#3.
+ }
+\__kernel_msg_new:nnnn { kernel } { protected-predicate }
+ { Predicate~'#1'~must~be~expandable. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~define~'#1'~as~a~protected~predicate.~
+ Only~expandable~tests~can~have~a~predicate~version.
+ }
+\__kernel_msg_new:nnn { kernel } { randint-backward-range }
+ { Bounds~ordered~backwards~in~\iow_char:N\\int_rand:nn~{#1}~{#2}. }
+\__kernel_msg_new:nnnn { kernel } { conditional-form-unknown }
+ { Conditional~form~'#1'~for~function~'#2'~unknown. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~define~the~conditional~form~'#1'~of~
+ the~function~'#2',~but~only~'TF',~'T',~'F',~and~'p'~forms~exist.
+ }
+\__kernel_msg_new:nnnn { kernel } { key-no-property }
+ { No~property~given~in~definition~of~key~'#1'. }
+ {
+ \c_@@_coding_error_text_tl
+ Inside~\keys_define:nn each~key~name~
+ needs~a~property: \\ \\
+ \iow_indent:n { #1 .<property> } \\ \\
+ LaTeX~did~not~find~a~'.'~to~indicate~the~start~of~a~property.
+ }
+\__kernel_msg_new:nnnn { kernel } { key-property-boolean-values-only }
+ { The~property~'#1'~accepts~boolean~values~only. }
+ {
+ \c_@@_coding_error_text_tl
+ The~property~'#1'~only~accepts~the~values~'true'~and~'false'.
+ }
+\__kernel_msg_new:nnnn { kernel } { key-property-requires-value }
+ { The~property~'#1'~requires~a~value. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~was~asked~to~set~property~'#1'~for~key~'#2'.\\
+ No~value~was~given~for~the~property,~and~one~is~required.
+ }
+\__kernel_msg_new:nnnn { kernel } { key-property-unknown }
+ { The~key~property~'#1'~is~unknown. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~set~the~property~'#1'~for~key~'#2':~
+ this~property~is~not~defined.
+ }
+\__kernel_msg_new:nnnn { kernel } { scanmark-already-defined }
+ { Scan~mark~#1~already~defined. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~create~a~new~scan~mark~'#1'~
+ but~this~name~has~already~been~used~for~a~scan~mark.
+ }
+\__kernel_msg_new:nnnn { kernel } { variable-not-defined }
+ { Variable~#1~undefined. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~show~a~variable~#1,~but~this~has~not~
+ been~defined~yet.
+ }
+\__kernel_msg_new:nnnn { kernel } { variant-too-long }
+ { Variant~form~'#1'~longer~than~base~signature~of~'#2'. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~create~a~variant~of~the~function~'#2'~
+ with~a~signature~starting~with~'#1',~but~that~is~longer~than~
+ the~signature~(part~after~the~colon)~of~'#2'.
+ }
+\__kernel_msg_new:nnnn { kernel } { invalid-variant }
+ { Variant~form~'#1'~invalid~for~base~form~'#2'. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~create~a~variant~of~the~function~'#2'~
+ with~a~signature~starting~with~'#1',~but~cannot~change~an~argument~
+ from~type~'#3'~to~type~'#4'.
+ }
+\__kernel_msg_new:nnnn { kernel } { invalid-exp-args }
+ { Invalid~variant~specifier~'#1'~in~'#2'. }
+ {
+ \c_@@_coding_error_text_tl
+ LaTeX~has~been~asked~to~create~an~\iow_char:N\\exp_args:N...~
+ function~with~signature~'N#2'~but~'#1'~is~not~a~valid~argument~
+ specifier.
+ }
+\__kernel_msg_new:nnn { kernel } { deprecated-variant }
+ {
+ Variant~form~'#1'~deprecated~for~base~form~'#2'.~
+ One~should~not~change~an~argument~from~type~'#3'~to~type~'#4'
+ \str_case:nnF {#3}
+ {
+ { n } { :~use~a~'\token_if_eq_charcode:NNTF #4 c v V'~variant? }
+ { N } { :~base~form~only~accepts~a~single~token~argument. }
+ {#4} { :~base~form~is~already~a~variant. }
+ } { . }
+ }
+% \end{macrocode}
+%
+% Some errors are only needed in package mode if debugging is enabled by
+% one of the options \texttt{enable-debug}, \texttt{check-declarations},
+% \texttt{log-functions}, or on the contrary if debugging is turned off.
+% In format mode the error is somewhat different.
+% \begin{macrocode}
+%<*package>
+\__kernel_if_debug:TF
+ {
+ \__kernel_msg_new:nnnn { kernel } { debug }
+ { The~debugging~option~'#1'~does~not~exist~\msg_line_context:. }
+ {
+ The~functions~'\iow_char:N\\debug_on:n'~and~
+ '\iow_char:N\\debug_off:n'~only~accept~the~arguments~
+ 'check-declarations',~'deprecation',~'log-functions',~not~'#1'.
+ }
+ \__kernel_msg_new:nnn { kernel } { expr } { '#2'~in~#1 }
+ \__kernel_msg_new:nnnn { kernel } { local-global }
+ { Inconsistent~local/global~assignment }
+ {
+ \c_@@_coding_error_text_tl
+ \if:w l #2 Local
+ \else:
+ \if:w g #2 Global \else: Constant \fi:
+ \fi:
+ \ %
+ assignment~to~a~
+ \if:w l #1 local
+ \else:
+ \if:w g #1 global \else: constant \fi:
+ \fi:
+ \ %
+ variable~'#3'.
+ }
+ \__kernel_msg_new:nnnn { kernel } { non-declared-variable }
+ { The~variable~#1~has~not~been~declared~\msg_line_context:. }
+ {
+ \c_@@_coding_error_text_tl
+ Checking~is~active,~and~you~have~tried~do~so~something~like: \\
+ \ \ \tl_set:Nn ~ #1 ~ \{ ~ ... ~ \} \\
+ without~first~having: \\
+ \ \ \tl_new:N ~ #1 \\
+ \\
+ LaTeX~will~create~the~variable~and~continue.
+ }
+ }
+ {
+ \__kernel_msg_new:nnnn { kernel } { enable-debug }
+ { To~use~'#1'~load~expl3~with~the~'enable-debug'~option. }
+ {
+ The~function~'#1'~will~be~ignored~because~it~can~only~work~if~
+ some~internal~functions~in~expl3~have~been~appropriately~
+ defined.~This~only~happens~if~one~of~the~options~
+ 'enable-debug',~'check-declarations'~or~'log-functions'~was~
+ given~when~loading~expl3.
+ }
+ }
+%</package>
+%<*initex>
+\__kernel_msg_new:nnnn { kernel } { enable-debug }
+ { '#1'~cannot~be~used~in~format~mode. }
+ {
+ The~function~'#1'~will~be~ignored~because~it~can~only~work~if~
+ some~internal~functions~in~expl3~have~been~appropriately~
+ defined.~This~only~happens~in~package~mode~(and~only~if~one~of~
+ the~options~'enable-debug',~'check-declarations'~or~'log-functions'~
+ was~given~when~loading~expl3.
+ }
+%</initex>
+% \end{macrocode}
+%
+% Some errors only appear in expandable settings,
+% hence don't need a \enquote{more-text} argument.
+% \begin{macrocode}
+\__kernel_msg_new:nnn { kernel } { bad-exp-end-f }
+ { Misused~\exp_end_continue_f:w or~:nw }
+\__kernel_msg_new:nnn { kernel } { bad-variable }
+ { Erroneous~variable~#1 used! }
+\__kernel_msg_new:nnn { kernel } { misused-sequence }
+ { A~sequence~was~misused. }
+\__kernel_msg_new:nnn { kernel } { misused-prop }
+ { A~property~list~was~misused. }
+\__kernel_msg_new:nnn { kernel } { negative-replication }
+ { Negative~argument~for~\iow_char:N\\prg_replicate:nn. }
+\__kernel_msg_new:nnn { kernel } { prop-keyval }
+ { Missing/extra~'='~in~'#1'~(in~'..._keyval:Nn') }
+\__kernel_msg_new:nnn { kernel } { unknown-comparison }
+ { Relation~'#1'~unknown:~use~=,~<,~>,~==,~!=,~<=,~>=. }
+\__kernel_msg_new:nnn { kernel } { zero-step }
+ { Zero~step~size~for~step~function~#1. }
+\cs_if_exist:NF \tex_expanded:D
+ {
+ \__kernel_msg_new:nnn { kernel } { e-type }
+ { #1 ~ in~e-type~argument }
+ }
+% \end{macrocode}
+%
+% Messages used by the \enquote{\texttt{show}} functions.
+% \begin{macrocode}
+\__kernel_msg_new:nnn { kernel } { show-clist }
+ {
+ The~comma~list~ \tl_if_empty:nF {#1} { #1 ~ }
+ \tl_if_empty:nTF {#2}
+ { is~empty \\>~ . }
+ { contains~the~items~(without~outer~braces): #2 . }
+ }
+\__kernel_msg_new:nnn { kernel } { show-intarray }
+ { The~integer~array~#1~contains~#2~items: \\ #3 . }
+\__kernel_msg_new:nnn { kernel } { show-prop }
+ {
+ The~property~list~#1~
+ \tl_if_empty:nTF {#2}
+ { is~empty \\>~ . }
+ { contains~the~pairs~(without~outer~braces): #2 . }
+ }
+\__kernel_msg_new:nnn { kernel } { show-seq }
+ {
+ The~sequence~#1~
+ \tl_if_empty:nTF {#2}
+ { is~empty \\>~ . }
+ { contains~the~items~(without~outer~braces): #2 . }
+ }
+\__kernel_msg_new:nnn { kernel } { show-streams }
+ {
+ \tl_if_empty:nTF {#2} { No~ } { The~following~ }
+ \str_case:nn {#1}
+ {
+ { ior } { input ~ }
+ { iow } { output ~ }
+ }
+ streams~are~
+ \tl_if_empty:nTF {#2} { open } { in~use: #2 . }
+ }
+% \end{macrocode}
+%
+% \subsection{Expandable errors}
+%
+% \begin{macro}{\@@_expandable_error:n}
+% \begin{macro}{\@@_expandable_error:w}
+% In expansion only context, we cannot use the normal means of
+% reporting errors. Instead, we feed \TeX{} an undefined control
+% sequence, \cs{LaTeX3 error:}. It is thus interrupted, and shows
+% the context, which thanks to the odd-looking \cs{use:n} is
+% \begin{verbatim}
+% <argument> \LaTeX3 error:
+% The error message.
+% \end{verbatim}
+% In other words, \TeX{} is processing the argument of \cs{use:n},
+% which is \cs{LaTeX3 error:} \meta{error message}.
+% Then \cs{@@_expandable_error:w} cleans up. In fact, there
+% is an extra subtlety: if the user inserts tokens for error recovery,
+% they should be kept. Thus we also use an odd space character
+% (with category code $7$) and keep tokens until that space character,
+% dropping everything else until \cs{q_stop}. The \cs{exp_end:} prevents
+% losing braces around the user-inserted text if any, and stops the
+% expansion of \cs{exp:w}. The group is used to prevent
+% |\LaTeX3~error:| from being globally equal to \cs{scan_stop:}.
+% \begin{macrocode}
+\group_begin:
+\cs_set_protected:Npn \@@_tmp:w #1#2
+ {
+ \cs_new:Npn \@@_expandable_error:n ##1
+ {
+ \exp:w
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \@@_expandable_error:w
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \exp_end:
+ \use:n { #1 #2 ##1 } #2
+ }
+ \cs_new:Npn \@@_expandable_error:w ##1 #2 ##2 #2 {##1}
+ }
+\exp_args:Ncx \@@_tmp:w { LaTeX3~error: }
+ { \char_generate:nn { `\ } { 7 } }
+\group_end:
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \__kernel_msg_expandable_error:nnnnnn,
+% \__kernel_msg_expandable_error:nnnnn,
+% \__kernel_msg_expandable_error:nnnn,
+% \__kernel_msg_expandable_error:nnn,
+% \__kernel_msg_expandable_error:nn,
+% \__kernel_msg_expandable_error:nnffff,
+% \__kernel_msg_expandable_error:nnfff,
+% \__kernel_msg_expandable_error:nnff,
+% \__kernel_msg_expandable_error:nnf,
+% }
+% The command built from the csname
+% \cs{c_@@_text_prefix_tl} |LaTeX / #1 / #2|
+% takes four arguments and builds the error text, which is fed to
+% \cs{@@_expandable_error:n} with appropriate expansion: just as for
+% usual messages the arguments are first turned to strings, then the
+% message is fully expanded.
+% \begin{macrocode}
+\exp_args_generate:n { oooo }
+\cs_new:Npn \__kernel_msg_expandable_error:nnnnnn #1#2#3#4#5#6
+ {
+ \exp_args:Ne \@@_expandable_error:n
+ {
+ \exp_args:Nc \exp_args:Noooo
+ { \c_@@_text_prefix_tl LaTeX / #1 / #2 }
+ { \tl_to_str:n {#3} }
+ { \tl_to_str:n {#4} }
+ { \tl_to_str:n {#5} }
+ { \tl_to_str:n {#6} }
+ }
+ }
+\cs_new:Npn \__kernel_msg_expandable_error:nnnnn #1#2#3#4#5
+ {
+ \__kernel_msg_expandable_error:nnnnnn
+ {#1} {#2} {#3} {#4} {#5} { }
+ }
+\cs_new:Npn \__kernel_msg_expandable_error:nnnn #1#2#3#4
+ {
+ \__kernel_msg_expandable_error:nnnnnn
+ {#1} {#2} {#3} {#4} { } { }
+ }
+\cs_new:Npn \__kernel_msg_expandable_error:nnn #1#2#3
+ {
+ \__kernel_msg_expandable_error:nnnnnn
+ {#1} {#2} {#3} { } { } { }
+ }
+\cs_new:Npn \__kernel_msg_expandable_error:nn #1#2
+ {
+ \__kernel_msg_expandable_error:nnnnnn
+ {#1} {#2} { } { } { } { }
+ }
+\cs_generate_variant:Nn \__kernel_msg_expandable_error:nnnnnn { nnffff }
+\cs_generate_variant:Nn \__kernel_msg_expandable_error:nnnnn { nnfff }
+\cs_generate_variant:Nn \__kernel_msg_expandable_error:nnnn { nnff }
+\cs_generate_variant:Nn \__kernel_msg_expandable_error:nnn { nnf }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex