% \iffalse
%% File: l3msg.dtx Copyright (C) 2009 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
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the ``expl3 bundle'' (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%% 
%
%<*driver|package>
\RequirePackage{l3names}
%</driver|package>
%\fi
\GetIdInfo$Id: l3msg.dtx 2052 2010-10-02 16:04:38Z will $
  {L3 Experimental LaTeX Messages module}
%\iffalse
%<*driver>
%\fi
\ProvidesFile{\filename.\filenameext}
  [\filedate\space v\fileversion\space\filedescription]
%\iffalse
\documentclass[full]{l3doc}
\begin{document}
\DocInput{l3msg.dtx}
\end{document}
%</driver>
% \fi
%
% \title{The \textsf{l3msg} package\thanks{This file
%         has version number \fileversion, last
%         revised \filedate.}\\
% Communicating with the user}
% \author{\Team}
% \date{\filedate}
% \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 
% 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. Inside the 
% message text, spaces are \emph{not} ignored. A space where \TeX\ 
% would normally gobble one can be created using |\ |, and a new line
% with |\\|. New lines may have `continuation' text added by the 
% output system.
% 
%\begin{function}{
%  \msg_new:nnnn |
%  \msg_new:nnn  |
%  \msg_set:nnnn |
%  \msg_set:nnn
%}
%  \begin{syntax}
%    "\msg_new:nnnn" \marg{module} \marg{message} \marg{text} 
%    ~~~~\marg{more text} 
%  \end{syntax}
%  Creates new <message> for <module> to produce <text> initially
%  and <more text> if requested by the user. <text> and <more text> can 
%  use up to four macro parameters (|#1| to |#4|), which are supplied by
%  the message system.  At the point where <message> is printed, the 
%  material supplied for |#1| to |#4| will be subject to an x-type 
%  expansion.
%  
%  An error will be raised by the \texttt{new} functions if the 
%  message already exists: the \texttt{set} functions do not 
%  carry any checking. For messages defined using
%  \cs{msg_new:nnn} or \cs{msg_set:nnn} \LaTeX3 will supply a 
%  standard <more text> at the point the message is used, if this
%  is required.
%\end{function}
%
%\section{Message classes}
% 
% Creating message output requires the message to be given a class.
%
%\begin{function}{
%  \msg_class_new:nn |
%  \msg_class_set:nn
%}
%  \begin{syntax}
%    "\msg_class_new:nn" \marg{class} \marg{code}
%  \end{syntax}
%  Creates new <class> to output a message, using <code> to process
%  the message text. The <class> should be a text value, while
%  the <code> may be any arbitrary material.
%\end{function}
%
% The module defines several common message classes. The following 
% describes the standard behaviour of each class if no redirection of 
% the class or message is active. In all cases, the message may be
% issued supplying \(0\) to \(4\) arguments. The code will
% ensure that there an no errors if the number of arguments supplied
% here does not match the number in the definition of the message
% (although of course the sense of the message may be impaired).
%
%\begin{function}{
%  \msg_fatal:nnxxxx |
%  \msg_fatal:nnxxx  |
%  \msg_fatal:nnxx   |
%  \msg_fatal:nnx    |
%  \msg_fatal:nn
%}
%  \begin{syntax}
%    "\msg_fatal:nnxxxx" \marg{module} \marg{name} \marg{arg one}
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Issues <module> error message <name>, passing <arg one> to 
%  <arg four> to the text-creating functions. After issuing a 
%  fatal error the \TeX\ run will halt. 
%\end{function}
%
%\begin{function}{
%  \msg_error:nnxxxx |
%  \msg_error:nnxxx  |
%  \msg_error:nnxx   |
%  \msg_error:nnx    |
%  \msg_error:nn
%}
%  \begin{syntax}
%    "\msg_error:nnxxxx" \marg{module} \marg{name} \marg{arg one}
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Issues <module> error message <name>, passing <arg one> to 
%  <arg four> to the text-creating functions. 
%  \begin{texnote}
%    The standard output here is similar to \cs{PackageError}.
%  \end{texnote}
%\end{function}
%
%\begin{function}{
%  \msg_warning:nnxxxx |
%  \msg_warning:nnxxx  |
%  \msg_warning:nnxx   |
%  \msg_warning:nnx    |
%  \msg_warning:nn
%}
%  \begin{syntax}
%    "\msg_warning:nnxxxx" \marg{module} \marg{name} \marg{arg one}
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Prints <module> message <name> to the terminal, passing <arg one> to
%  <arg four> to the text-creating functions. 
%  \begin{texnote}
%    The standard output here is similar to \cs{PackageWarningNoLine}.
%  \end{texnote}
%\end{function}
%
%\begin{function}{
%  \msg_info:nnxxxx |
%  \msg_info:nnxxx  |
%  \msg_info:nnxx   |
%  \msg_info:nnx    |
%  \msg_info:nn
%}
%  \begin{syntax}
%    "\msg_info:nnxxxx" \marg{module} \marg{name} \marg{arg one}
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Prints <module> message <name> to the log, passing <arg one> to
%  <arg four> to the text-creating functions. 
%  \begin{texnote}
%    The standard output here is similar to \cs{PackageInfoNoLine}.
%  \end{texnote}
%\end{function}
%
%\begin{function}{
%  \msg_log:nnxxxx|
%  \msg_log:nnxxx|
%  \msg_log:nnxx|
%  \msg_log:nnx|
%  \msg_log:nn
%}
%  \begin{syntax}
%    "\msg_log:nnxxxx" \marg{module} \marg{name} \marg{arg one}
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Prints <module> message <name> to the log, passing <arg one> to
%  <arg four> to the text-creating functions. No continuation text is
%  added.
%\end{function}
%
%\begin{function}{
%  \msg_trace:nnxxxx|
%  \msg_trace:nnxxx|
%  \msg_trace:nnxx|
%  \msg_trace:nnx|
%  \msg_trace:nn
%}
%  \begin{syntax}
%    "\msg_trace:nnxxxx" \marg{module} \marg{name} \marg{arg one}
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Prints <module> message <name> to the log, passing <arg one> to
%  <arg four> to the text-creating functions. No continuation text is
%  added.
%\end{function}
%
%\begin{function}{
%  \msg_none:nnxxxx|
%  \msg_none:nnxxx|
%  \msg_none:nnxx|
%  \msg_none:nnx|
%  \msg_none:nn
%}
%  \begin{syntax}
%    "\msg_none:nnxxxx" \marg{module} \marg{name} \marg{arg one}
%      ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Does nothing: used for redirecting other message classes. Gobbles 
%  arguments given. 
%\end{function}
% 
% \section{Redirecting messages}
%
%\begin{function}{\msg_redirect_class:nn}
%  \begin{syntax}
%    "\msg_redirect_class:nn" \marg{class one} \marg{class two}
%  \end{syntax}
%  Changes the behaviour of messages of <class one> so that they
%  are processed using the code for those of <class two>. Multiple
%  redirections are possible. Redirection to a missing class or
%  infinite loops will raise errors when the messages are used,
%  rather than at the point of redirection.
%\end{function}
%
%\begin{function}{\msg_redirect_module:nnn}
%  \begin{syntax}
%    "\msg_redirect_module:nnn" \marg{module} \marg{class one}
%      \marg{class two}
%  \end{syntax}
%  Redirects message of <class one> for <module> to act as though
%  they were from <class two>. Messages of <class one> from 
%  sources other than <module> are not affected by this redirection. 
%  \begin{texnote}
%    This function can be used to make some messages `silent' by
%    default. For example, all of the \texttt{trace} messages of
%    <module> could be turned off with: 
%    \begin{verbatim}
%    \msg_redirect_module:nnn { module } { trace } { none }
%    \end{verbatim}
%  \end{texnote}
%\end{function}
%
%\begin{function}{\msg_redirect_name:nnn}
%  \begin{syntax}
%    "\msg_redirect_name:nnn" \marg{module} \marg{message} \marg{class}
%  \end{syntax}
%  Redirects a specific <message> from a specific <module> to act
%  as a member of <class> of messages.
%  \begin{texnote}
%    This function can be used to make a selected message `silent'
%    without changing global parameters:
%    \begin{verbatim}
%    \msg_redirect_name:nnn { module } { annoying-message } { none }
%    \end{verbatim}
%  \end{texnote}
%\end{function}
%
% \section{Support functions for output}
% 
%\begin{function}{\msg_line_context:}
%  \begin{syntax}
%    "\msg_line_context:" 
%  \end{syntax}
%  Prints the text specified in \cs{c_msg_on_line_tl} followed by
%  the current line in the current input file.
%  \begin{texnote}
%    This is similar to the text added to messages by \LaTeXe's
%    \cs{PackageWarning} and \cs{PackageInfo}.
%  \end{texnote}
%\end{function}
% 
%\begin{function}{\msg_line_number:}
%  \begin{syntax}
%    "\msg_line_number:" 
%  \end{syntax}
%  Prints the current line number in the current input file.
%\end{function}
% 
%\begin{function}{
%  \msg_newline:     |
%  \msg_two_newlines:
%}
%  \begin{syntax}
%    "\msg_newline:" 
%  \end{syntax}
%  Print one or two newlines with no continuation information.  
%\end{function}
%
% \section{Low-level functions}
% 
% The low-level functions do not make assumptions about module names.
% The output functions here produce messages directly, and do not 
% respond to redirection.
% 
%\begin{function}{
%  \msg_generic_new:nnn |
%  \msg_generic_new:nn  |
%  \msg_generic_set:nnn |
%  \msg_generic_set:nn
%}
%  \begin{syntax}
%    "\msg_generic_new:nnn"  \marg{name} \marg{text} \marg{more text} 
%  \end{syntax}
%  Creates new message <name> to produce <text> initially and 
%  <more text> if requested by the user. <text> and <more text>  can use
%  up to four macro parameters ("#1" to "#4"), which are supplied by the
%  message system. Inside <text> and <more text> spaces are not ignored.
%\end{function}
%
%\begin{function}{\msg_direct_interrupt:xxxxx}
%  \begin{syntax}
%    "\msg_direct_interrupt:xxxxx"  \marg{first line} \marg{text} 
%    ~~~~\marg{continuation} \marg{last line} \marg{more text}
%  \end{syntax}
%  Executes a \TeX\ error, interrupting compilation. The <first line> 
%  is displayed followed by <text> and the input prompt. <more text> is
%  displays if requested by the user. If <more text> is blank a default
%  is supplied. Each line of <text> (broken with "\\") begins with 
%  <continuation> and finishes off with <last line>.
%  <last line> has a period appended to it; do not add one yourself.
%\end{function}
%
%\begin{function}{
%  \msg_direct_log:xx|
%  \msg_direct_term:xx
%}
%  \begin{syntax}
%    "\msg_direct_log:xx"  \marg{text} \marg{continuation}
%  \end{syntax}
%  Prints <text> to either the log or terminal. New lines (broken 
%  with "\\") start with <continuation>. 
%\end{function}
%
% \section{Kernel-specific functions}
% 
%\begin{function}{
%  \msg_kernel_new:nnnn |
%  \msg_kernel_new:nnn  |
%  \msg_kernel_set:nnnn |
%  \msg_kernel_set:nnn
%}
%  \begin{syntax}
%    "\msg_kernel_new:nnnn" \marg{divsion} \marg{name} \marg{text} 
%     ~~~~\marg{more text}
%  \end{syntax}
%  Creates new kernel message <name> to produce <text> initially and 
%  <more text> if requested by the user. <text> and <more text> can use
%  up to four macro parameters ("#1" to "#4"), which are supplied by the 
%  message system. Kernel messages are divided into <divisions>, roughly
%  equivalent to the \LaTeXe\ package names used.
%\end{function}
%
%\begin{function}{
%  \msg_kernel_fatal:nnxxxx |
%  \msg_kernel_fatal:nnxxx  |
%  \msg_kernel_fatal:nnxx   |
%  \msg_kernel_fatal:nnx    |
%  \msg_kernel_fatal:nn
%}
%  \begin{syntax}
%    "\msg_kernel_fatal:nnxx" \marg{division} \marg{name} \marg{arg one} 
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Issues kernel error message <name> for <division>, passing <arg one>
%  to <arg four> to the text-creating functions. The \TeX\ run then 
%  halts.  Cannot be redirected.
%\end{function}
%
%\begin{function}{
%  \msg_kernel_error:nnxxxx |
%  \msg_kernel_error:nnxxx  |
%  \msg_kernel_error:nnxx   |  
%  \msg_kernel_error:nnx    |
%  \msg_kernel_error:nn
%}
%  \begin{syntax}
%    "\msg_kernel_error:nnxx" \marg{division} \marg{name} \marg{arg one} 
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Issues kernel error message <name> for <division>, passing <arg one> 
%  to <arg four> to the text-creating functions. Cannot be redirected.
%\end{function}
%
%\begin{function}{
%  \msg_kernel_warning:nnxxxx |
%  \msg_kernel_warning:nnxxx  |
%  \msg_kernel_warning:nnxx   |
%  \msg_kernel_warning:nnx    |
%  \msg_kernel_warning:nn
%}
%  \begin{syntax}
%    "\msg_kernel_warning:nnxx" \marg{division} \marg{name} \marg{arg one} 
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Prints kernel message <name> for <division> to the terminal, passing 
%  <arg one> to <arg four> to the text-creating functions. 
%\end{function}
%
%\begin{function}{
%  \msg_kernel_info:nnxxxx |
%  \msg_kernel_info:nnxxx  |
%  \msg_kernel_info:nnxx   |
%  \msg_kernel_info:nnx    |
%  \msg_kernel_info:nn
%}
%  \begin{syntax}
%    "\msg_kernel_info:nxx" \marg{division} \marg{name} \marg{arg one} 
%     ~~~~\marg{arg two} \marg{arg three} \marg{arg four}
%  \end{syntax}
%  Prints kernel message <name> for <division> to the log, passing 
%  <arg one> to <arg four> to the text-creating functions. 
%\end{function}
%
%\begin{function}{\msg_kernel_bug:x}
%  \begin{syntax}
%    "\msg_kernel_bug:x" \marg{text}
%  \end{syntax}
%  Short-cut for `This is a LaTeX bug: check coding' errors.
%\end{function}
%
% \begin{function}{\msg_fatal_text:n}
% \begin{syntax}
%   "\msg_fatal_text:n" \marg{package}
% \end{syntax}
% Prints `Fatal <package> error' for use in error messages.
% \end{function}
%
% 
% \section{Variables and constants}
% 
%\begin{variable}{
%  \c_msg_error_tl   |
%  \c_msg_warning_tl |
%  \c_msg_info_tl
%}
%  Simple headers for errors. Although these are marked as constants,
%  they could be changed for printing errors in a different language.
%\end{variable}
% 
%\begin{variable}{
%  \c_msg_coding_error_text_tl    |
%  \c_msg_fatal_text_tl           |
%  \c_msg_help_text_tl            |
%  \c_msg_kernel_bug_text_tl      |
%  \c_msg_kernel_bug_more_text_tl |
%  \c_msg_no_info_text_tl         |
%  \c_msg_return_text_tl
%}
%  Various pieces of text for use in messages, which are not changed by
%  the code here although they could be to alter the language. Although 
%  these are marked as constants, they could be changed for printing
%  errors in a different language.
%\end{variable}
%
%\begin{variable}{\c_msg_on_line_tl}
%  The `on line' phrase for line numbers. Although marked as a constant,
%  they could be changed for printing errors in a different language.
%\end{variable}
%
%\begin{variable}{
%  \c_msg_text_prefix_tl      |
%  \c_msg_more_text_prefix_tl
%}
%  Header information for storing the `paths' to parts of a message.
%  Although these are marked as constants, they could be changed for 
%  printing errors in a different language.
%\end{variable}
%
%\begin{variable}{
%  \l_msg_class_tl         |
%  \l_msg_current_class_tl |
%  \l_msg_current_module_tl
%}
%  Information about message method, used for filtering.
%\end{variable}
%
%\begin{variable}{\l_msg_names_clist}
%  List of all of the message names defined.
%\end{variable}
%
%\begin{variable}{
%  \l_msg_redirect_classes_prop |
%  \l_msg_redirect_names_prop
%}
%  Re-direction lists containing the class of message to convert an 
%  different one.
%\end{variable}
%
%\begin{variable}{\l_msg_redirect_classes_clist}
%  List so that filtering does not loop.
%\end{variable}
% 
% \end{documentation}
% 
% \begin{implementation}
%
% \section{\pkg{l3msg} implementation}
%
% The usual lead-off.
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage
  {\filename}{\filedate}{\fileversion}{\filedescription}
\package_check_loaded_expl:
%</package>
%<*initex|package>
%    \end{macrocode}
%    
% \LaTeX\ is handling context, so the \TeX\ ``noise'' is turned down.
%    \begin{macrocode}
\int_set:Nn \tex_errorcontextlines:D { \c_minus_one }
%    \end{macrocode}
%    
% \subsection{Variables and constants}
%    
%\begin{macro}{\c_msg_error_tl}
%\begin{macro}{\c_msg_warning_tl}
%\begin{macro}{\c_msg_info_tl}
% Header information.
%    \begin{macrocode}
\tl_const:Nn \c_msg_error_tl   { error }
\tl_const:Nn \c_msg_warning_tl { warning }
\tl_const:Nn \c_msg_info_tl    { info }
%    \end{macrocode}
%\end{macro}    
%\end{macro} 
%\end{macro}
%
%
% \begin{macro}{\msg_fatal_text:n,\msg_see_documentation_text:n}
% Contextual header/footer information.
%    \begin{macrocode}
\cs_new:Npn \msg_fatal_text:n #1 { Fatal~#1~error }
\cs_new:Npn \msg_see_documentation_text:n #1
  { See~the~#1~documentation~for~further~information }
%    \end{macrocode}
% \end{macro}
%
%    
%\begin{macro}{\c_msg_coding_error_text_tl}
%\begin{macro}{\c_msg_fatal_text_tl}
%\begin{macro}{\c_msg_help_text_tl}
%\begin{macro}{\c_msg_kernel_bug_text_tl}
%\begin{macro}{\c_msg_kernel_bug_more_text_tl}
%\begin{macro}{\c_msg_no_info_text_tl}
%\begin{macro}{\c_msg_return_text_tl}
% Simple pieces of text for messages.
%    \begin{macrocode}
\tl_const:Nn \c_msg_coding_error_text_tl {
  This~is~a~coding~error.
  \msg_two_newlines:
}
\tl_const:Nn \c_msg_fatal_text_tl {
  This~is~a~fatal~error:~LaTeX~will~abort
}
\tl_const:Nn \c_msg_help_text_tl {
  For~immediate~help~type~H~<return>
}
\tl_const:Nn \c_msg_kernel_bug_text_tl {
  This~is~a~LaTeX~bug:~check~coding!
}
\tl_const:Nn \c_msg_kernel_bug_more_text_tl {
  There~is~a~coding~bug~somewhere~around~here. \\
  This~probably~needs~examining~by~an~expert.
  \c_msg_return_text_tl
}
\tl_const:Nn \c_msg_no_info_text_tl {
  LaTeX~does~not~know~anything~more~about~this~error,~sorry.
  \c_msg_return_text_tl
}
\tl_const:Nn \c_msg_return_text_tl {
  \\ \\
  Try~typing~<return>~to~proceed.
  \\
  If~that~doesn't~work,~type~X~<return>~to~quit
}
%    \end{macrocode}
%\end{macro}    
%\end{macro}
%\end{macro}
%\end{macro} 
%\end{macro} 
%\end{macro} 
%\end{macro} 
%
%\begin{macro}[aux]{\c_msg_hide_tl<spaces>}
% An empty variable with a number of (category code 11) periods at the
% end of its name. This is used to push the \TeX\ part of an error
% message ``off the screen''.
%    \begin{macrocode}
\group_begin:
\char_make_letter:N \.
\tl_to_lowercase:n {
  \group_end:
  \tl_const:Nn \c_msg_hide_tl................................................
    {}
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\c_msg_on_line_tl}
% Text for ``on line''.
%    \begin{macrocode}
\tl_const:Nn \c_msg_on_line_tl { on~line }
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\c_msg_text_prefix_tl}
%\begin{macro}{\c_msg_more_text_prefix_tl}
% Prefixes for storage areas.
%    \begin{macrocode}
\tl_const:Nn \c_msg_text_prefix_tl      { msg_text ~>~ }
\tl_const:Nn \c_msg_more_text_prefix_tl { msg_text_more ~>~ }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\l_msg_class_tl}
%\begin{macro}{\l_msg_current_class_tl}
%\begin{macro}{\l_msg_current_module_tl}
% For holding the current message method and that for redirection.
%    \begin{macrocode}
\tl_new:N \l_msg_class_tl
\tl_new:N \l_msg_current_class_tl
\tl_new:N \l_msg_current_module_tl
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\l_msg_names_clist}
% Lists used for filtering.
%    \begin{macrocode}
\clist_new:N \l_msg_names_clist
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\l_msg_redirect_classes_prop}
%\begin{macro}{\l_msg_redirect_names_prop}
% For filtering messages, a list of all messages and of those which have
% to be modified is required.
%    \begin{macrocode}
\prop_new:N \l_msg_redirect_classes_prop
\prop_new:N \l_msg_redirect_names_prop
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\begin{macro}{\l_msg_redirect_classes_clist}
% To prevent an infinite loop.
%    \begin{macrocode}
\clist_new:N \l_msg_redirect_classes_clist
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\l_msg_tmp_tl}
% A scratch variable.
%    \begin{macrocode}
\tl_new:N \l_msg_tmp_tl
%    \end{macrocode}
%\end{macro}
%
% \subsection{Output helper functions}
%
%\begin{macro}{\msg_line_number:}
%\begin{macro}{\msg_line_context:}
% For writing the line number nicely.
%    \begin{macrocode}
\cs_new_nopar:Npn \msg_line_number: {
  \toks_use:N \tex_inputlineno:D
}
\cs_new_nopar:Npn \msg_line_context: {
  \c_msg_on_line_tl
  \c_space_tl
  \msg_line_number:
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_newline:}
%\begin{macro}{\msg_two_newlines:}
% Always forces a new line.
%    \begin{macrocode}
\cs_new_nopar:Npn \msg_newline:      { ^^J }
\cs_new_nopar:Npn \msg_two_newlines: { ^^J ^^J }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\subsection{Generic functions}
%
% The lowest level functions make no assumptions about modules, 
% \emph{etc.}
%
%\begin{macro}{\msg_generic_new:nnn}
%\begin{macro}{\msg_generic_new:nn}
% Creating a new message is basically the same as the non-checking
% version, and so after a check everything hands over.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_generic_new:nnn #1 {  
  \chk_if_free_cs:c { \c_msg_text_prefix_tl #1 :xxxx }
  \msg_generic_set:nnn {#1}
}
\cs_new_protected_nopar:Npn \msg_generic_new:nn #1 {  
  \chk_if_free_cs:c { \c_msg_text_prefix_tl #1 :xxxx }
  \msg_generic_set:nn {#1}
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_generic_set:nnn}
%\begin{macro}{\msg_generic_set:nn}
%\begin{macro}[aux]{\msg_generic_set_clist:n}
% Creating a message is quite simple. There must be a short text part,
% while the longer text may or may not be available.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_generic_set:nnn #1#2#3 { 
  \msg_generic_set_clist:n {#1}  
  \cs_set:cpn { \c_msg_text_prefix_tl #1 :xxxx } ##1##2##3##4 {#2}
  \cs_set:cpn { \c_msg_more_text_prefix_tl #1 :xxxx } ##1##2##3##4 {#3}
}
\cs_new_protected_nopar:Npn \msg_generic_set:nn #1#2 {  
  \msg_generic_set_clist:n {#1}  
  \cs_set:cpn { \c_msg_text_prefix_tl #1 :xxxx } ##1##2##3##4 {#2}
  \cs_set_eq:cN { \c_msg_more_text_prefix_tl #1 :xxxx } \c_undefined
}
\cs_new_protected_nopar:Npn \msg_generic_set_clist:n #1 {
  \clist_if_in:NnF \l_msg_names_clist { // #1 / } {
    \clist_put_right:Nn \l_msg_names_clist { // #1 / }
  }  
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_direct_interrupt:xxxxx}
%\begin{macro}[aux]{\msg_direct_interrupt:n}
% The low-level interruption macro is rather opaque, unfortunately. The 
% idea here is to create a a message which hides all of \TeX's own 
% information by filling the output up with dots. To achieve this,
% dots have to be letters. The odd
% \cs{c_msg_hide_tl<dots>} actually does the hiding: it is the
% large run of dots in the name that is important here. The meaning
% of "\\" is altered so that the explanation text is a simple run 
% whilst the initial error has line-continuation shown.
%    \begin{macrocode}
\group_begin:
  \char_set_lccode:nn {`\&} {`\ } % {
  \char_set_lccode:w `\} = `\ \scan_stop:
  \char_set_lccode:w `\& = `\!\scan_stop:
  \char_make_active:N \&
  \char_make_letter:N \.
\tl_to_lowercase:n{
  \group_end:
  \cs_new_protected:Npn \msg_direct_interrupt:xxxxx #1#2#3#4#5 {
    \group_begin:
      \cs_set_nopar:Npn \\ {\msg_newline:}
      \cs_set_eq:NN \  \c_space_tl
      \tl_set:Nx \l_tmpa_tl {#5}
      \tl_set:Nx \l_tmpb_tl {\c_msg_no_info_text_tl}
      \msg_direct_interrupt_aux:n {#5}
      \tex_errhelp:D \l_msg_tmp_tl
      \cs_set_nopar:Npn \\ {\msg_newline: !~#3}
      \iow_term:x
        {\msg_newline: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
      \cs_set:Npn & {
        \tex_errmessage:D{
          \\ #1 \\ \\ #2 \\ \\ #4
          \tl_if_eq:NNF \l_tmpa_tl \l_tmpb_tl
            { . \\ \c_msg_help_text_tl }
          \c_msg_hide_tl................................................
          }
        }
      &
    \group_end:
  }
}
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new_protected:Npn \msg_direct_interrupt_aux:n #1 {
  \cs_set_nopar:Npn \\ {\msg_newline: |~}
  \tl_if_empty:nTF {#1} {
    \tl_set:Nx \l_msg_tmp_tl { { \c_msg_no_info_text_tl } }
  }{
    \tl_set:Nx \l_msg_tmp_tl { {
      |'''''''''''''''''''''''''''''''''''''''''''''''\\
      #1^^J
      |...............................................^^J
    } }
  }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_direct_log:xx}
%\begin{macro}{\msg_direct_term:xx}
% Printing to the log or terminal without a stop is rather easier.
%    \begin{macrocode}
\cs_new_protected:Npn \msg_direct_log:xx #1#2 {
  \group_begin:
    \cs_set:Npn \\ { \msg_newline: #2 }
    \cs_set_eq:NN \ \c_space_tl
    \iow_log:x { #1 \msg_newline: }
  \group_end:
}
\cs_new_protected:Npn \msg_direct_term:xx #1#2 {
  \group_begin:
    \cs_set:Npn \\ { \msg_newline: #2 }
    \cs_set_eq:NN \ \c_space_tl
    \iow_term:x { #1 \msg_newline: }
  \group_end:
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\subsection{General functions}
%
% The main functions for messaging are built around the separation of
% module from the message name. These have short names as they will be
% widely used.
% 
%\begin{macro}{\msg_new:nnnn}
%\begin{macro}{\msg_new:nnn}
%\begin{macro}{\msg_set:nnnn}
%\begin{macro}{\msg_set:nnn}
% For making messages: all aliases.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_new:nnnn #1#2 {
  \msg_generic_new:nnn { #1 / #2 } 
}
\cs_new_protected_nopar:Npn \msg_new:nnn #1#2 {
  \msg_generic_new:nn { #1 / #2 } 
}
\cs_new_protected_nopar:Npn \msg_set:nnnn #1#2 {
  \msg_generic_set:nnn { #1 / #2 }
}
\cs_new_protected_nopar:Npn \msg_set:nnn #1#2 {
  \msg_generic_set:nn { #1 / #2 } 
}
%    \end{macrocode}
%\end{macro}
%\end{macro} 
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_class_new:nn}
%\begin{macro}{\msg_class_set:nn}
% Creating a new class produces three new functions, with varying 
% numbers of arguments. The \cs{msg_class_loop:n} function is set up
% so that redirection will work as desired.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_class_new:nn #1 {
  \chk_if_free_cs:c { msg_ #1 :nnxxxx }
  \prop_new:c { l_msg_redirect_ #1 _prop }
  \msg_class_set:nn {#1}
}
\cs_new_protected_nopar:Npn \msg_class_set:nn #1#2 {
  \prop_clear:c { l_msg_redirect_ #1 _prop }
  \cs_set_protected:cpn { msg_ #1 :nnxxxx } ##1##2##3##4##5##6 {
    \msg_use:nnnnxxxx {#1} {#2} {##1} {##2} {##3} {##4} {##5} {##6}
  }
  \cs_set_protected:cpx { msg_ #1 :nnxxx } ##1##2##3##4##5 {
    \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} {##5} { }
  }
  \cs_set_protected:cpx { msg_ #1 :nnxx } ##1##2##3##4 {
    \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} {##4} { } { }
  }
  \cs_set_protected:cpx { msg_ #1 :nnx } ##1##2##3 {
    \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { }
  }
  \cs_set_protected:cpx { msg_ #1 :nn } ##1##2 {
    \exp_not:c { msg_ #1 :nnxxxx } {##1} {##2} { } { } { } { }
  }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}[aux]{\msg_use:nnnnxxxx}
% The main message-using macro creates two auxiliary functions: one
% containing the code for the message, and the second a loop function.
% There is then a hand-off to the system for checking if redirection is
% needed.
%    \begin{macrocode}
\cs_new_protected:Npn \msg_use:nnnnxxxx #1#2#3#4#5#6#7#8 {
  \cs_set_nopar:Npn \msg_use_code: {
    \clist_clear:N \l_msg_redirect_classes_clist
    #2
  }
  \cs_set:Npn \msg_use_loop:n ##1 {
    \clist_if_in:NnTF \l_msg_redirect_classes_clist {#1} {
      \msg_kernel_error:nn { msg } { redirect-loop } {#1}
    }{
      \clist_put_right:Nn \l_msg_redirect_classes_clist {#1}
      \cs_if_exist:cTF { msg_ ##1 :nnxxxx } {
        \use:c { msg_ ##1 :nnxxxx } {#3} {#4} {#5} {#6} {#7} {#8}
      }{
        \msg_kernel_error:nnx { msg } { message-class-unknown } {##1}
      }
    }
  }
  \cs_if_exist:cTF { \c_msg_text_prefix_tl #3 / #4 :xxxx } {
    \msg_use_aux:nnn {#1} {#3} {#4} 
  }{
    \msg_kernel_error:nnxx { msg } { message-unknown } {#3} {#4}
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}[aux]{\msg_use_code:}
%\begin{macro}[aux]{\msg_use_loop:}
% Blank definitions are initially created for these functions.
%    \begin{macrocode}
\cs_new_nopar:Npn \msg_use_code: { }
\cs_new:Npn \msg_use_loop:n #1 { }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%
%\begin{macro}[aux]{\msg_use_aux:nnn}
% The first auxiliary macro looks for a match by name: the most 
% restrictive check.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_use_aux:nnn #1#2#3 {
  \tl_set:Nn \l_msg_current_class_tl  {#1}
  \tl_set:Nn \l_msg_current_module_tl {#2}
  \prop_if_in:NnTF \l_msg_redirect_names_prop { // #2 / #3 / } {
     \msg_use_loop_check:nn { names } { // #2 / #3 / }
  }{
    \msg_use_aux:nn {#1} {#2}
  }
}
%    \end{macrocode}
%\end{macro}
%\begin{macro}[aux]{\msg_use_aux:nn}
% The second function checks for general matches by module or for
% all modules.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_use_aux:nn #1#2 {
  \prop_if_in:cnTF { l_msg_redirect_ #1 _prop } {#2} {
    \msg_use_loop_check:nn {#1} {#2}
  }{
    \prop_if_in:cnTF { l_msg_redirect_ #1 _prop } { * } {
      \msg_use_loop_check:nn {#1} { * }
    }{
      \msg_use_code:
    }
  }    
}
%    \end{macrocode}
%\end{macro}
%\begin{macro}[aux]{\msg_use_loop_check:nn}
% When checking whether to loop, the same code is needed in a few
% places.
%    \begin{macrocode}
\cs_new_protected:Npn \msg_use_loop_check:nn #1#2 {
  \prop_get:cnN { l_msg_redirect_ #1 _prop } {#2} \l_msg_class_tl
  \tl_if_eq:NNTF \l_msg_current_class_tl \l_msg_class_tl {
    \msg_use_code:
  }{
    \msg_use_loop:n { \l_msg_class_tl }
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\msg_fatal:nnxxxx}
%\begin{macro}{\msg_fatal:nnxxx}
%\begin{macro}{\msg_fatal:nnxx}
%\begin{macro}{\msg_fatal:nnx}
%\begin{macro}{\msg_fatal:nn}
% For fatal errors, after the error message \TeX\ bails out.
%    \begin{macrocode}
\msg_class_new:nn { fatal } {
  \msg_direct_interrupt:xxxxx
    { \msg_fatal_text:n {#1} : ~ "#2"  }
    { 
      \use:c { \c_msg_text_prefix_tl #1 / #2 :xxxx } {#3} {#4} {#5} {#6}
    }
    {}
    { \msg_see_documentation_text:n {#1} }
    { \c_msg_fatal_text_tl }
  \tex_end:D
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_error:nnxxxx}
%\begin{macro}{\msg_error:nnxxx}
%\begin{macro}{\msg_error:nnxx}
%\begin{macro}{\msg_error:nnx}
%\begin{macro}{\msg_error:nn}
% For an error, the interrupt routine is called, then any recovery code
% is tried.
%    \begin{macrocode}
\msg_class_new:nn { error } {
  \msg_direct_interrupt:xxxxx
    { #1~ \c_msg_error_tl : ~ "#2" }
    { 
      \use:c { \c_msg_text_prefix_tl #1 / #2 :xxxx } {#3} {#4} {#5} {#6}
    }
    {}
    { \msg_see_documentation_text:n {#1} }
    { 
      \cs_if_exist:cTF { \c_msg_more_text_prefix_tl #1 / #2 :xxxx } 
        {
          \use:c { \c_msg_more_text_prefix_tl #1 / #2 :xxxx } 
            {#3} {#4} {#5} {#6}
        }
        { \c_msg_no_info_text_tl }
    }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_warning:nnxxxx}
%\begin{macro}{\msg_warning:nnxxx}
%\begin{macro}{\msg_warning:nnxx}
%\begin{macro}{\msg_warning:nnx}
%\begin{macro}{\msg_warning:nn}
% Warnings are printed to the terminal.
%    \begin{macrocode}
\msg_class_new:nn { warning } {
  \msg_direct_term:xx { 
    \c_space_tl #1 ~ \c_msg_warning_tl :~  
    \use:c { \c_msg_text_prefix_tl #1 / #2 :xxxx } {#3} {#4} {#5} {#6}
  }
  { ( #1 ) \c_space_tl \c_space_tl }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_info:nnxxxx}
%\begin{macro}{\msg_info:nnxxx}
%\begin{macro}{\msg_info:nnxx}
%\begin{macro}{\msg_info:nnx}
%\begin{macro}{\msg_info:nn}
% Information only goes into the log.
%    \begin{macrocode}
\msg_class_new:nn { info } {
  \msg_direct_log:xx { 
    \c_space_tl #1~\c_msg_info_tl :~  
    \use:c { \c_msg_text_prefix_tl #1 / #2 :xxxx } {#3} {#4} {#5} {#6}
  }
  { ( #1 ) \c_space_tl \c_space_tl }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_log:nnxxxx}
%\begin{macro}{\msg_log:nnxxx}
%\begin{macro}{\msg_log:nnxx}
%\begin{macro}{\msg_log:nnx}
%\begin{macro}{\msg_log:nn}
%  ``Log'' data is very similar to information, but with no extras 
%  added.
%    \begin{macrocode}
\msg_class_new:nn { log } {
  \msg_direct_log:xx { 
    \use:c { \c_msg_text_prefix_tl #1 / #2 :xxxx } {#3} {#4} {#5} {#6}
  }
  { }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_trace:nnxxxx}
%\begin{macro}{\msg_trace:nnxxx}
%\begin{macro}{\msg_trace:nnxx}
%\begin{macro}{\msg_trace:nnx}
%\begin{macro}{\msg_trace:nn}
%  Trace data is the same as log data, more or less
%    \begin{macrocode}
\msg_class_new:nn { trace } {
  \msg_direct_log:xx { 
    \use:c { \c_msg_text_prefix_tl #1 / #2 :xxxx } {#3} {#4} {#5} {#6}
  }
  { }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_none:nnxxxx}
%\begin{macro}{\msg_none:nnxxx}
%\begin{macro}{\msg_none:nnxx}
%\begin{macro}{\msg_none:nnx}
%\begin{macro}{\msg_none:nn}
% The \texttt{none} message type is needed so that input can be gobbled.
%    \begin{macrocode}
\msg_class_new:nn { none } { }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\subsection{Redirection functions}
%
%\begin{macro}{\msg_redirect_class:nn}
% Converts class one into class two.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_redirect_class:nn #1#2 {
  \prop_put:cnn { l_msg_redirect_ #1 _prop } { * } {#2}
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\msg_redirect_module:nnn}
% For when all messages of a class should be altered for a given module.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_redirect_module:nnn #1#2#3 {
  \prop_put:cnn { l_msg_redirect_ #2 _prop } {#1} {#3}
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\msg_redirect_name:nnn}
% Named message will always use the given class.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_redirect_name:nnn #1#2#3 {
  \prop_put:Nnn \l_msg_redirect_names_prop { // #1 / #2 / } {#3}
}
%    \end{macrocode}
%\end{macro}
%
%\subsection{Kernel-specific functions}
%
%\begin{macro}{\msg_kernel_new:nnnn}
%\begin{macro}{\msg_kernel_new:nnn}
%\begin{macro}{\msg_kernel_set:nnnn}
%\begin{macro}{\msg_kernel_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_nopar:Npn \msg_kernel_new:nnnn #1#2 {
  \msg_new:nnnn { LaTeX } { #1 / #2 }
}
\cs_new_protected_nopar:Npn \msg_kernel_new:nnn #1#2 {
  \msg_new:nnn { LaTeX } { #1 / #2 }
}
\cs_new_protected_nopar:Npn \msg_kernel_set:nnnn #1#2 {
  \msg_set:nnnn { LaTeX } { #1 / #2 }
}
\cs_new_protected_nopar:Npn \msg_kernel_set:nnn #1#2 {
  \msg_set:nnn { LaTeX } { #1 / #2 }
}
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}[aux]{\msg_kernel_classes_new:n}
% Quickly make the fewer-arguments versions.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_kernel_classes_new:n #1 {
  \cs_new_protected:cpx { msg_kernel_ #1 :nnxxx } ##1##2##3##4##5 
  {
    \exp_not:c { msg_kernel_ #1 :nnxxxx } 
      {##1} {##2} {##3} {##4} {##5} { }
  }
  \cs_new_protected:cpx { msg_kernel_ #1 :nnxx } ##1##2##3##4 
  {
    \exp_not:c { msg_kernel_ #1 :nnxxxx } 
      {##1} {##2} {##3} {##4} { } { }
  }
  \cs_new_protected:cpx { msg_kernel_ #1 :nnx } ##1##2##3 
  {
    \exp_not:c { msg_kernel_ #1 :nnxxxx } {##1} {##2} {##3} { } { } { }
  }
  \cs_new_protected:cpx { msg_kernel_ #1 :nn } ##1##2 
  {
    \exp_not:c { msg_kernel_ #1 :nnxxxx } {##1} {##2} { } { } { } { }
  }
}
%    \end{macrocode}
%\end{macro}
%
%\begin{macro}{\msg_kernel_fatal:nnxxxx}
%\begin{macro}{\msg_kernel_fatal:nnxxx}
%\begin{macro}{\msg_kernel_fatal:nnxx}
%\begin{macro}{\msg_kernel_fatal:nnx}
%\begin{macro}{\msg_kernel_fatal:nn}
% Fatal kernel errors cannot be re-defined.
%    \begin{macrocode}
\cs_new_protected:Npn \msg_kernel_fatal:nnxxxx #1#2#3#4#5#6 {
  \msg_direct_interrupt:xxxxx
    { \msg_fatal_text:n {LaTeX} }
    { 
      \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 :xxxx } 
        {#3} {#4} {#5} {#6}
    }
    {}
    { \msg_see_documentation_text:n {LaTeX3} }
    { \c_msg_fatal_text_tl }
  \tex_end:D
}
\msg_kernel_classes_new:n { fatal }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_kernel_error:nnxxxx}
%\begin{macro}{\msg_kernel_error:nnxxx}
%\begin{macro}{\msg_kernel_error:nnxx}
%\begin{macro}{\msg_kernel_error:nnx}
%\begin{macro}{\msg_kernel_error:nn}
% Neither can kernel errors.
%    \begin{macrocode}
\cs_new_protected:Npn \msg_kernel_error:nnxxxx #1#2#3#4#5#6 {
  \msg_direct_interrupt:xxxxx
    { LaTeX~\c_msg_error_tl \c_space_tl "#2" }
    { 
      \use:c { \c_msg_text_prefix_tl LaTeX / #1 / #2 :xxxx } 
        {#3} {#4} {#5} {#6}
    }
    {}
    { \msg_see_documentation_text:n {LaTeX3} }
    { 
      \cs_if_exist:cTF 
        { \c_msg_more_text_prefix_tl LaTeX / #1 / #2 :xxxx } 
        {
          \use:c { \c_msg_more_text_prefix_tl LaTeX / #1 / #2 :xxxx } 
            {#3} {#4} {#5} {#6}
        }
        { \c_msg_no_info_text_tl }
    }
}
\msg_kernel_classes_new:n { error }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
%\begin{macro}{\msg_kernel_warning:nnxxxx}
%\begin{macro}{\msg_kernel_warning:nnxxx}
%\begin{macro}{\msg_kernel_warning:nnxx}
%\begin{macro}{\msg_kernel_warning:nnx}
%\begin{macro}{\msg_kernel_warning:nn}
%\begin{macro}{\msg_kernel_info:nnxxxx}
%\begin{macro}{\msg_kernel_info:nnxxx}
%\begin{macro}{\msg_kernel_info:nnxx}
%\begin{macro}{\msg_kernel_info:nnx}
%\begin{macro}{\msg_kernel_info:nn}
% Life is much more simple for warnings and information messages, as
% these are just short-cuts to the standard classes.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \msg_kernel_warning:nnxxxx #1#2 {
  \msg_warning:nnxxxx { LaTeX } { #1 / #2 }
}
\msg_kernel_classes_new:n { warning }
\cs_new_protected_nopar:Npn \msg_kernel_info:nnxxxx #1#2 {
  \msg_info:nnxxxx { LaTeX } { #1 / #2 }
}
\msg_kernel_classes_new:n { info }
%    \end{macrocode}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%\end{macro}
%
% Error messages needed to actually implement the message system
% itself.
%    \begin{macrocode}
\msg_kernel_new:nnnn { msg } { message-unknown } 
  { Unknown~message~'#2'~for~module~'#1'.}
  {
    \c_msg_coding_error_text_tl
    LaTeX~was~asked~to~display~a~message~called~'#2'\\
    by~the~module~'#1'~module:~this~message~does~not~exist.
    \c_msg_return_text_tl
  }
\msg_kernel_new:nnnn { msg } { message-class-unknown }   
  { Unknown~message~class~'#1'. }
  {
    LaTeX~has~been~asked~to~redirect~messages~to~a~class~'#1':\\
    this~was~never~defined.
    
    \c_msg_return_text_tl
  }
\msg_kernel_new:nnnn { msg } { redirect-loop } 
  { Message~redirection~loop~for~message~class~'#1'. }
  {
    LaTeX~has~been~asked~to~redirect~messages~in~an~infinite~loop.\\
    The~original~message~here~has~been~lost.
    \c_msg_return_text_tl
  }
%    \end{macrocode}
%    
%\begin{macro}{\msg_kernel_bug:x}
% The \LaTeX\ coding bug error gets re-visited here.
%    \begin{macrocode}
\cs_set_protected:Npn \msg_kernel_bug:x #1 {
  \msg_direct_interrupt:xxxxx
    { \c_msg_kernel_bug_text_tl }
    { #1 } 
    {}
    { \msg_see_documentation_text:n {LaTeX3} }
    { \c_msg_kernel_bug_more_text_tl }
}
%    \end{macrocode}
%\end{macro}
%    
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
% 
% \PrintIndex
