diff options
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3msg.dtx')
-rw-r--r-- | macros/latex/contrib/l3kernel/l3msg.dtx | 2097 |
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 |