summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex-dev
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2020-07-21 21:39:07 +0000
committerKarl Berry <karl@freefriends.org>2020-07-21 21:39:07 +0000
commita4824d556273f90fbb37d24449cca150397ab7f2 (patch)
tree27fa3e556270c65afd257af5c0e69168c8c2633b /Master/texmf-dist/source/latex-dev
parenta5ed6b49fd24fce0a996e8db92f76022c41c5007 (diff)
latex-dev (21jul20)
git-svn-id: svn://tug.org/texlive/trunk@55898 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex-dev')
-rw-r--r--Master/texmf-dist/source/latex-dev/base/doc.dtx17
-rw-r--r--Master/texmf-dist/source/latex-dev/base/docstrip.dtx180
-rw-r--r--Master/texmf-dist/source/latex-dev/base/format.ins2
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltclass.dtx42
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltdefns.dtx12
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltexpl.dtx198
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx1161
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltfiles.dtx68
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltfinal.dtx251
-rw-r--r--Master/texmf-dist/source/latex-dev/base/lthooks.dtx3925
-rw-r--r--Master/texmf-dist/source/latex-dev/base/lthooks.ins76
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltluatex.dtx19
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx29
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx84
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltshipout.dtx1425
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltvers.dtx2
-rw-r--r--Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx13
-rw-r--r--Master/texmf-dist/source/latex-dev/base/unpack.ins1
-rw-r--r--Master/texmf-dist/source/latex-dev/graphics/lscape.dtx7
-rw-r--r--Master/texmf-dist/source/latex-dev/tools/array.dtx52
-rw-r--r--Master/texmf-dist/source/latex-dev/tools/varioref.dtx87
-rw-r--r--Master/texmf-dist/source/latex-dev/tools/verbatim.dtx31
22 files changed, 7527 insertions, 155 deletions
diff --git a/Master/texmf-dist/source/latex-dev/base/doc.dtx b/Master/texmf-dist/source/latex-dev/base/doc.dtx
index 3011994d9d1..7e7817153c8 100644
--- a/Master/texmf-dist/source/latex-dev/base/doc.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/doc.dtx
@@ -35,7 +35,7 @@
%<+package|shortvrb>\NeedsTeXFormat{LaTeX2e}[1994/12/01]
%<+package> \ProvidesPackage{doc}
%<+shortvrb>\ProvidesPackage{shortvrb}
-%<+package|shortvrb> [2019/12/16 v2.1l
+%<+package|shortvrb> [2020/06/15 v2.1m
%<+package|shortvrb> Standard LaTeX documentation package (FMi)]
%\catcode`\<=12
%
@@ -139,7 +139,7 @@
% \changes{v1.9t}{1995/05/11}{Use \cs{GetFileInfo}}
% \GetFileInfo{doc.sty}
%
-% \CheckSum{2208} ^^A % keep the checksum in this file
+% \CheckSum{2213} ^^A % keep the checksum in this file
%
% \title{The \DOC{} and \texttt{shortvrb} Packages\thanks
% {This file has version number \fileversion{} dated \filedate{}.}}
@@ -1324,6 +1324,16 @@
\if@inlabel\leavevmode\fi
\trivlist \parskip \z@ \item[]%
% \end{macrocode}
+% The \cs{item} command sets the \cs{@labels} box but that box is
+% never typeset (as \cs{everypar} that normally does this gets
+% redefined later). That is normally not an issue, but produces a
+% problem when typesetting in mixed directions, (e.g., in
+% Japanese), so we explicitly clear it for that use case.
+% \changes{v2.1m}{2020/06/15}{Void \cs{@labels} for vertical
+% typesetting (gh/344)}
+% \begin{macrocode}
+ \global\setbox\@labels\box\voidb@x
+% \end{macrocode}
% Additionally, everything should be set in \texttt{typewriter} font.
% Some people might prefer it somewhat differently; because of this
% the font choice is
@@ -1448,7 +1458,8 @@
% bothered since doc-sources should be up-to-date but since the
% request came from someone called David Carlisle \ldots :-)
% \changes{v1.9y}{1996/01/26}{Support compat mode}
-% \changes{v2.1l}{2019/12/16}{Use \cs{shapedefault} not \cs{updefault} for extended NFSS}
+% \changes{v2.1l}{2019/12/16}{Use \cs{shapedefault} not
+% \cs{updefault} for extended NFSS}
% \begin{macrocode}
\def\MacroFont{\small
\usefont\encodingdefault
diff --git a/Master/texmf-dist/source/latex-dev/base/docstrip.dtx b/Master/texmf-dist/source/latex-dev/base/docstrip.dtx
index 3ce6ed56967..a0a06311edb 100644
--- a/Master/texmf-dist/source/latex-dev/base/docstrip.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/docstrip.dtx
@@ -29,9 +29,9 @@
\catcode`\{=1
\catcode`\}=2
\def\filename{docstrip.dtx}
-\def\fileversion{v2.5h}
-\def\filedate{2020/04/18}
-\def\docdate {2018/05/03}
+\def\fileversion{v2.6a}
+\def\filedate{2020-07-07}
+\def\docdate {2020-07-11}
%%
%
%\iffalse
@@ -42,7 +42,7 @@
%% Frank Mittelbach
%% Copyright (C) 1995 Marcin Woli\'nski
%% Copyright (C) 1996-1997 Mark Wooding, Marcin Woli\'nski
-%% Copyright (C) 1998-2003 LaTeX3 project and the above authors
+%% Copyright (C) 1998-2020 LaTeX3 project and the above authors
%% All rights are reserved.
%%
%
@@ -82,6 +82,8 @@
% \changes{2.3e}{1996/10/02}{Introduced ``open lists''}
% \changes{2.4a}{1996/06/06}{Add stream limits (MDW)}
% \changes{2.4c}{1996/06/11}{Add initex support (DPC)}
+% \changes{v2.6a}{2020-07-07}{Added the handling of @@-modules from
+% \texttt{l3docstrip.dtx} (gh/337)}
%
% \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ }
% \DoNotIndex{\@ne}
@@ -785,6 +787,57 @@
% When a block of code is {\em not\/} included, any guards that occur
% within that block are {\em not\/} evaluated.
%
+% \section{Internal functions and variables}
+%
+% An important consideration for \LaTeX3 development is separating
+% out public and internal functions. Functions and variables which
+% are private to one module should not be used or modified by any
+% other module. As \TeX{} does not have any formal namespacing
+% system, this requires a convention for indicating which functions
+% in a code-level module are public and which are private.
+%
+% Using \ds\ allows internal functions to be indicated
+% using a `two part' system. Within the \texttt{.dtx} file,
+% internal functions may be indicated using |@@| in place of the
+% module name, for example
+% \begin{verbatim}
+% \cs_new_protected:Npn \@@_some_function:nn #1#2
+% {
+% % Some code here
+% }
+% \tl_new:N \l_@@_internal_tl
+% \end{verbatim}
+%
+% To extract the code using \ds, the original `guard'
+% mecahnism is extended by the introduction of the syntax
+% \texttt{\%<@@=\meta{module}>}. The \meta{module} name then
+% replaces the |@@| when the code is extracted, so that
+% \begin{verbatim}
+% %<*package>
+% %<@@=foo>
+% \cs_new_protected:Npn \@@_some_function:nn #1#2
+% {
+% % Some code here
+% }
+% \tl_new:N \l_@@_internal_tl
+% %</package>
+% \end{verbatim}
+% is extracted as
+% \begin{verbatim}
+% \cs_new_protected:Npn \__foo_some_function:nn #1#2
+% {
+% % Some code here
+% }
+% \tl_new:N \l__foo_internal_tl
+% \end{verbatim}
+% where the |__| indicates that the functions and variables are
+% internal to the \texttt{foo} module.
+%
+% Use |@@@@| to obtain |@@| in the output (|@@@@@| to get |@@@|).
+% For longer pieces of code the replacement can be completely
+% suppressed by giving an empty module name, namely using the
+% syntax \texttt{\%<@@=>}.
+%
% \section{Those other languages}
% Since \TeX\ is an open system some of \TeX\ packages include
% non-\TeX\ files. Some authors use \ds\ to generate PostScript
@@ -853,7 +906,7 @@
%
% \subsection{Verbatim mode}
% If your programming language uses some construct that can
-% interferes badly with \ds\ (e.g., percent in column one) you may
+% interfere badly with \ds\ (e.g., percent in column one) you may
% need a way for preventing it from being stripped off. For that
% purpose \ds\ features `verbatim mode'.
%
@@ -2245,9 +2298,14 @@ Z
% \subsection{Processing the input lines}
%
% \begin{macro}{\normalLine}
+% \changes{v2.6a}{2020-07-07}{The search-and-replace macro
+% \cs{replaceModuleInLine} added from \textsf{l3docstrip.dtx}
+% (gh/337)}
% The macro |\normalLine| writes its argument (which has to be
% delimited with |\endLine|) on all active output files i.e.
-% those with off-counters equal to zero.
+% those with off-counters equal to zero. It uses the
+% search-and-replace macro \cs{replaceModuleInLine} to replace any
+% occurences of \texttt{@@} with the current module name.
% If statistics are included, the counter
% |\codeLinesPassed| is incremented by $1$.
% \begin{macrocode}
@@ -2257,6 +2315,7 @@ Z
%</stats>
\maybeMsg{.}%
\def\inLine{#1}%
+ \replaceModuleInLine
\let\do\putline@do
\activefiles
}
@@ -2417,14 +2476,17 @@ Z
% \changes{2.3a}{1995/08/18}{Adapted to concurrent version}
% \changes{2.3a}{1995/08/20}{Trying to avoid assignments}
% \changes{2.3e}{1996/09/16}{Verbatim mode}
+% \changes{v2.6a}{2020-07-07}{Add the @-sign option from
+% \textsf{l3docstrip.dtx} (gh/337)}
+%
% When the macros that process a line have found that the line
% starts with `\texttt{\%<}', a guard line has been encountered.
% The first character of a guard can be an asterisk (\texttt{*}), a
% slash (\texttt{/}) a plus (\texttt{+}), a minus (\texttt{-}), a
-% less-than sign (\texttt{<}) starting verbatim mode or
-% any other character that can be found in an option name. This
-% means that we have to peek at the next token and
-% decide what kind of guard we have.
+% less-than sign (\texttt{<}) starting verbatim mode, a commercial
+% at (\texttt{@}) or any other character that can be found in an
+% option name. This means that we have to peek at the next token
+% and decide what kind of guard we have.
%
% We reinsert |#1| as it may be needed by |\doOption|.
% \begin{macrocode}
@@ -2432,12 +2494,13 @@ Z
\ifcase
\ifx*#10\else \ifx/#11\else
\ifx+#12\else \ifx-#13\else
- \ifx<#14\else 5\fi\fi\fi\fi\fi\relax
+ \ifx<#14\else \ifx @#15\else 6\fi\fi\fi\fi\fi\fi\relax
\expandafter\starOption\or
\expandafter\slashOption\or
\expandafter\plusOption\or
\expandafter\minusOption\or
\expandafter\verbOption\or
+ \expandafter\moduleOption\or
\expandafter\doOption\fi
#1}
% \end{macrocode}
@@ -2452,12 +2515,17 @@ Z
% result of the test |\if1\Expr{|\meta{options}|}|, the current
% line is either copied to the output stream or removed. Then
% the test is computed for all active output files.
+% \changes{v2.6a}{2020-07-07}{Now use \cs{InLine} and call
+% \cs{replaceModuleInline} (gh/337)}
% \begin{macrocode}
\def\doOption#1>#2\endLine{%
\maybeMsg{<#1 . >}%
\Evaluate{#1}%
\def\do##1##2##3{%
- \if1\Expr{##2}\StreamPut##1{#2}\fi
+ \if1\Expr{##2}%
+ \def\inLine{#2}%
+ \replaceModuleInLine
+ \StreamPut##1{\inLine}\fi
}%
\activefiles
}
@@ -2681,6 +2749,94 @@ Z
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\moduleOption}
+% \changes{v2.6a}{2020-07-07}{Macro added from
+% \textsf{l3docstrip.dtx} (gh/337)}
+%
+% In the case where the line starts |%<@|: the defined syntax requires that
+% this continues to |%<@@=|. At the moment, we assume that the syntax is
+% correct and |#1| here is the module name for substitution into any
+% internal functions in the extracted material.
+% \begin{macrocode}
+\def\moduleOption @@=#1>#2\endLine{%
+ \maybeMsg{<@@=#1>}%
+ \prepareActiveModule{#1}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\prepareActiveModule}
+% \changes{v2.6a}{2020-07-07}{Macro added from
+% \textsf{l3docstrip.dtx} (gh/337)}
+% \begin{macro}{\replaceModuleInLine}
+% \changes{v2.6a}{2020-07-07}{Macro added from
+% \textsf{l3docstrip.dtx} (gh/337)}
+% Here, we set up to do the search-and-replace when doing the
+% extraction. The argument (|#1|) is the replacement text to use,
+% or if empty an indicator that no replacement should be done. The
+% search material is one of |__@@|, |_@@| or |@@|, done in order
+% such that all three end up the same in the output. The string
+% |@@@@| is hidden from these replacements by temporarily turning
+% it into a pair of letters with different category codes, not
+% produced by \ds; this allows to get |@@| in the
+% output. The replacement function is initialised as a do-nothing
+% for the case where |%<@@=| is never seen.
+% \begin{macrocode}
+\begingroup
+ \catcode`\_ = 12 %
+ \long\gdef\prepareActiveModule#1{%
+ \ifx\relax#1\relax
+ \let\replaceModuleInLine\empty
+ \else
+ \edef\replaceModuleInLine{%
+ \noexpand\replaceAllIn\noexpand\inLine{@@@@}{\string aa}%
+ \noexpand\replaceAllIn\noexpand\inLine{__@@}{__#1}%
+ \noexpand\replaceAllIn\noexpand\inLine{_@@}{__#1}%
+ \noexpand\replaceAllIn\noexpand\inLine{@@}{__#1}%
+ \noexpand\replaceAllIn\noexpand\inLine{\string aa}{@@}%
+ }%
+ \fi
+ }
+\endgroup
+\let\replaceModuleInLine\empty
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\replaceAllIn}
+% \changes{v2.6a}{2020-07-07}{Macro added from
+% \textsf{l3docstrip.dtx} (gh/337)}
+% \begin{macro}{\replaceAllInAuxI}
+% \changes{v2.6a}{2020-07-07}{Macro added from
+% \textsf{l3docstrip.dtx} (gh/337)}
+% \begin{macro}{\replaceAllInAuxII}
+% \changes{v2.6a}{2020-07-07}{Macro added from
+% \textsf{l3docstrip.dtx} (gh/337)}
+% \begin{macro}{\replaceAllInAuxIII}
+% \changes{v2.6a}{2020-07-07}{Macro added from
+% \textsf{l3docstrip.dtx} (gh/337)}
+% The code here is a simple search-and-replace routine for a macro
+% |#1|, replacing |#2| by |#3|. As set up here, there is an
+% assumption that nothing is going to be expandable, which is
+% reasonable as \ds\ deals with `string' material.
+% \begin{macrocode}
+\long\def\replaceAllIn#1#2#3{%
+ \long\def\tempa##1##2#2{%
+ ##2\qMark\replaceAllInAuxIII#3##1%
+ }%
+ \edef#1{\expandafter\replaceAllInAuxI#1\qMark#2\qStop}%
+}
+\def\replaceAllInAuxI{%
+ \expandafter\replaceAllInAuxII\tempa\replaceAllInAuxI\empty
+}
+\long\def\replaceAllInAuxII#1\qMark#2{#1}
+\long\def\replaceAllInAuxIII#1\qStop{}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
% \subsection{Batchfile commands}
% \changes{2.3e}{1996/10/02}{Added doc}
% \ds{} keeps information needed to control inclusion of sources in
diff --git a/Master/texmf-dist/source/latex-dev/base/format.ins b/Master/texmf-dist/source/latex-dev/base/format.ins
index 940161edd5b..5d96b5e1f35 100644
--- a/Master/texmf-dist/source/latex-dev/base/format.ins
+++ b/Master/texmf-dist/source/latex-dev/base/format.ins
@@ -161,6 +161,7 @@ the system are in the document `cfgguide.tex'.
\from{ltdirchk.dtx}{initex,2ekernel,dircheck}
\from{ltplain.dtx}{2ekernel}
\from{ltvers.dtx}{2ekernel}
+ \from{ltluatex.dtx}{2ekernel}
\from{ltdefns.dtx}{2ekernel}
\from{ltalloc.dtx}{2ekernel}
\from{ltcntrl.dtx}{2ekernel}
@@ -196,7 +197,6 @@ the system are in the document `cfgguide.tex'.
\from{ltpage.dtx}{2ekernel}
\from{ltoutput.dtx}{2ekernel}
\from{ltclass.dtx}{2ekernel,tracerollback}
- \from{ltluatex.dtx}{2ekernel}
\from{ltfinal.dtx}{2ekernel}}
\file{tracefnt.sty}{%
\from{ltfsstrc.dtx}{package,trace}}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltclass.dtx b/Master/texmf-dist/source/latex-dev/base/ltclass.dtx
index dd35be9ae41..152adf82ff2 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltclass.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltclass.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltclass.dtx}
- [2020/04/24 v1.3k LaTeX Kernel (Class & Package Interface)]
+ [2020/06/05 v1.3l LaTeX Kernel (Class & Package Interface)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltclass.dtx}
@@ -552,22 +552,58 @@
% |#2| current extension. \\
% |#3| current catcode of |@|. \\
% |#4| Rest of the stack.
+% \changes{v1.3l}{2020/06/05}{Added \cs{@expl@push@filename@@}
+% and \cs{@expl@push@filename@aux@@}}
% \begin{macrocode}
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@pushfilename}%
+%<latexrelease> {Add \@expl@push@filename@@ and \@expl@push@filename@aux@@}%
\def\@pushfilename{%
+ \@expl@push@filename@@
\xdef\@currnamestack{%
{\@currname}%
{\@currext}%
{\the\catcode`\@}%
- \@currnamestack}}
+ \@currnamestack}%
+ \@expl@push@filename@aux@@}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>
+%<latexrelease>\IncludeInRelease{0000/00/00}{\@pushfilename}%
+%<latexrelease> {Add \@expl@push@filename@@ and \@expl@push@filename@aux@@}%
+%<latexrelease>\def\@pushfilename{%
+%<latexrelease> \xdef\@currnamestack{%
+%<latexrelease> {\@currname}%
+%<latexrelease> {\@currext}%
+%<latexrelease> {\the\catcode`\@}%
+%<latexrelease> \@currnamestack}}
+%<latexrelease>\EndIncludeInRelease
\@onlypreamble\@pushfilename
% \end{macrocode}
%
+% \changes{v1.3l}{2020/06/05}{Added \cs{@expl@pop@filename@@}}
% \begin{macrocode}
-\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil}
+%<latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}{\@popfilename}%
+%<latexrelease> {Add \@expl@pop@filename@@}%
+\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil
+ \@expl@pop@filename@@}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>
+%<latexrelease>\IncludeInRelease{0000/00/00}{\@pushfilename}%
+%<latexrelease> {Add \@expl@push@filename@@ and \@expl@push@filename@aux@@}%
+%<latexrelease>\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil}
+%<latexrelease>\EndIncludeInRelease
\@onlypreamble\@popfilename
% \end{macrocode}
%
% \begin{macrocode}
+%</2ekernel|latexrelease>
+%<*2ekernel>
+% \end{macrocode}
+%
+% \begin{macrocode}
\def\@p@pfilename#1#2#3#4\@nil{%
\gdef\@currname{#1}%
\gdef\@currext{#2}%
diff --git a/Master/texmf-dist/source/latex-dev/base/ltdefns.dtx b/Master/texmf-dist/source/latex-dev/base/ltdefns.dtx
index 8b7a307ad2d..3abd251e4c9 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltdefns.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltdefns.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltdefns.dtx}
- [2020/05/15 v1.5h LaTeX Kernel (definition commands)]
+ [2020/06/04 v1.5i LaTeX Kernel (definition commands)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltdefns.dtx}
@@ -101,6 +101,16 @@
%<*2ekernel>
% \end{macrocode}
%
+% \subsection{Loading further extensions}
+%
+% \changes{v1.5i}{2020-06-04}{Load \textsf{ltexpl} in \texttt{ltdefns}}
+% Simply load further code: it's deliberately separate.
+% This is done as soon as possible here in \texttt{ltdefns.dtx} so that
+% we have the extensions as soon as possible.
+% \begin{macrocode}
+\input ltexpl.ltx
+% \end{macrocode}
+%
% \subsection{Initex initialisations}
%
% \task{???}{This section needs extension}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltexpl.dtx b/Master/texmf-dist/source/latex-dev/base/ltexpl.dtx
index 5e726298b26..7a567e378f3 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltexpl.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltexpl.dtx
@@ -33,10 +33,10 @@
%<*driver>
% \fi
\ProvidesFile{ltexpl.dtx}
- [2020-05-03 v1.2b LaTeX Kernel (expl3-dependent code)]
+ [2020-07-08 v1.2d LaTeX Kernel (expl3-dependent code)]
% \iffalse
\documentclass{ltxdoc}
-\GetFileInfo{ltfinal.dtx}
+\GetFileInfo{ltexpl.dtx}
\title{\filename}
\date{\filedate}
\author{%
@@ -44,7 +44,7 @@
\begin{document}
\MaintainedByLaTeXTeam{latex}
\maketitle
- \DocInput{ltfinal.dtx}
+ \DocInput{ltexpl.dtx}
\end{document}
%</driver>
% \fi
@@ -55,69 +55,170 @@
%
% \changes{v0.0}{2019-10-02}{Initial version}
%
+% \subsection{Loader}
+%
+% \changes{v1.0a}{2020/03/02}
+% {Don't load expl3 if already in the format (gh/295)}
+% \changes{v1.1}{2020/03/05}
+% {Load xparse.ltx if \cs{NewDocumentCommand} is not defined
+% by expl3.ltx}
+% \changes{v1.2c}{2020/06/04}
+% {Define a local version of some \LaTeXe{} basic macros to support
+% package loading}
+%
+% First define some blank commands, so that in case something goes wrong while
+% loading \textsf{expl3}, we won't get strange \texttt{Undefined control
+% sequence} errors.
% \begin{macrocode}
%<*2ekernel>
+\def\@expl@sys@load@backend@@{}
+\def\@expl@push@filename@@{}
+\def\@expl@push@filename@aux@@{}
+\def\@expl@pop@filename@@{}
+%</2ekernel>
% \end{macrocode}
%
-% \subsection{Loader}
+% \changes{v1.2d}{2020/07/08}
+% {Add a last-minute hook for \textsf{expl3}}
+% Create a hook for last-minute \pkg{expl3} material.
+% \begin{macrocode}
+%<*2ekernel>
+\def\@expl@finalise@setup@@{}
+%</2ekernel>
+% \end{macrocode}
%
-% Check for the required primitive/engine support and the existence of
-% a loader.
+% Now define some basics to support loading \textsf{expl3}. These macros can
+% be defined here safely, because they are redefined later on by the kernel,
+% so we define simpler versions just to suit our needs.
% \begin{macrocode}
+%<*2ekernel>
+\long\def\@gobble#1{}
+\long\def\@firstofone#1{#1}
+\long\def\@firstoftwo#1#2{#1}
+\long\def\@secondoftwo#1#2{#2}
+\long\def\IfFileExists#1{%
+ \openin\@inputcheck"#1" %
+ \ifeof\@inputcheck
+ \expandafter\@secondoftwo
+ \else
+ \closein\@inputcheck
+ \expandafter\@firstoftwo
+ \fi}
+\long\def\@ifnextchar#1#2#3{%
+ \let\reserved@d=#1%
+ \def\reserved@a{#2}%
+ \def\reserved@b{#3}%
+ \futurelet\@let@token\@ifnch}
+\def\@ifnch{%
+ \ifx\@let@token\reserved@d
+ \expandafter\reserved@a
+ \else
+ \expandafter\reserved@b
+ \fi}
%</2ekernel>
-%<*2ekernel|latexrelease>
-%<latexrelease>\IncludeInRelease{2020/02/02}%
-%<latexrelease> {expl3}{Pre-load expl3}%
% \end{macrocode}
+%
% If we are doing a rollback with a format containing expl3 we
% aren't reloading it as that creates havoc. This may need a
% refined version!
-% \changes{v1.0a}{2020/03/02}
-% {Don't load expl3 if already in the format (gh/295)}
-% \changes{v1.1}{2020/03/05}
-% {Load xparse.ltx if \cs{NewDocumentCommand} is not defined
-% by expl3.ltx}
% \begin{macrocode}
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {expl3}{Pre-load expl3}%
\expandafter\ifx\csname tex\string _let:D\endcsname\relax
- \IfFileExists{expl3.ltx}
- {%
- \ifnum0%
- \ifdefined\pdffilesize 1\fi
- \ifdefined\filesize 1\fi
- \ifdefined\luatexversion\ifnum\luatexversion>94 1\fi\fi
- >0 %
- \expandafter\@firstofone
- \else
- \message{Skipping expl3-dependent extensions}
-%<2ekernel> \expandafter\endinput
-%<latexrelease> \expandafter\@gobble
- \fi
- }
- {%
- \message{Skipping expl3-dependent extensions}%
-%<2ekernel> \endinput
-%<latexrelease> \@gobble
- }%
- {%
- \input{expl3.ltx}
- \ifdefined\NewDocumentCommand
- \else
- \IfFileExists{xparse.ltx}
- {\input{xparse.ltx}}
- {}%
- \fi
- }%
+ \expandafter\@firstofone
\else
- \GenericInfo{}{Skipping: expl3 code already part of the format}
+ \GenericInfo{}{Skipping: expl3 code already part of the format}%
+%<2ekernel> \expandafter\endinput
+%<latexrelease> \expandafter\@gobble
\fi
-%</2ekernel|latexrelease>
+% \end{macrocode}
+%
+% Check for the required primitive/engine support and the existence of
+% a loader.
+% \begin{macrocode}
+ {%
+ \IfFileExists{expl3.ltx}
+ {%
+ \ifnum0%
+ \ifdefined\pdffilesize 1\fi
+ \ifdefined\filesize 1\fi
+ \ifdefined\luatexversion\ifnum\luatexversion>94 1\fi\fi
+ \ifdefined\kanjiskip 1\fi
+ >0 %
+ \expandafter\@firstofone
+ \else
+% \end{macrocode}
+%
+% In \texttt{2ekernel} mode, an error is fatal and building the format
+% is aborted. Use \verb=\batchmode \read -1 to \tokenlist=, which errors
+% with
+% \verb=! Emergency stop. (cannot \read from terminal in nonstop modes)=
+% and aborts the \TeX{} run. In \texttt{latexrelease} mode, raise an
+% error and do nothing. Both ways, the error message shows the minimum
+% \textsf{expl3} engine requirements.
+% \begin{macrocode}
+%<2ekernel> \def~{ }\def\MessageBreak{^^J~~~~~~~~~~~~~~~}%
+%<2ekernel> \errmessage{LaTeX Error:
+%<latexrelease> \@latex@error{%
+ LaTeX requires the e-TeX primitives and additional\MessageBreak
+ functionality available in the engines:\MessageBreak
+ - pdfTeX v1.40\MessageBreak
+ - XeTeX v0.99992\MessageBreak
+ - LuaTeX v0.95\MessageBreak
+ - e-(u)pTeX mid-2012\MessageBreak
+ or later%
+%<latexrelease> }\@ehd \expandafter\@gobble
+%<2ekernel> }\batchmode \read -1 to \reserved@a
+ \fi
+ }
+ {%
+%<*2ekernel>
+ \errmessage{LaTeX requires expl3}%
+ \batchmode \read -1 to \reserved@a
+%</2ekernel>
+%<*latexrelease>
+ \@latex@error{LaTeX requires expl3}\@ehd
+ \@gobble
+%</latexrelease>
+ }%
+ {%
+ \input expl3.ltx
+ \ifdefined\NewDocumentCommand
+ \else
+ \IfFileExists{xparse.ltx}
+ {\input xparse.ltx }
+ {}%
+ \fi
+ }%
+ }
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>
+%<latexrelease>\IncludeInRelease{2020/02/02}%
+%<latexrelease> {expl3}{Pre-load expl3}%
+%<latexrelease>\IfFileExists{expl3.ltx}
+%<latexrelease> {%
+%<latexrelease> \ifnum0%
+%<latexrelease> \ifdefined\pdffilesize 1\fi
+%<latexrelease> \ifdefined\filesize 1\fi
+%<latexrelease> \ifdefined\luatexversion\ifnum\luatexversion>94 1\fi\fi
+%<latexrelease> >0 %
+%<latexrelease> \else
+%<latexrelease> \message{Skipping expl3-dependent extensions}
+%<latexrelease> \expandafter\@gobbletwo
+%<latexrelease> \fi
+%<latexrelease> }
+%<latexrelease> {%
+%<latexrelease> \message{Skipping expl3-dependent extensions}%
+%<latexrelease> \@gobbletwo
+%<latexrelease> }%
+%<latexrelease>\input{expl3.ltx}
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
% \subsection{Using expl3 code}
%
% \begin{macrocode}
-%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease> {\@expl@tl@trim@spaces@apply@@nN}
%<latexrelease> {l3 macro for use in include}%
@@ -141,7 +242,6 @@
% \end{macrocode}
%
% \begin{macrocode}
-%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease> {\@expl@tl@trim@spaces@apply@@nN}
@@ -150,11 +250,7 @@
%<latexrelease>\let\@expl@tl@trim@spaces@apply@@nN\@undefined
%<latexrelease>
%<latexrelease>\EndIncludeInRelease
-%<*2ekernel>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%</2ekernel>
+%</2ekernel|latexrelease>
% \end{macrocode}
%
% \Finale
diff --git a/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx b/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx
new file mode 100644
index 00000000000..6c16a9832ea
--- /dev/null
+++ b/Master/texmf-dist/source/latex-dev/base/ltfilehook.dtx
@@ -0,0 +1,1161 @@
+% \iffalse meta-comment
+%
+%% File: ltfilehook.dtx (C) Copyright 2020 Frank Mittelbach, LaTeX Team
+%
+% 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
+%
+%
+% The development version of the bundle can be found below
+%
+% https://github.com/FrankMittelbach/...
+%
+% for those people who are interested or want to report an issue.
+%
+% \begin{macrocode}
+\providecommand\ltfilehookversion{v0.9a}
+\providecommand\ltfilehookdate{2020/07/19}
+% \end{macrocode}
+%
+%<*driver>
+
+\RequirePackage{lthooks} % needed for structedlog if running old format
+
+\documentclass{l3doc}
+
+% bug fix fo l3doc.cls
+\ExplSyntaxOn
+\cs_set_protected:Npn \__codedoc_macro_typeset_one:nN #1#2
+ {
+ \vbox_set:Nn \l__codedoc_macro_box
+ {
+ \vbox_unpack_drop:N \l__codedoc_macro_box
+ \hbox { \llap { \__codedoc_print_macroname:nN {#1} #2
+ \MacroFont % <----- without it the \ is in lmr10 if a link is made
+ \
+ } }
+ }
+ \int_incr:N \l__codedoc_macro_int
+ }
+\ExplSyntaxOff
+
+\usepackage{structuredlog} % for demonstration
+
+\EnableCrossrefs
+\CodelineIndex
+\begin{document}
+ \DocInput{ltfilehook.dtx}
+\end{document}
+%</driver>
+%
+% \fi
+%
+%
+% \long\def\fmi#1{\begin{quote}\itshape Todo: #1\end{quote}}
+%
+% \let\hook\texttt
+%
+% \title{The \texttt{ltfilehook} package\thanks{This package has version
+% \ltfilehookversion\ dated \ltfilehookdate, \copyright\ \LaTeX\
+% Project.}}
+%
+% \author{Frank Mittelbach}
+%
+% \maketitle
+%
+%
+%
+% \tableofcontents
+%
+% \section{Introduction}
+%
+%
+%
+% \subsection{Provided hooks}
+%
+% The code offers a number of hooks into which packages (or the
+% user) can add code to support different use cases.
+% Many hooks are offered as pairs (i.e., the second hook is
+% reversed. Also important to know is that these pairs are
+% properly nested with respect to other pairs of hooks.
+%
+% There are hooks that are executed for all files of a certain type
+% (if they contain code), e.g., for all \enquote{include files} or
+% all \enquote{packages},
+% and there are also hooks that are specific to a single file,
+% e.g., do something after the package \texttt{foo.sty} has been
+% loaded.
+%
+%
+% \subsection{General hooks for file reading}
+% \label{sec:general-file-hooks}
+%
+% There are four hooks that are called for each file that is read
+% using document-level commands such as \cs{input}, \cs{include},
+% \cs{usepackage}, etc. They are not called for files read using
+% internal low-level methods, such as \cs{@input} or \cs{openin}.
+%
+% \begin{variable}{file/before,file/before/...,
+% file/after/...,file/after,
+% }
+% These are:
+% \begin{description}
+% \item[\texttt{file/before}, \texttt{file/before/\meta{file-name}}]
+%
+% These hooks are executed in that order just before the file is
+% loaded for reading. The code of the first hook is used is used
+% with every file, while the second is executed only for the
+% file with matching \meta{file-name} allowing you to specify
+% code that only applies to one file.
+%
+% \item[\texttt{file/after/\meta{file-name}}, \texttt{file/after}]
+%
+% These hooks are after the file with name \meta{file-name} has
+% been fully consumed. The order is swapped (the specific one
+% comes first) so that the \texttt{before} and \texttt{after}
+% hooks nest properly, which is important if any of them involve
+% grouping (e.g., contain environments, for example).
+% furthermore both hooks are reversed hooks to support correct
+% nesting of different packages add code to both
+% \texttt{/before} and \texttt{/after} hooks.
+%
+% \end{description}
+% \end{variable}
+%
+%
+% So the overall sequence of hook processing for any file read
+% through the user interface commands of \LaTeX{} is:
+%
+% \begin{tabbing}
+% mm\=mm\=mm\=mm\=\kill
+% \>\cs{UseHook}\marg{\hook{file/before}} \\
+% \>\cs{UseHook}\marg{\hook{file/before/\meta{file name}}} \\
+% \>\> \meta{file contents} \\
+% \>\cs{UseHook}\marg{\hook{file/after/\meta{file name}}} \\
+% \>\cs{UseHook}\marg{\hook{file/after}}
+% \end{tabbing}
+%
+% \fmi{With a higher-level interface that doesn't matter, but it
+% is a bit weird, if you use \cs{AddToHook} or \cs{hook_gput:nnn}
+% directly, so I guess that has to be done differently!}
+%
+% The file hooks only refer to the file by its name and extension,
+% so the \meta{file name} should be the file name as it is on the
+% filesystem with extension (if any) and without paths. Different
+% from \cs{input} and similar commands, for hooks the \texttt{.tex}
+% extension is not assumed, so \texttt{.tex} files must also be given
+% with their extension.
+% Files within subfolders should also be addressed by their name and
+% extension only.
+%
+% Extensionless files also work, and should then be given without
+% extension. Note however that \TeX{} prioritizes \texttt{.tex}
+% files, so if two files \texttt{foo} and \texttt{foo.tex} exist in
+% the search path, only the latter will be seen.
+%
+% When a file is input, the \meta{file name} is available in
+% \cs{CurrentFile}, which is then used when accessing the
+% \hook{file/before/\meta{file name}} and
+% \hook{file/after/\meta{file name}}.
+%
+% \begin{variable}{\CurrentFile}
+% The name of the file about to be read (or just finished) is
+% available to the hooks through \cs{CurrentFile} (there is no
+% \texttt{expl3} name for it for now). The file is always provided
+% with its extension, i.e., how it appears on your hard drive, but
+% without any specified path to it. For example,
+% \verb=\input{sample}= and \verb=\input{app/sample.tex}= would
+% both have \cs{CurrentFile} being \texttt{sample.tex}.
+% \end{variable}
+%
+% \begin{variable}{\CurrentFilePath}
+% The path to the current file (complement to \cs{CurrentFile}) is
+% available in \cs{CurrentFilePath} if needed.
+% The paths returned in \cs{CurrentFilePath} are only user paths,
+% given through \cs{input@path} (or \pkg{expl3}'s equivalent
+% \cs{l_file_search_path_seq}) or by directly typing in the path
+% in the \cs{input} command or equivalent. Files located by
+% \texttt{kpsewhich} get the path added internally by the \TeX{}
+% implementation, so at the macro level it looks as if the file were
+% in the current folder, so the path in \cs{CurrentFilePath} is empty
+% in these cases (package and class files, mostly).
+% \end{variable}
+%
+% \subsection{Hooks for package and class files}
+%
+% Commands to load package and class files (e.g., \cs{usepackage},
+% \cs{RequirePackage}, \cs{LoadPackageWithOptions}, etc.) offer the
+% hooks from section~\ref{sec:general-file-hooks} when they are
+% used to load a package or class file, e.g.,
+% \texttt{file/after/array.sty} would be called after the
+% \pkg{array} package got loaded. But as packages and classes form as special group
+% of files, there are some additional hooks available that only
+% apply when a package or class is loaded.
+%
+%
+% \begin{variable}{
+% package/before,package/after,
+% package/before/...,package/after/...,
+% class/before,class/after,
+% class/before/...,class/after/...,
+% }
+% These are:
+% \begin{description}
+% \item[\texttt{package/before}, \texttt{package/after}]
+%
+% These hooks are called for each package being loaded.
+%
+% \item[\texttt{package/before/\meta{name}},
+% \texttt{package/after/\meta{name}}]
+%
+% These hooks are additionally called if the package name is
+% \meta{name} (without extension).
+%
+% \item[\texttt{class/before}, \texttt{class/after}]
+%
+% These hooks are called for each class being loaded.
+%
+% \item[\texttt{class/before/\meta{name}}, \texttt{class/after/\meta{name}}]
+%
+% These hooks are additionally called if the class name is
+% \meta{name} (without extension).
+%
+% \end{description}
+% \end{variable}
+% All \hook{/after} hooks are implemented as reversed hooks.
+%
+% \noindent The overall sequence of execution for \cs{usepackage}
+% and friends is therefore:
+% \begin{tabbing}
+% mm\=mm\=mm\=mm\=\kill
+% \>\cs{UseHook}\marg{\hook{package/before}} \\
+% \>\cs{UseHook}\marg{\hook{package/before/\meta{package name}}} \\[5pt]
+% \>\>\cs{UseHook}\marg{\hook{file/before}} \\
+% \>\>\cs{UseHook}\marg{\hook{file/before/\meta{package name}.sty}} \\
+% \>\>\> \meta{package contents} \\
+% \>\>\cs{UseHook}\marg{\hook{file/after/\meta{package name}.sty}} \\
+% \>\>\cs{UseHook}\marg{\hook{file/after}} \\[5pt]
+% \>\>\emph{code from \cs{AtEndOfPackage} if
+% used inside the package} \\[5pt]
+% \>\cs{UseHook}\marg{\hook{package/after/\meta{package name}}} \\
+% \>\cs{UseHook}\marg{\hook{package/after}}
+% \end{tabbing}
+% and similar for class file loading, except that \texttt{package/}
+% is replaced by \texttt{class/} and \cs{AtEndOfPackage} by
+% \cs{AtEndOfClass}.
+%
+% If a package or class is not loaded (or it was loaded before the
+% hooks were set) none of the hooks are executed!
+%
+% \subsection{Hooks for \cs{include} files}
+%
+% To manage \cs{include} files, \LaTeX{} issues a \cs{clearpage}
+% before and after loading such a file. Depending on the use case
+% one may want to execute code before or after these
+% \cs{clearpage}s especially for the one that is issued at the end.
+%
+% Executing code before the final \cs{clearpage}, means that the
+% code is processed while the last page of the included material is
+% still under construction. Executing code after it means that all
+% floats from inside the include file are placed (which
+% might have added further pages) and the final page has finished.
+%
+% Because of these different scenarios we offer hooks in three
+% places.\footnote{If you want to execute code before the first
+% \cs{clearpage} there is no need to use a hook---you can write it
+% directly in front of the \cs{include}.}
+% None of the hooks are executed when an \cs{include} file is
+% bypassed because of an \cs{includeonly} declaration. They are,
+% however, all executed if \LaTeX{} makes an attempt to load the
+% \cs{include} file (even if it doesn't exist and all that happens
+% is \enquote{\texttt{No file \meta{filename}.tex}}).
+%
+%
+% \begin{variable}{include/before,include/before/...,
+% include/end,include/end/...,
+% include/after,include/after/...,
+% }
+% These are:
+% \begin{description}
+%
+% \item[\texttt{include/before}, \texttt{include/before/\meta{name}}]
+%
+% These hooks are executed one after another after the initial
+% \cs{clearpage} and after \texttt{.aux} file is changed to use
+% \texttt{\meta{name}.aux}, but before the
+% \texttt{\meta{name}.tex} file is loaded. In other words they are executed
+% at the very beginning of the first page of the \cs{include}
+% file.
+%
+%
+% \item[\texttt{include/end/\meta{name}}, \texttt{include/end}]
+%
+% These hooks are executed (in that order) after \LaTeX{} has
+% stopped reading from the \cs{include} file, but before it has
+% issued a \cs{clearpage} to output any deferred floats.
+%
+%
+% \item[\texttt{include/after/\meta{name}}, \texttt{include/after}]
+%
+% These hooks are executed (in that order) after \LaTeX{} has
+% issued the \cs{clearpage} but before is has switched back
+% writing to the main \texttt{.aux} file. Thus technically we are
+% still inside the \cs{include} and if the hooks generate any
+% further typeset material including anything that writes to the
+% \texttt{.aux} file, then it would be considered part of the
+% included material and bypassed if it is not loaded because of
+% some \cs{includeonly} statement.\footnotemark
+%
+% \end{description}
+% \end{variable}\footnotetext{For that reason
+% another \cs{clearpage} is executed after these hooks which
+% normally does nothing, but starts a new page if further material
+% got added this way.}
+%
+% \subsection{High-level interfaces for \LaTeX{}}
+%
+% We do not provide any high-level \LaTeX{} commands (like
+% \pkg{filehook} or \pkg{scrlfile} do) but think that for package
+% writers the commands from for hook management are sufficient.
+%
+% \subsection{A sample package for structuring the log output}
+%
+% As an application we provide the package \pkg{structuredlog} that
+% adds lines to the \texttt{.log} when a file is opened and closed
+% for reading keeping track of nesting level es well.
+% For example, for the current document it adds the lines
+%\begin{verbatim}
+% = (LEVEL 1 START) t1lmr.fd
+% = (LEVEL 1 STOP) t1lmr.fd
+% = (LEVEL 1 START) supp-pdf.mkii
+% = (LEVEL 1 STOP) supp-pdf.mkii
+% = (LEVEL 1 START) nameref.sty
+% == (LEVEL 2 START) refcount.sty
+% == (LEVEL 2 STOP) refcount.sty
+% == (LEVEL 2 START) gettitlestring.sty
+% == (LEVEL 2 STOP) gettitlestring.sty
+% = (LEVEL 1 STOP) nameref.sty
+% = (LEVEL 1 START) ltfilehook-doc.out
+% = (LEVEL 1 STOP) ltfilehook-doc.out
+% = (LEVEL 1 START) ltfilehook-doc.out
+% = (LEVEL 1 STOP) ltfilehook-doc.out
+% = (LEVEL 1 START) ltfilehook-doc.hd
+% = (LEVEL 1 STOP) ltfilehook-doc.hd
+% = (LEVEL 1 START) ltfilehook.dtx
+% == (LEVEL 2 START) ot1lmr.fd
+% == (LEVEL 2 STOP) ot1lmr.fd
+% == (LEVEL 2 START) omllmm.fd
+% == (LEVEL 2 STOP) omllmm.fd
+% == (LEVEL 2 START) omslmsy.fd
+% == (LEVEL 2 STOP) omslmsy.fd
+% == (LEVEL 2 START) omxlmex.fd
+% == (LEVEL 2 STOP) omxlmex.fd
+% == (LEVEL 2 START) umsa.fd
+% == (LEVEL 2 STOP) umsa.fd
+% == (LEVEL 2 START) umsb.fd
+% == (LEVEL 2 STOP) umsb.fd
+% == (LEVEL 2 START) ts1lmr.fd
+% == (LEVEL 2 STOP) ts1lmr.fd
+% == (LEVEL 2 START) t1lmss.fd
+% == (LEVEL 2 STOP) t1lmss.fd
+% = (LEVEL 1 STOP) ltfilehook.dtx
+%\end{verbatim}
+% Thus if you inspect an issue in the \texttt{.log} it is easy to
+% figure out in which file it occurred, simply by searching back for
+% \texttt{LEVEL} and if it is a \texttt{STOP} then remove 1 from
+% the level value and search further for \texttt{LEVEL} with that value
+% which should then be the \texttt{START} level of the file you are in.
+%
+% \StopEventually{\setlength\IndexMin{200pt} \PrintIndex }
+%
+%
+% \section{The Implementation}
+% \begin{macrocode}
+%<*2ekernel>
+% \end{macrocode}
+%
+% \subsection{\pkg{expl3} helpers}
+%
+% \begin{macrocode}
+%<@@=filehook>
+% \end{macrocode}
+%
+% \begin{macro}{\CurrentFile,\CurrentFilePath}
+% User-level macros that hold the current file name and file path.
+% These are used internally as well because the code takes care to
+% protect against a possible redefinition of these macros in the loaded
+% file (it's necessary anyway to make hooks work with nested
+% \cs{input}).
+% \begin{macrocode}
+\def\CurrentFile{}
+\def\CurrentFilePath{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_internal_tl}
+% \begin{macro}{\@filehook@set@curr@file,\@@_normalise_file_name:n}
+% When inputting a file, \cs{@filehook@set@curr@file} does a file
+% lookup (in \cs{input@path} and \cs{l_file_search_path_seq}) and
+% returns the actual file name (\meta{base} plus \meta{ext}) in
+% \cs{CurrentFile}. Only the base and extension are returned,
+% regardless of the input (both \texttt{path/to/file.tex} and
+% \texttt{file.tex} end up as \texttt{file.tex} in \cs{CurrentFile}).
+% The path is returned in \cs{CurrentFilePath}, in case it's needed.
+% \cs{CurrentFile} is then used to run the file hooks with
+% \texttt{file/before/\cs{CurrentFile}} and
+% \texttt{file/after/\cs{CurrentFile}}.
+% \begin{macrocode}
+\ExplSyntaxOn
+\tl_new:N \l_@@_internal_tl
+\cs_new_protected:Npn \@filehook@set@curr@file #1
+ { \exp_args:NV \@@_normalise_file_name:n #1 }
+\cs_new_protected:Npn \@@_normalise_file_name:n #1
+ {
+ \file_if_exist:nTF {#1}
+ {
+ \exp_args:Nx \file_parse_full_name:nNNN
+ { \file_full_name:n {#1} }
+ }
+ { \file_parse_full_name:nNNN {#1} }
+ \CurrentFilePath \CurrentFile \l_@@_internal_tl
+ \tl_set:Nx \CurrentFile { \CurrentFile \l_@@_internal_tl }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\g_@@_input_file_seq}
+% \begin{macro}{\@filehook@file@push,\@filehook@file@pop}
+% \begin{macro}{\@@_file_pop_assign:nn}
+% Yet another stack, to keep track of \cs{CurrentFile} and
+% \cs{CurrentFilePath} with nested \cs{input}s. At the beginning of
+% \cs{InputIfFileExists}, the current value of \cs{CurrentFilePath}
+% and \cs{CurrentFile} is pushed to \cs{g_@@_input_file_seq}, and
+% at the end, it is popped and the value reassigned.
+% \cs{IfFileExists} does \cs{set@curr@file} internally, which changes
+% \cs{CurrentFile}, so \cs{@filehook@file@push} has to be executed
+% before \cs{IfFileExists}.
+% \begin{macrocode}
+\seq_new:N \g_@@_input_file_seq
+\cs_new_protected:Npn \@filehook@file@push
+ {
+ \seq_gpush:Nx \g_@@_input_file_seq
+ { { \CurrentFilePath } { \CurrentFile } }
+ }
+\cs_new_protected:Npn \@filehook@file@pop
+ {
+ \seq_gpop:NNTF \g_@@_input_file_seq \l_@@_internal_tl
+ { \exp_after:wN \@@_file_pop_assign:nn \l_@@_internal_tl }
+ { \ERROR_should_not_happen }
+ }
+\cs_new_protected:Npn \@@_file_pop_assign:nn #1 #2
+ {
+ \tl_set:Nn \CurrentFilePath {#1}
+ \tl_set:Nn \CurrentFile {#2}
+ }
+\ExplSyntaxOff
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsection{Declaring the file-related hooks}
+%
+% All hooks starting with \texttt{file/} \texttt{include/},
+% \texttt{class/} or \texttt{package/} are generic and will be
+% allocated if code is added to them. Thus there is no need to
+% explicitly declare any hook in the code below.
+%
+% Furthermore, those named \texttt{.../after} or \texttt{.../end} are
+% automatically declared as reversed hooks if filled with code, so this
+% is also automatically taken care of.
+%
+% \subsection{Patching \LaTeX{} commands (need proper integration later)}
+%
+% Most of what we have to do is adding \cs{UseHook} into several
+% \LaTeXe{} core commands, which is done for now by patching them.
+% \begin{macrocode}
+%<@@=>
+% \end{macrocode}
+%
+% \begin{macro}{\InputIfFileExists}
+% \cs{InputIfFileExists} loads any file if it is available so we
+% have to add the hooks \texttt{file/before} and
+% \texttt{file/after} in the right places. If the file doesn't
+% exist no hooks should be executed.
+% \begin{macrocode}
+\let\InputIfFileExists\@undefined
+\DeclareRobustCommand \InputIfFileExists[3]{%
+ \@filehook@file@push
+ \IfFileExists{#1}%
+ {%
+% \end{macrocode}
+% If the file exists then \cs{@curr@file} holds its name. But we
+% can't rely on that still being true after the file has been
+% processed. Thus for using the name in the file hooks we need to
+% preserve the name and then restored it for the
+% \texttt{file/after/...} hook.
+%
+% The hook always refers to the \emph{actual} file that will be
+% operated on, regardless of how the user had it written in the
+% document. \pkg{expl3}'s \cs{file_full_name:n} normalizes the file
+% name (to factor out differences in the |.tex| extension), and
+% then does a file lookup to take into account a possible path from
+% \cs{l_file_search_path_seq} and \cs{input@path}. However only
+% the file name and extension are returned so that file hooks can
+% refer to the file by their name only. The path to the file is
+% returned in \cs{CurrentFilePath}.
+% \begin{macrocode}
+ \edef\reserved@a{\@filef@und
+ \def\noexpand\CurrentFile{\CurrentFile}%
+ \def\noexpand\CurrentFilePath{\CurrentFilePath}%
+ }%
+ \expandafter\@swaptwoargs\expandafter
+ {\reserved@a}%
+ {%
+ #2%
+ \@addtofilelist{#1}%
+ \UseHook{file/before}%
+% \end{macrocode}
+% The current file name is available in \cs{@curr@file} so we use
+% that in the specific hook.
+% \begin{macrocode}
+ \UseHook{file/before/\CurrentFile}%
+ \@@input
+ }%
+% \end{macrocode}
+% And it is restored here so we can use it once more.
+% \begin{macrocode}
+ \UseHook{file/after/\CurrentFile}%
+ \UseHook{file/after}%
+ \@filehook@file@pop
+ }%
+ {\@filehook@file@pop #3}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\set@curr@file}
+% Now we just hook into \cs{set@curr@file} to add
+% \cs{@filehook@set@curr@file} at the end, after \cs{@curr@file} is
+% set.
+% \begin{macrocode}
+\def\set@curr@file#1{%
+ \begingroup
+ \escapechar\m@ne
+ \xdef\@curr@file{%
+ \expandafter\expandafter\expandafter\unquote@name
+ \expandafter\expandafter\expandafter{%
+ \expandafter\string
+ \csname\@firstofone#1\@empty\endcsname}}%
+ \endgroup
+ \@filehook@set@curr@file{\@curr@file}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\load@onefilewithoptions}
+% This macro is used when loading packages or classes.
+% \begin{macrocode}
+\def\load@onefilewithoptions#1[#2][#3]#4{%
+ \@pushfilename
+ \xdef\@currname{#1}%
+ \global\let\@currext#4%
+ \let\CurrentOption\@empty
+ \@reset@ptions
+ \makeatletter
+ \def\reserved@a{%
+ \@ifl@aded\@currext{#1}%
+ {\@if@ptions\@currext{#1}{#2}{}%
+ {\@latex@error
+ {Option clash for \@cls@pkg\space #1}%
+ {The package #1 has already been loaded
+ with options:\MessageBreak
+ \space\space[\@ptionlist{#1.\@currext}]\MessageBreak
+ There has now been an attempt to load it
+ with options\MessageBreak
+ \space\space[#2]\MessageBreak
+ Adding the global options:\MessageBreak
+ \space\space
+ \@ptionlist{#1.\@currext},#2\MessageBreak
+ to your \noexpand\documentclass declaration may fix this.%
+ \MessageBreak
+ Try typing \space <return> \space to proceed.}}}%
+ {\@pass@ptions\@currext{#2}{#1}%
+ \global\expandafter
+ \let\csname ver@\@currname.\@currext\endcsname\@empty
+ \expandafter\let\csname\@currname.\@currext-h@@k\endcsname\@empty
+ \InputIfFileExists
+ {\@currname.\@currext}%
+ {%
+%-----------------------------------------
+% \end{macrocode}
+% When the current extension is \cs{@pkgextension} we are loading a
+% package otherwise, if it is \cs{@clsextension}, a class, so
+% depending on that we execute different hooks. If the extension is
+% neither, then it is another type of file without special hooks.
+% \begin{macrocode}
+ \ifx\@currext\@pkgextension
+ \UseHook{package/before}%
+ \UseHook{package/before/\@currname}%
+ \else
+ \ifx\@currext\@clsextension
+ \UseHook{class/before}%
+ \UseHook{class/before/\@currname}%
+ \fi
+ \fi
+% \end{macrocode}
+% The value of \cs{CurrentFile} holds during \cs{InputIfFileExists},
+% so the hooks above have that available for using. However at this
+% point \cs{CurrentFile} is reset to its previous value by
+% \cs{@filehook@file@pop} because it doesn't know that we'll have
+% more hooks ahead. So here (still in the \meta{true} branch of
+% \cs{InputIfFileExists}, right after actually reading the file in)
+% we'll cheat: use \cs{@filehook@file@push} once more, so there are
+% two entries for the current file in the name stack, so that when
+% \cs{InputIfFileExists} pops it, there's still one (identical) left.
+% \begin{macrocode}
+ \@filehook@file@push
+%-----------------------------------------
+ }%
+ {\@missingfileerror\@currname\@currext}%
+ \let\@unprocessedoptions\@@unprocessedoptions
+ \csname\@currname.\@currext-h@@k\endcsname
+ \expandafter\let\csname\@currname.\@currext-h@@k\endcsname
+ \@undefined
+%-----------------------------------------
+% \end{macrocode}
+% And same procedure, James, when we are finished loading, except
+% that the hook order is now reversed.
+% \begin{macrocode}
+ \ifx\@currext\@pkgextension
+ \UseHook{package/after/\@currname}%
+ \UseHook{package/after}%
+ \else
+ \ifx\@currext\@clsextension
+ \UseHook{class/after/\@currname}%
+ \UseHook{class/after}%
+ \fi
+ \fi
+% \end{macrocode}
+% Now here we do \cs{@filehook@file@pop} to restore the
+% \cs{CurrentFile} before this file being loaded and fix what we've
+% done in the stack right above.
+% \begin{macrocode}
+ \@filehook@file@pop
+%-----------------------------------------
+ \@unprocessedoptions}%
+ \@ifl@ter\@currext{#1}{#3}{}%
+ {\@latex@warning@no@line
+ {You have requested,\on@line,
+ version\MessageBreak
+ `#3' of \@cls@pkg\space #1,\MessageBreak
+ but only version\MessageBreak
+ `\csname ver@#1.\@currext\endcsname'\MessageBreak
+ is available}}%
+ \ifx\@currext\@clsextension\let\LoadClass\@twoloadclasserror\fi
+ \@popfilename
+ \@reset@ptions}%
+ \reserved@a}
+% \end{macrocode}
+%
+% The code for this macro has changed between 2020/02/02 and
+% 2020/10/01 so the never version is this:
+% \begin{macrocode}
+\@ifl@t@r\fmtversion{2020/10/01}
+{%
+\def\load@onefilewithoptions#1[#2][#3]#4{%
+ \@pushfilename
+ \xdef\@currname{#1}%
+ \global\let\@currext#4%
+ \let\CurrentOption\@empty
+ \@reset@ptions
+ \makeatletter
+ \def\reserved@a{%
+ \@ifl@aded\@currext{#1}%
+ {\@if@ptions\@currext{#1}{#2}{}%
+ {\@latex@error
+ {Option clash for \@cls@pkg\space #1}%
+ {The package #1 has already been loaded
+ with options:\MessageBreak
+ \space\space[\@ptionlist{#1.\@currext}]\MessageBreak
+ There has now been an attempt to load it
+ with options\MessageBreak
+ \space\space[#2]\MessageBreak
+ Adding the global options:\MessageBreak
+ \space\space
+ \@ptionlist{#1.\@currext},#2\MessageBreak
+ to your \noexpand\documentclass declaration may fix this.%
+ \MessageBreak
+ Try typing \space <return> \space to proceed.}}}%
+ {\@pass@ptions\@currext{#2}{#1}%
+ \global\expandafter
+ \let\csname ver@\@currname.\@currext\endcsname\@empty
+ \expandafter\let\csname\@currname.\@currext-h@@k\endcsname\@empty
+ \InputIfFileExists
+ {\@currname.\@currext}%
+ {%
+%-----------------------------------------
+ \ifx\@currext\@pkgextension
+ \UseHook{package/before}%
+ \UseHook{package/before/\@currname}%
+ \else
+ \ifx\@currext\@clsextension
+ \UseHook{class/before}%
+ \UseHook{class/before/\@currname}%
+ \fi
+ \fi
+ \@filehook@file@push
+%-----------------------------------------
+ }%
+ {\@missingfileerror\@currname\@currext}%
+ \expandafter\let\csname unprocessedoptions-\@currname.\@currext\endcsname
+ \@@unprocessedoptions
+ \csname\@currname.\@currext-h@@k\endcsname
+ \expandafter\let\csname\@currname.\@currext-h@@k\endcsname
+ \@undefined
+ \ifx\@unprocessedoptions\relax
+ \let\@unprocessedoptions\@undefined
+ \else
+ \csname unprocessedoptions-\@currname.\@currext\endcsname
+ \fi
+ \expandafter\let
+ \csname unprocessedoptions-\@currname.\@currext\endcsname
+ \@undefined
+%-----------------------------------------
+ \ifx\@currext\@pkgextension
+ \UseHook{package/after/\@currname}%
+ \UseHook{package/after}%
+ \else
+ \ifx\@currext\@clsextension
+ \UseHook{class/after/\@currname}%
+ \UseHook{class/after}%
+ \fi
+ \fi
+ \@filehook@file@pop
+%-----------------------------------------
+ }%
+ \@ifl@ter\@currext{#1}{#3}{}%
+ {\@latex@warning@no@line
+ {You have requested,\on@line,
+ version\MessageBreak
+ `#3' of \@cls@pkg\space #1,\MessageBreak
+ but only version\MessageBreak
+ `\csname ver@#1.\@currext\endcsname'\MessageBreak
+ is available}}%
+ \ifx\@currext\@clsextension\let\LoadClass\@twoloadclasserror\fi
+ \@popfilename
+ \@reset@ptions}%
+ \reserved@a}
+}{}%
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \begin{macro}{\@include}
+% \begin{macrocode}
+\def\@include#1 {%
+ \clearpage
+ \if@filesw
+ \immediate\write\@mainaux{\string\@input{#1.aux}}%
+ \fi
+ \@tempswatrue
+ \if@partsw
+ \@tempswafalse
+ \edef\reserved@b{#1}%
+ \@for\reserved@a:=\@partlist\do
+ {\ifx\reserved@a\reserved@b\@tempswatrue\fi}%
+ \fi
+ \if@tempswa
+ \let\@auxout\@partaux
+ \if@filesw
+ \immediate\openout\@partaux #1.aux
+ \immediate\write\@partaux{\relax}%
+ \fi
+%-----------------------------------------
+% \end{macrocode}
+% First we need to fix \cs{CurrentFile}, because due the pesky
+% space-delimited \cs{@include}, \cs{CurrentFile} contains the
+% \cs{include}'d file with a space. To fix that, we re-do
+% \cs{set@curr@file}. The 2020/10/01 release doesn't need this as
+% \cs{include} was changed to do \cs{set@curr@file} on the correct
+% file name, rather than one with a trailing space.
+% \begin{macrocode}
+ \set@curr@file{#1}%
+% \end{macrocode}
+% Execute the \texttt{before} hooks just after we switched the
+% \texttt{.aux} file \ldots
+% \begin{macrocode}
+ \UseHook{include/before}%
+ \UseHook{include/before/#1}%
+%-----------------------------------------
+ \@input@{#1.tex}%
+% \end{macrocode}
+% \ldots{} then \texttt{end} hooks \ldots
+% \begin{macrocode}
+%-----------------------------------------
+ \UseHook{include/end/#1}%
+ \UseHook{include/end}%
+%-----------------------------------------
+ \clearpage
+% \end{macrocode}
+% \ldots{} and after the \cs{clearpage} the \texttt{after} hooks
+% followed by another \cs{clearpage} just in case new material got
+% added (after all we need to be in well defined state after the
+% \cs{include}).
+% \begin{macrocode}
+%-----------------------------------------
+ \UseHook{include/after/#1}%
+ \UseHook{include/after}%
+% \end{macrocode}
+% The additional \cs{clearpage} is needed to ensure that switching
+% the \texttt{.aux} files happen at a defined point even if the
+% above hooks add further material.
+% \begin{macrocode}
+ \clearpage
+%-----------------------------------------
+ \@writeckpt{#1}%
+ \if@filesw
+ \immediate\closeout\@partaux
+ \fi
+ \else
+ \deadcycles\z@
+ \@nameuse{cp@#1}%
+ \fi
+ \let\@auxout\@mainaux
+}
+% \end{macrocode}
+%
+% The code for this macro has changed between 2020/02/02 and
+% 2020/10/01 so the never version is this:
+% \begin{macrocode}
+\@ifl@t@r\fmtversion{2020/10/01}
+{%
+\def\@include#1 {%
+ \clearpage
+ \if@filesw
+ \immediate\write\@mainaux{\string\@input{"#1.aux"}}%
+ \fi
+ \@tempswatrue
+ \if@partsw
+ \@tempswafalse
+ \edef\reserved@b{#1}%
+ \@for\reserved@a:=\@partlist\do
+ {\ifx\reserved@a\reserved@b\@tempswatrue\fi}%
+ \fi
+ \if@tempswa
+ \let\@auxout\@partaux
+ \if@filesw
+ \immediate\openout\@partaux "#1.aux"
+ \immediate\write\@partaux{\relax}%
+ \fi
+%-----------------------------------------
+ \UseHook{include/before}%
+ \UseHook{include/before/#1}%
+%-----------------------------------------
+ \@input@{#1.tex}%
+%-----------------------------------------
+ \UseHook{include/end/#1}%
+ \UseHook{include/end}%
+%-----------------------------------------
+ \clearpage
+%-----------------------------------------
+ \UseHook{include/after/#1}%
+ \UseHook{include/after}%
+ \clearpage
+%-----------------------------------------
+ \@writeckpt{#1}%
+ \if@filesw
+ \immediate\closeout\@partaux
+ \fi
+ \else
+ \deadcycles\z@
+ \@nameuse{cp@#1}%
+ \fi
+ \let\@auxout\@mainaux}
+}{}
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{High-level interfaces for \LaTeX{}}
+%
+% None so far and the general feeling for now is that the hooks are
+% enough. Packages like \pkg{filehook}, etc., may use them to set
+% up their interfaces (samples are given below) but for the now the
+% kernel will not provide any.
+%
+%
+%
+% \begin{macrocode}
+%</2ekernel>
+% \end{macrocode}
+%
+%
+%
+% \section{Package emulation for compatibility}
+%
+%
+% \subsection{Package \pkg{filehook} emulation}
+%
+% This is a partial implementation of the \pkg{filehook}
+% interfaces. It is only meant for guidance in case that package
+% gets updated to use the hook management.
+%
+% Not implemented are:
+%\begin{verbatim}
+% \AtBeginOfFiles
+% \AtEndOfFiles
+% \AtBeginOfInputs
+% \AtEndOfInputs
+% \AtBeginOfInputFile
+% \AtEndOfInputFile
+%\end{verbatim}
+%
+% \begin{macrocode}
+%<*filehook-draft>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcommand\AtBeginOfEveryFile [1]
+ {\AddToHook{file/before}{#1}}
+\newcommand\AtEndOfEveryFile [1]
+ {\AddToHook{file/after}{#1}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcommand\AtBeginOfIncludes [1]
+ {\AddToHook{include/before}{#1}}
+\newcommand\AtEndOfIncludes [1]
+ {\AddToHook{include/end}{#1}}
+\newcommand\AfterIncludes [1]
+ {\AddToHook{include/after}{#1}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcommand\AtBeginOfPackages [1]
+ {\AddToHook{package/before}{#1}}
+\newcommand\AtEndOfPackages [1]
+ {\AddToHook{package/after}{#1}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcommand\AtBeginOfClasses [1]
+ {\AddToHook{class/before}{#1}}
+\newcommand\AtEndOfClasses [1]
+ {\AddToHook{class/after}{#1}}
+% \end{macrocode}
+%
+% For normal files we drop the \texttt{.tex} extension for now:
+% \begin{macrocode}
+\newcommand\AtBeginOfFile [2]
+ {\AddToHook{file/before/#1}{#2}}
+\newcommand\AtEndOfFile [2]
+ {\AddToHook{file/after/#1}{#2}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\DeclareDocumentCommand \AtBeginOfPackageFile {smm}
+ {\IfBooleanTF{#1}%
+ {\@ifpackageloaded{#2}%
+ {#3}%
+ {\AddToHook{package/before/#2}{#3}}}%
+ {\AddToHook{package/before/#2}{#3}}%
+ }
+\DeclareDocumentCommand \AtEndOfPackageFile {smm}
+ {\IfBooleanTF{#1}%
+ {\@ifpackageloaded{#2}%
+ {#3}%
+ {\AddToHook{package/after/#2}{#3}}}%
+ {\AddToHook{package/after/#2}{#3}}%
+ }
+% \end{macrocode}
+%
+% Are the * forms here of any use? I know they are use 3--4 times
+% on CTAN but I wonder if those are real or mistaken usages.
+% \begin{macrocode}
+\DeclareDocumentCommand \AtBeginOfClassFile {smm}
+ {\IfBooleanTF{#1}%
+ {\@ifclassloaded{#2}%
+ {#3}%
+ {\AddToHook{class/before/#2}{#3}}}%
+ {\AddToHook{class/before/#2}{#3}}%
+ }
+\DeclareDocumentCommand \AtEndOfClassFile {smm}
+ {\IfBooleanTF{#1}%
+ {\@ifclassloaded{#2}%
+ {#3}%
+ {\AddToHook{class/after/#2}{#3}}}%
+ {\AddToHook{class/after/#2}{#3}}%
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcommand\AtBeginOfIncludeFile [2]
+ {\AddToHook{include/before/#1}{#2}}
+\newcommand\AtEndOfIncludeFile [2]
+ {\AddToHook{include/end/#1}{#2}}
+\newcommand\AfterIncludeFile [2]
+ {\AddToHook{include/after/#1}{#2}}
+% \end{macrocode}
+%
+%
+% This is missing some interfaces so disabling the package isn't
+% really correct, but then this code above is not supposed to stay
+% like this anyway.
+% \begin{macrocode}
+\expandafter\let\csname ver@filehook.sty\endcsname\fmtversion
+\@namedef {ver@filehook.sty}{2020/10/01}
+% \end{macrocode}
+%
+%
+% \begin{macrocode}
+%</filehook-draft>
+% \end{macrocode}
+%
+%
+%
+%
+% \subsection{Package \pkg{scrlfile} emulation}
+%
+% This is a partial implementation of the \pkg{scrlfile}
+% interfaces. It is only meant for guidance in case that package
+% gets updated to use the hook management.
+%
+% \begin{macrocode}
+%<*scrlfile-draft>
+% \end{macrocode}
+%
+% I think this is roughly correct (using the \texttt{file/...}
+% hooks rather than the class or package hooks at least for the
+% \cs{After...} commands but it needs some further verification.
+%
+% The star and plus variants haven't been implemented so far, this
+% is only a rough draft.
+% \begin{macrocode}
+\newcommand\BeforeClass[2]
+ {\AddToHook{file/before/#1.cls}{#2}}
+\newcommand\AfterClass [2]
+ {\AddToHook{file/after/#1.cls}{#2}}
+\newcommand\AfterAtEndOfClass [2]
+ {\AddToHook{class/after/#1}{#2}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcommand\BeforePackage [2]
+ {\AddToHook{package/before/#1.sty}{#2}}
+\newcommand\AfterPackage [2]
+ {\AddToHook{file/after/#1.sty}{#2}}
+\newcommand\AfterEndOfPackage [2]
+ {\AddToHook{package/after/#1}{#2}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcommand\BeforeFile [2]
+ {%
+ \typeout{BeforeFile: #1!!!}%
+ \AddToHook{file/before/#1}{#2}}
+\newcommand\AfterFile [2]
+ {%
+ \typeout{AfterFile: #1!!!}%
+ \AddToHook{file/after/#1}{#2}}
+% \end{macrocode}
+%
+% This is missing some interfaces so disabling the package isn't
+% really correct, but then this code above is not supposed to stay
+% like this anyway.
+% \begin{macrocode}
+\expandafter\let\csname ver@scrlfile.sty\endcsname\fmtversion
+\@namedef {ver@scrlfile.sty}{2020/10/01}
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</scrlfile-draft>
+% \end{macrocode}
+%
+%
+%
+% \section{A sample package for structuring the log output}
+%
+% \begin{macrocode}
+%<*structuredlog>
+%<@@=filehook>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ProvidesExplPackage
+ {structuredlog}{\ltfilehookdate}{\ltfilehookversion}
+ {Structuring the TeX transcript file}
+% \end{macrocode}
+
+
+
+% \begin{macrocode}
+\int_new:N \g_@@_nesting_level_int
+% \end{macrocode}
+
+% \begin{macrocode}
+\tl_new:N \g_@@_nesting_prefix_tl
+\tl_gset:Nn \g_@@_nesting_prefix_tl { }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\AddToHook{file/before}{
+ \int_gincr:N \g_@@_nesting_level_int
+ \tl_gput_right:Nn\g_@@_nesting_prefix_tl {=}
+ \iow_term:x {
+ \g_@@_nesting_prefix_tl \space
+ ( LEVEL~ \int_use:N \g_@@_nesting_level_int \space START )~
+ \CurrentFile ^^J
+ }
+}
+% \end{macrocode}
+% We don't want to install the \hook{file/after} hook immediately,
+% because that would mean it is the first time executed when the
+% package finishes. We therefore put the declaration inside
+% \cs{AddToHookNext} so that it gets only installed when we have
+% left the package.
+% \begin{macrocode}
+\AddToHookNext{file/after}{
+ \AddToHook{file/after}{
+ \iow_term:x {
+ \g_@@_nesting_prefix_tl \space
+ ( LEVEL~ \int_use:N \g_@@_nesting_level_int \space STOP )~
+ \CurrentFile ^^J
+ }
+ \int_gdecr:N \g_@@_nesting_level_int
+ \tl_gset:Nx \g_@@_nesting_prefix_tl
+ {\exp_after:wN \use_none:n \g_@@_nesting_prefix_tl}
+ }
+}
+% \end{macrocode}
+%
+% We have to manually increment the level because now that we have
+% installed the code in \texttt{file/after} it gets decremented
+% when we leave the package without ever being incremented upon
+% entry.
+% \begin{macrocode}
+%\int_incr:N\g_@@_nesting_level_int
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</structuredlog>
+% \end{macrocode}
+
+% \Finale
+%
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\endinput
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
diff --git a/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx b/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx
index 8e9611d9180..60b6a23e5c2 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltfiles.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltfiles.dtx}
- [2020-05-05 v1.2g LaTeX Kernel (File Handling)]
+ [2020-06-05 v1.2h LaTeX Kernel (File Handling)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfiles.dtx}
@@ -234,14 +234,18 @@
% \changes{v0.9e}{1993/12/09}{Hook added}
% \begin{macrocode}
%</2ekernel>
-%<latexrelease>\IncludeInRelease{2017/04/15}%
-%<latexrelease> {\document}{Save language for hyphenation}%
+%<latexrelease>\IncludeInRelease{2020/06/05}%
+%<latexrelease> {\document}{Added hook to load l3backend code}%
%<*2ekernel|latexrelease>
% \end{macrocode}
% Cancel the |\begingroup| from |\begin|.
% \begin{macrocode}
\def\document{\endgroup
% \end{macrocode}
+% \changes{v1.2h}{2020/06/05}{Added hook to load \textsf{l3backend} code}
+% \begin{macrocode}
+ \@expl@sys@load@backend@@
+% \end{macrocode}
% If some options on |\documentclass| haven't been used by any
% package we will now give a warning since this is most certainly a
% misspelling.
@@ -406,6 +410,64 @@
\ignorespaces}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
+%<latexrelease>
+%<latexrelease>\IncludeInRelease{2017/04/15}%
+%<latexrelease> {\document}{Save language for hyphenation}%
+%<latexrelease>\def\document{\endgroup
+%<latexrelease> \ifx\@unusedoptionlist\@empty\else
+%<latexrelease> \@latex@warning@no@line{Unused global option(s):^^J%
+%<latexrelease> \@spaces[\@unusedoptionlist]}%
+%<latexrelease> \fi
+%<latexrelease> \@colht\textheight
+%<latexrelease> \@colroom\textheight \vsize\textheight
+%<latexrelease> \columnwidth\textwidth
+%<latexrelease> \@clubpenalty\clubpenalty
+%<latexrelease> \if@twocolumn
+%<latexrelease> \advance\columnwidth -\columnsep
+%<latexrelease> \divide\columnwidth\tw@ \hsize\columnwidth \@firstcolumntrue
+%<latexrelease> \fi
+%<latexrelease> \hsize\columnwidth \linewidth\hsize
+%<latexrelease> \begingroup\@floatplacement\@dblfloatplacement
+%<latexrelease> \makeatletter\let\@writefile\@gobbletwo
+%<latexrelease> \global \let \@multiplelabels \relax
+%<latexrelease> \@input{\jobname.aux}%
+%<latexrelease> \endgroup
+%<latexrelease> \if@filesw
+%<latexrelease> \immediate\openout\@mainaux\jobname.aux
+%<latexrelease> \immediate\write\@mainaux{\relax}%
+%<latexrelease> \fi
+%<latexrelease> \process@table
+%<latexrelease> \let\glb@currsize\@empty % Force math initialization.
+%<latexrelease> \normalsize
+%<latexrelease> \everypar{}%
+%<latexrelease> \ifx\normalsfcodes\@empty
+%<latexrelease> \ifnum\sfcode`\.=\@m
+%<latexrelease> \let\normalsfcodes\frenchspacing
+%<latexrelease> \else
+%<latexrelease> \let\normalsfcodes\nonfrenchspacing
+%<latexrelease> \fi
+%<latexrelease> \fi
+%<latexrelease> \ifx\document@default@language\m@ne
+%<latexrelease> \chardef\document@default@language\language
+%<latexrelease> \fi
+%<latexrelease> \@noskipsecfalse
+%<latexrelease> \let \@refundefined \relax
+%<latexrelease> \let\AtBeginDocument\@firstofone
+%<latexrelease> \@begindocumenthook
+%<latexrelease> \ifdim\topskip<1sp\global\topskip 1sp\relax\fi
+%<latexrelease> \global\@maxdepth\maxdepth
+%<latexrelease> \global\let\@begindocumenthook\@undefined
+%<latexrelease> \ifx\@listfiles\@undefined
+%<latexrelease> \global\let\@filelist\relax
+%<latexrelease> \global\let\@addtofilelist\@gobble
+%<latexrelease> \fi
+%<latexrelease> \gdef\do##1{\global\let ##1\@notprerr}%
+%<latexrelease> \@preamblecmds
+%<latexrelease> \global\let \@nodocument \relax
+%<latexrelease> \global\let\do\noexpand
+%<latexrelease> \ignorespaces}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease> {\document}{Save language for hyphenation}
%<latexrelease>\def\document{\endgroup
diff --git a/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx b/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx
index 56549507624..9089c8a7055 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltfinal.dtx
@@ -33,7 +33,7 @@
%<*driver>
% \fi
\ProvidesFile{ltfinal.dtx}
- [2019-10-02 v2.2 LaTeX Kernel (Final Settings)]
+ [2020-07-16 v2.2f LaTeX Kernel (Final Settings)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltfinal.dtx}
@@ -460,6 +460,14 @@
\fi
% \end{macrocode}
%
+% \changes{v2.2b}{2020/07/08}
+% {Add a last-minute hook for \textsf{expl3}}
+% At this stage, we can install any last-minute \textsf{expl3} set-up.
+% \begin{macrocode}
+\@expl@finalise@setup@@
+\def\@expl@finalise@setup@@{}
+% \end{macrocode}
+%
% This is as good a place as any to active a few Xe\TeX{}-specific
% settings
% \begin{macrocode}
@@ -1044,13 +1052,8 @@
% }{}
% \end{macrocode}
%
-% \subsection{Loading further extensions}
-%
% \changes{v2.2}{2019-10-02}{Load \textsf{ltexpl}}
-% Simply load further code: it's deliberately separate
-% \begin{macrocode}
-\input{ltexpl.ltx}
-% \end{macrocode}
+% \changes{v2.2a}{2020-06-04}{Load \textsf{ltexpl} in \texttt{ltdefns}}
%
% \subsection{Freeing Memory}
%
@@ -1124,14 +1127,6 @@
% \end{macro}
% \end{macro}
%
-% \subsection{Some last minute initializations \ldots}
-%
-% This initializes the 2020/02/02 extensions to NFSS after any changes
-% in the preamble.
-% \begin{macrocode}
-\AtBeginDocument{\reinstall@nfss@defs\init@series@setup}
-% \end{macrocode}
-%
%
%
% \subsection{Do some temporary work for pre-release}
@@ -1139,9 +1134,233 @@
% This is a good place to load code that hasn't yet been
% integrated into the other files \ldots
% \begin{macrocode}
-%\input ...
+%</2ekernel>
+%<*2ekernel|latexrelease>
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {\ShowHook}{The hook management}%
+\input lthooks.ltx
+\input ltshipout.ltx
+\input ltfilehook.ltx
+%</2ekernel|latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{0000/00/00}%
+%<latexrelease> {\ShowHook}{The hook management}%
+
+%<latexrelease>
+%<latexrelease>\DeclareRobustCommand*\begin[1]{%
+%<latexrelease> \@ifundefined{#1}%
+%<latexrelease> {\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
+%<latexrelease> {\def\reserved@a{\def\@currenvir{#1}%
+%<latexrelease> \edef\@currenvline{\on@line}%
+%<latexrelease> \csname #1\endcsname}}%
+%<latexrelease> \@ignorefalse
+%<latexrelease> \begingroup\@endpefalse\reserved@a}
+%<latexrelease>
+%<latexrelease>\@namedef{end }#1{%
+%<latexrelease> \csname end#1\endcsname\@checkend{#1}%
+%<latexrelease> \expandafter\endgroup\if@endpe\@doendpe\fi
+%<latexrelease> \if@ignore\@ignorefalse\ignorespaces\fi}
+%<latexrelease>
+%<latexrelease>\DeclareDocumentCommand \NewHook {m}{}
+%<latexrelease>\DeclareDocumentCommand \NewReversedHook {m}{}
+%<latexrelease>\DeclareDocumentCommand \NewMirroredHookPair {mm}{}
+%<latexrelease>
+%<latexrelease>\DeclareDocumentCommand \AddToHookNext {m+m}{}
+%<latexrelease>\DeclareDocumentCommand \RemoveFromHook {mo}{}
+%<latexrelease>\def \UseHook #1{}
+%<latexrelease>\def \UseOneTimeHook #1{}
+%<latexrelease>\def \ShowHook #1{}
+%<latexrelease>\let \DebugHookOn \@empty
+%<latexrelease>\let \DebugHookOff\@empty
+%<latexrelease>
+%<latexrelease>\DeclareDocumentCommand \DeclareHookRule {mmmm}{}
+%<latexrelease>\DeclareDocumentCommand \DeclareDefaultHookRule {mmm}{}
+%<latexrelease>\DeclareDocumentCommand \ClearHookRule {mmm}{}
+% \end{macrocode}
+% If the hook management is not provided we make the test for existence
+% false and the test for empty true in the hope that this is most
+% of the time reasonable. If not a package would need to guard
+% against running in an old kernel.
+% \begin{macrocode}
+%<latexrelease>\DeclareExpandableDocumentCommand \IfHookExistTF {mmm}{#3}
+%<latexrelease>\DeclareExpandableDocumentCommand \IfHookEmptyTF {mmm}{#2}
+%<latexrelease>
+%<latexrelease>\DeclareRobustCommand\AtBeginDocument{\g@addto@macro\@begindocumenthook}
+%<latexrelease>\DeclareRobustCommand\AtEndDocument{\g@addto@macro\@enddocumenthook}
+%<latexrelease>
+%<latexrelease>\let\AtBeginEnvironment \@undefined
+%<latexrelease>\let\AtEndEnvironment \@undefined
+%<latexrelease>\let\BeforeBeginEnvironment \@undefined
+%<latexrelease>\let\AfterEndEnvironment \@undefined
+%<latexrelease>
+%<latexrelease>\def\@pushfilename{%
+%<latexrelease> \@expl@push@filename@@
+%<latexrelease> \xdef\@currnamestack{%
+%<latexrelease> {\@currname}%
+%<latexrelease> {\@currext}%
+%<latexrelease> {\the\catcode`\@}%
+%<latexrelease> \@currnamestack}%
+%<latexrelease> \@expl@push@filename@aux@@}
+%<latexrelease>\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil
+%<latexrelease> \@expl@pop@filename@@}
+%<latexrelease>
+%<latexrelease>
+%<latexrelease>% next goes away again when etoolbox is updated ...
+%<latexrelease>\expandafter\let\csname ver@etoolbox.sty\endcsname\@undefined
+%<latexrelease>
+%<latexrelease>\def\document{\endgroup
+%<latexrelease> \@expl@sys@load@backend@@
+%<latexrelease> \ifx\@unusedoptionlist\@empty\else
+%<latexrelease> \@latex@warning@no@line{Unused global option(s):^^J%
+%<latexrelease> \@spaces[\@unusedoptionlist]}%
+%<latexrelease> \fi
+%<latexrelease> \@colht\textheight
+%<latexrelease> \@colroom\textheight \vsize\textheight
+%<latexrelease> \columnwidth\textwidth
+%<latexrelease> \@clubpenalty\clubpenalty
+%<latexrelease> \if@twocolumn
+%<latexrelease> \advance\columnwidth -\columnsep
+%<latexrelease> \divide\columnwidth\tw@ \hsize\columnwidth \@firstcolumntrue
+%<latexrelease> \fi
+%<latexrelease> \hsize\columnwidth \linewidth\hsize
+%<latexrelease> \begingroup\@floatplacement\@dblfloatplacement
+%<latexrelease> \makeatletter\let\@writefile\@gobbletwo
+%<latexrelease> \global \let \@multiplelabels \relax
+%<latexrelease> \@input{\jobname.aux}%
+%<latexrelease> \endgroup
+%<latexrelease> \if@filesw
+%<latexrelease> \immediate\openout\@mainaux\jobname.aux
+%<latexrelease> \immediate\write\@mainaux{\relax}%
+%<latexrelease> \fi
+%<latexrelease> \process@table
+%<latexrelease> \let\glb@currsize\@empty % Force math initialization.
+%<latexrelease> \normalsize
+%<latexrelease> \everypar{}%
+%<latexrelease> \ifx\normalsfcodes\@empty
+%<latexrelease> \ifnum\sfcode`\.=\@m
+%<latexrelease> \let\normalsfcodes\frenchspacing
+%<latexrelease> \else
+%<latexrelease> \let\normalsfcodes\nonfrenchspacing
+%<latexrelease> \fi
+%<latexrelease> \fi
+%<latexrelease> \ifx\document@default@language\m@ne
+%<latexrelease> \chardef\document@default@language\language
+%<latexrelease> \fi
+%<latexrelease> \@noskipsecfalse
+%<latexrelease> \let \@refundefined \relax
+%<latexrelease> \let\AtBeginDocument\@firstofone
+%<latexrelease> \@begindocumenthook
+%<latexrelease> \ifdim\topskip<1sp\global\topskip 1sp\relax\fi
+%<latexrelease> \global\@maxdepth\maxdepth
+%<latexrelease> \global\let\@begindocumenthook\@undefined
+%<latexrelease> \ifx\@listfiles\@undefined
+%<latexrelease> \global\let\@filelist\relax
+%<latexrelease> \global\let\@addtofilelist\@gobble
+%<latexrelease> \fi
+%<latexrelease> \gdef\do##1{\global\let ##1\@notprerr}%
+%<latexrelease> \@preamblecmds
+%<latexrelease> \global\let \@nodocument \relax
+%<latexrelease> \global\let\do\noexpand
+%<latexrelease> \ignorespaces}
+%<latexrelease>
+%<latexrelease>\def\enddocument{%
+%<latexrelease> \let\AtEndDocument\@firstofone
+%<latexrelease> \@enddocumenthook
+%<latexrelease> \@checkend{document}%
+%<latexrelease> \clearpage
+%<latexrelease> \begingroup
+%<latexrelease> \if@filesw
+%<latexrelease> \immediate\closeout\@mainaux
+%<latexrelease> \let\@setckpt\@gobbletwo
+%<latexrelease> \let\@newl@bel\@testdef
+%<latexrelease> \@tempswafalse
+%<latexrelease> \makeatletter \@@input\jobname.aux
+%<latexrelease> \fi
+%<latexrelease> \@dofilelist
+%<latexrelease> \ifdim \font@submax >\fontsubfuzz\relax
+%<latexrelease> \@font@warning{Size substitutions with differences\MessageBreak
+%<latexrelease> up to \font@submax\space have occurred.\@gobbletwo}%
+%<latexrelease> \fi
+%<latexrelease> \@defaultsubs
+%<latexrelease> \@refundefined
+%<latexrelease> \if@filesw
+%<latexrelease> \ifx \@multiplelabels \relax
+%<latexrelease> \if@tempswa
+%<latexrelease> \@latex@warning@no@line{Label(s) may have changed.
+%<latexrelease> Rerun to get cross-references right}%
+%<latexrelease> \fi
+%<latexrelease> \else
+%<latexrelease> \@multiplelabels
+%<latexrelease> \fi
+%<latexrelease> \fi
+%<latexrelease> \endgroup
+%<latexrelease> \deadcycles\z@\@@end}
+%<latexrelease>
+%<latexrelease>\expandafter\let\csname ver@atveryend.sty\endcsname\@undefined
+%<latexrelease>\let\AfterLastShipout \@undefined
+%<latexrelease>\let\AtVeryEndDocument \@undefined
+%<latexrelease>\let\AtEndAfterFileList \@undefined
+%<latexrelease>\let\AtVeryVeryEnd \@undefined
+%<latexrelease>\let\BeforeClearDocument \@undefined
+%<latexrelease>
+%<latexrelease>
+%<latexrelease>\expandafter\let\expandafter\shipout\csname tex_shipout:D\endcsname
+%<latexrelease>
+%<latexrelease>\let \ShipoutBox\@undefined
+%<latexrelease>\let \ReadonlyShipoutCounter \@undefined
+%<latexrelease>\let \c@totalpages \@undefined
+%<latexrelease>\let \thetotalpages \@undefined
+%<latexrelease>
+%<latexrelease>\let \DiscardShipoutBox \@undefined
+%<latexrelease>\let \DebugShipoutOn \@undefined
+%<latexrelease>\let \DebugShipoutOff \@undefined
+%<latexrelease>
+%<latexrelease>\DeclareRobustCommand \AtBeginDvi [1]{%
+%<latexrelease> \global \setbox \@begindvibox
+%<latexrelease> \vbox{\unvbox \@begindvibox #1}%
+%<latexrelease>}
+%<latexrelease>
+%<latexrelease>\let \AtBeginShipout \@undefined
+%<latexrelease>\let \AtBeginShipoutNext \@undefined
+%<latexrelease>
+%<latexrelease>\let \AtBeginShipoutFirst \@undefined
+%<latexrelease>
+%<latexrelease>\let \ShipoutBoxHeight \@undefined
+%<latexrelease>\let \ShipoutBoxDepth \@undefined
+%<latexrelease>\let \ShipoutBoxWidth \@undefined
+%<latexrelease>
+%<latexrelease>\let \AtBeginShipoutDiscard \@undefined
+%<latexrelease>
+%<latexrelease>\let \AtBeginShipoutAddToBox \@undefined
+%<latexrelease>\let \AtBeginShipoutAddToBoxForeground \@undefined
+%<latexrelease>\let \AtBeginShipoutUpperLeft \@undefined
+%<latexrelease>\let \AtBeginShipoutUpperLeftForeground \@undefined
+%<latexrelease>
+%<latexrelease>\expandafter\let\csname ver@atbegshi.sty\endcsname \@undefined
+%<latexrelease>
+%<latexrelease>\let \EveryShipout \@undefined
+%<latexrelease>\let \AtNextShipout \@undefined
+%<latexrelease>\expandafter \let \csname ver@everyshi.sty\endcsname \@undefined
+%<latexrelease>
+%<latexrelease>\let \AtEndDvi \@undefined
+%<latexrelease>\expandafter\let \csname ver@atenddvi.sty\endcsname \@undefined
+%<latexrelease>
+%<latexrelease>\AtBeginDocument{\reinstall@nfss@defs\init@series@setup}
+%<latexrelease>
+%<latexrelease>\EndIncludeInRelease
+%<*2ekernel>
+% \end{macrocode}
+%
+% \subsection{Some last minute initializations \ldots}
+%
+% This initializes the 2020/02/02 extensions to NFSS after any changes
+% in the preamble.
+% \begin{macrocode}
+\g@addto@macro\@kernel@after@env@document@begin
+ {\reinstall@nfss@defs\init@series@setup}
% \end{macrocode}
%
+%
% \subsection{Dumping the format}
% Finally we make |@| into a letter, ensure the format will
% be in the `normal' error mode, and dump everything into the
diff --git a/Master/texmf-dist/source/latex-dev/base/lthooks.dtx b/Master/texmf-dist/source/latex-dev/base/lthooks.dtx
new file mode 100644
index 00000000000..603b472e44a
--- /dev/null
+++ b/Master/texmf-dist/source/latex-dev/base/lthooks.dtx
@@ -0,0 +1,3925 @@
+% \iffalse meta-comment
+%
+%% File: lthooks.dtx (C) Copyright 2020 Frank Mittelbach, LaTeX Team
+%
+% 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
+%
+%
+% The development version of the bundle can be found below
+%
+% https://github.com/FrankMittelbach/...
+%
+% for those people who are interested or want to report an issue.
+%
+% \begin{macrocode}
+\providecommand\lthooksversion{v0.9b}
+\providecommand\lthooksdate{2020/07/19}
+% \end{macrocode}
+%
+%<*driver>
+\RequirePackage[debug]{lthooks}
+
+\documentclass{l3doc}
+
+% bug fix fo l3doc.cls
+\ExplSyntaxOn
+\cs_set_protected:Npn \__codedoc_macro_typeset_one:nN #1#2
+ {
+ \vbox_set:Nn \l__codedoc_macro_box
+ {
+ \vbox_unpack_drop:N \l__codedoc_macro_box
+ \hbox { \llap { \__codedoc_print_macroname:nN {#1} #2
+ \MacroFont % <----- without it the \ is in lmr10 if a link is made
+ \
+ } }
+ }
+ \int_incr:N \l__codedoc_macro_int
+ }
+\ExplSyntaxOff
+
+\EnableCrossrefs
+\CodelineIndex
+\begin{document}
+ \DocInput{lthooks.dtx}
+\end{document}
+%</driver>
+%
+% \fi
+%
+%
+% \long\def\fmi#1{\begin{quote}\itshape FMi: #1\end{quote}}
+% \long\def\pho#1{\begin{quote}\itshape PhO: #1\end{quote}}
+%
+% \newcommand\hook[1]{\texttt{#1}}
+%
+%
+% \title{The \texttt{lthooks} package\thanks{This package has version
+% \lthooksversion\ dated \lthooksdate, \copyright\ \LaTeX\
+% Project.}}
+%
+% \author{Frank Mittelbach\thanks{Code improvements for speed and other goodies by Phelype Oleinik}}
+%
+% \maketitle
+%
+%
+% \tableofcontents
+%
+% \section{Introduction}
+%
+% Hooks are points in the code of commands or environments where it
+% is possible to add processing code into existing commands. This
+% can be done by different packages that do not know about each
+% other and to allow for hopefully safe processing it is necessary
+% to sort different chunks of code added by different packages into
+% a suitable processing order.
+%
+% This is done by the packages adding chunks of code (via
+% \cs{AddToHook}) and labeling their code with some label by
+% default using the package name as a label.
+%
+% At \verb=\begin{document}= all code for a hook is then sorted
+% according to some rules (given by \cs{DeclareHookRule}) for fast
+% execution without processing overhead. If the hook code is
+% modified afterwards (or the rules are changed),
+% a new version for fast processing is generated.
+%
+% Some hooks are used already in the preamble of the document. If
+% that happens then the hook is prepared for execution (and sorted)
+% already at that point.
+%
+%
+% \section{Package writer interface}
+%
+% The hook management system is offered as a set of CamelCase
+% commands for traditional \LaTeXe{} packages (and for use in the
+% document preamble if needed) as well as \texttt{expl3} commands
+% for modern packages, that use the L3 programming layer of
+% \LaTeX{}. Behind the scenes, a single set of data structures is
+% accessed so that packages from both worlds can coexist and access
+% hooks in other packages.
+%
+%
+%
+% \subsection{\LaTeXe\ interfaces}
+%
+% \subsubsection{Declaring hooks and using them in code}
+%
+% With two exceptions, hooks have to be declared before they can be
+% used. The exceptions are hooks in environments (i.e., executed at
+% \cs{begin} and \cs{end}) and hooks run when loading files,
+% e.g. before and after a package is loaded, etc. Their hook names
+% depend on the environment or the file name and so declaring them
+% beforehand is difficult.
+%
+%
+% \begin{function}{\NewHook}
+% \begin{syntax}
+% \cs{NewHook} \Arg{hook}
+% \end{syntax}
+% Creates a new \meta{hook}.
+% If this is a hook provided as part of a package it is suggested
+% that the \meta{hook} name is always structured as follows:
+% \meta{package-name}\texttt{/}\meta{hook-name}. If necessary you
+% can further subdivide the name by adding more \texttt{/} parts.
+% If a hook name is already taken, an error is raised and the hook
+% is not created.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+% \begin{function}{\NewReversedHook}
+% \begin{syntax}
+% \cs{NewReversedHook} \Arg{hook}
+% \end{syntax}
+% Like \cs{NewHook} declares a new \meta{hook}.
+% the difference is that the code chunks for this hook are in
+% reverse order by default (those added last are executed first).
+% Any rules for the hook are applied after the default ordering.
+% See sections~\ref{sec:order} and \ref{sec:reversed-order}
+% for further details.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+%
+% \begin{function}{\NewMirroredHookPair}
+% \begin{syntax}
+% \cs{NewMirroredHookPair} \Arg{hook-1} \Arg{hook-2}
+% \end{syntax}
+% A shorthand for
+% \cs{NewHook}\Arg{hook-1}\cs{NewReversedHook}\Arg{hook-2}.
+%
+% The \meta{hooks} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+
+
+
+% \begin{function}{\UseHook}
+% \begin{syntax}
+% \cs{UseHook} \Arg{hook}
+% \end{syntax}
+% Execute the hook code inside a command or environment.\footnote{For
+% legacy hooks such as \hook{begindocument} it is also
+% possible to call \cs{@...hook}, e.g., \cs{@begindocumenthook},
+% but this syntax is discouraged.}
+%
+% Before \verb=\begin{document}= the fast execution code for a hook
+% is not set up, so in order to use a hook there it is explicitly
+% initialized first. As that involves assignments using a hook at
+% those times is not 100\% the same as using it after
+% \verb=\begin{document}=.
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
+% \begin{function}{\UseOneTimeHook}
+% \begin{syntax}
+% \cs{UseOneTimeHook} \Arg{hook}
+% \end{syntax}
+% Some hooks are only used (and can be only used) in one place, for
+% example, those in \verb=\begin{document}= or
+% \verb=\end{document}=. Once we have passed that point adding to
+% the hook through a defined \cs{\meta{addto-cmd}} command (e.g.,
+% \cs{AddToHook} or \cs{AtBeginDocument}, etc.\@) would have no
+% effect (as would the use of such a command inside the hook code
+% itself). It is therefore customary to redefine
+% \cs{\meta{addto-cmd}} to simply process its argument, i.e.,
+% essentially make it behave like \cs{@firstofone}.
+%
+% \cs{UseOneTimeHook} does that: it records that the hook has been
+% consumed and any further attempt to add to it will result in
+% executing the code to be added immediately.
+%
+% \fmi{Maybe add an error version as well?}
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
+%
+% \subsubsection{Updating code for hooks}
+%
+% \begin{function}{\AddToHook}
+% \begin{syntax}
+% \cs{AddToHook} \Arg{hook}\oarg{label}\Arg{code}
+% \end{syntax}
+% Adds \meta{code} to the \meta{hook} labeled by \meta{label}. If
+% the optional argument \meta{label} is not provided, if \cs{AddToHook}
+% is used in a package/class, then the current
+% package/class name is used, otherwise \hook{top-level} is
+% used~(see section~\ref{sec:default-label}).
+%
+% If there already exists code under the \meta{label} then the new
+% \meta{code} is appended to the existing one (even if this is a reversed hook).
+% If you want to replace existing code under the
+% \meta{label}, first apply \cs{RemoveFromHook}.
+%
+% The hook doesn't have to exist for code to be added to
+% it. However, if it is not declared later then obviously the
+% added \meta{code} will never be executed. This
+% allows for hooks to work regardless of package loading order and
+% enables packages to add to hook of other packages without
+% worrying whether they are actually used in the current document.
+% See section~\ref{sec:querying}.
+%
+% The \meta{hook} and \meta{label} can be specified using the
+% dot-syntax to denote the current package name.
+% See section~\ref{sec:default-label}.
+% \end{function}
+%
+% \begin{function}{\RemoveFromHook}
+% \begin{syntax}
+% \cs{RemoveFromHook} \Arg{hook}\oarg{label}
+% \end{syntax}
+% Removes any code labeled by \meta{label} from the \meta{hook}.
+% If the optional
+% argument \meta{label} is not provided, if \cs{AddToHook}
+% is used in a package/class, then the current
+% package/class name is used, otherwise \hook{top-level} is used.
+%
+% If the optional argument is \texttt{*}, then all code chunks are
+% removed. This is rather dangerous as it drops code from other
+% packages one may not know about!
+%
+% The \meta{hook} and \meta{label} can be specified using the
+% dot-syntax to denote the current package name.
+% See section~\ref{sec:default-label}.
+% \end{function}
+%
+% \medskip
+%
+% A useful application for this declaration inside the document body
+% is when one wants to temporarily add code to hooks and later remove
+% it again, e.g.,
+%\begin{verbatim}
+% \AddToHook{env/quote/before}{\small}
+% \begin{quote}
+% A quote set in a smaller typeface
+% \end{quote}
+% ...
+% \RemoveFromHook{env/quote/before}
+% ... now back to normal for further quotes
+%\end{verbatim}
+% Note that you can't cancel the setting with
+%\begin{verbatim}
+% \AddToHook{env/quote/before}{}
+%\end{verbatim}
+% because that only \enquote{adds} a further empty chunk of code to
+% the hook. Adding \cs{normalsize} would work but that means the hook
+% then contained \cs{small}\cs{normalsize} which means to font size
+% changes for no good reason.
+%
+% The above is only needed if one wants to typeset several quotes in a
+% smaller typeface. If the hook is only needed once then
+% \cs{AddToHookNext} is simpler, because it resets itself after one use.
+%
+%
+% \begin{function}{\AddToHookNext}
+% \begin{syntax}
+% \cs{AddToHookNext} \Arg{hook}\Arg{code}
+% \end{syntax}
+% Adds \meta{code} to the next invocation of the \meta{hook}.
+% The code is executed after the normal hook code has finished and
+% it is executed only once, i.e. it is deleted after it was used.
+%
+% Using the declaration is a global operation, i.e., the code is
+% not lost, even if the declaration is used inside a group and the
+% next invocation happens after the group. If the declaration is
+% used several times before the hook is executed then all code is
+% executed in the order in which it was declared.\footnotemark
+%
+% The hook doesn't have to exist for code to be added to it. This
+% allows for hooks to work regardless of package loading order.
+% See section~\ref{sec:querying}.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}\footnotetext{There is
+% no mechanism to reorder such code chunks (or delete them).}
+%
+% \subsubsection{Hook names and default labels}
+% \label{sec:default-label}
+%
+% It is best practice to use \cs{AddToHook} in packages or classes
+% \emph{without specifying a \meta{label}} because then the package
+% or class name is automatically used, which is helpful if rules are
+% needed, and avoids mistyping the \meta{label}.
+%
+% Using an explicit \meta{label} is only necessary in very specific
+% situations, e.g., if you want to add several chunks of code into a
+% single hook and have them placed in different parts of the hook
+% (by providing some rules).
+%
+% The other case is when you develop a larger package with several
+% sub-packages. In that case you may want to use the same
+% \meta{label} throughout the sub-packages in order to avoid
+% that the labels change if you internally reorganize your code.
+%
+% It is not enforced, but highly recommended that the hooks defined by
+% a package, and the \meta{labels} used to add code to other hooks
+% contain the package name to easily identify the source of the code
+% chunk and to prevent clashes. This should be the standard practice,
+% so this hook management code provides a shortcut to refer to the
+% current package in the name of a \meta{hook} and in a \meta{label}.
+% If \meta{hook} name or \meta{label} consist just of a single dot
+% (|.|), or starts with a dot followed by a slash (|./|) then the dot
+% denotes the \meta{default label} (usually the current package or class
+% name---see~\cs{DeclareDefaultHookLabel}).
+% A \enquote{|.|} or \enquote{|./|} anywhere else in a \meta{hook} or in
+% \meta{label} is treated literally and is not replaced.
+
+% For example,
+% inside the package \texttt{mypackage.sty}, the default label is
+% \texttt{mypackage}, so the instructions:
+% \begin{verbatim}
+% \NewHook {./hook}
+% \AddToHook {./hook}[.]{code} % Same as \AddToHook{./hook}{code}
+% \AddToHook {./hook}[./sub]{code}
+% \DeclareHookRule{begindocument}{.}{<}{babel}
+% \AddToHook {file/after/foo.tex}{code}
+% \end{verbatim}
+% are equivalent to:
+% \begin{verbatim}
+% \NewHook {mypackage/hook}[mypackage]{code}
+% \AddToHook {mypackage/hook}[mypackage]{code}
+% \AddToHook {mypackage/hook}[mypackage/sub]{code}
+% \DeclareHookRule{begindocument}{mypackage}{<}{babel}
+% \AddToHook {file/after/foo.tex}{code} % unchanged
+% \end{verbatim}
+%
+% The \meta{default label} is automatically set to the name of the
+% current package or class (using \cs{@currname}). If \cs{@currname}
+% is not set (because the hook command is used outside of a package, or
+% the current file wasn't loaded with \cs{usepackage} or
+% \cs{documentclass}), then the \texttt{top-level} is used as the
+% \meta{default label}.
+%
+% This syntax is available in all \meta{label} arguments and most
+% \meta{hook}, both in the \LaTeXe{} interface, and the \LaTeX3
+% interface described in section~\ref{sec:l3hook-interface}.
+%
+% Note, however, that the replacement of |.| by the \meta{default label}
+% takes place when the hook command is executed, so actions that are
+% somehow executed after the package ends will have the wrong
+% \meta{default label} if the dot-syntax is used. For that reason,
+% this syntax is not available in \cs{UseHook} (and \cs{hook_use:n})
+% because the hook is most of the time used outside of the package file
+% in which it was defined. This syntax is also not available in the hook
+% conditionals \cs{IfHookEmptyTF} (and \cs{hook_if_empty:nTF}) and
+% \cs{IfHookExistTF} (and \cs{hook_if_exist:nTF}) because these
+% conditionals are used in some performance-critical parts of the hook
+% management code, and because they are usually used to refer to other
+% package's hooks, so the dot-syntax doesn't make much sense.
+%
+% In some cases, for example in large packages, one may want to separate
+% it in logical parts, but still use the main package name as
+% \meta{label}, then the \meta{default label} can be set using
+% \cs{DeclareDefaultHookLabel}:
+%
+% \begin{function}{\DeclareDefaultHookLabel}
+% \begin{syntax}
+% \cs{DeclareDefaultHookLabel} \Arg{default label}
+% \end{syntax}
+% Sets the \meta{default label} to be used in \meta{label} arguments.
+% If \cs{DeclareDefaultHookLabel} is not used in the
+% current package, \cs{@currname} is used instead. If \cs{@currname}
+% is not set, the code is assumed to be in the main document, in which
+% case \texttt{top-level} is used.
+%
+% The effect of \cs{DeclareDefaultHookLabel} holds for the current
+% file, and is reset to the previous value when the file is closed.
+% \end{function}
+%
+%
+% \subsubsection{Defining relations between hook code}
+%
+% The default assumption is that code added to hooks by different
+% packages is independent and the order in which it is executed is
+% irrelevant. While this is true in many case it is obviously false
+% in many others.
+%
+% Before the hook management system was introduced
+% packages had to take elaborate precaution to determine of some other
+% package got loaded as well (before or after) and find some ways to
+% alter its behavior accordingly. In addition is was often the user's
+% responsibility to load packages in the right order so that code
+% added to hooks got added in the right order and some cases even
+% altering the loading order wouldn't resolve the conflicts.
+%
+% With the new hook management system it is now possible to define
+% rules (i.e., relationships) between code chunks added by different
+% packages and explicitly describe in which order they should be
+% processed.
+%
+% \begin{function}{\DeclareHookRule}
+% \begin{syntax}
+% \cs{DeclareHookRule} \Arg{hook}\Arg{label1}\Arg{relation}\Arg{label2}
+% \end{syntax}
+% Defines a relation between \meta{label1} and \meta{label2} for a
+% given \meta{hook}. If \meta{hook} is \texttt{??} this defines a
+% relation for all hooks that use the two labels, i.e., that have
+% chunks of code labeled with \meta{label1} and \meta{label2}.
+% Rules specific to a given hook take precedence over default
+% rules that use \texttt{??} as the \meta{hook}.
+%
+% Currently, the supported relations are the following:
+% \begin{itemize}
+%
+% \item[\texttt{before} or \texttt{\string<}]
+%
+% Code for \meta{label1} comes before code for \meta{label2}.
+%
+% \item[\texttt{after} or \texttt{\string>}]
+% Code for \meta{label1} comes after code for \meta{label2}.
+%
+% \item[\texttt{incompatible-warning}]
+%
+% Only code for either \meta{label1} or \meta{label2} can appear
+% for that hook (a way to say that two packages---or parts of
+% them---are incompatible). A warning is raised if both labels
+% appear in the same hook.
+%
+% \item[\texttt{incompatible-error}]
+%
+% Like \texttt{incompatible-error} but instead of a warning a
+% \LaTeX{} error is raised, and the code for both labels are
+% dropped from that hook until the conflict is resolved.
+%
+% \item[\texttt{removes}]
+%
+% Code for \meta{label1} overwrites code for \meta{label2}. More
+% precisely, code for \meta{label2} is dropped for that
+% hook. This can be used, for example if one package is a
+% superset in functionality of another one and therefore wants to
+% undo code in some hook and replace it with its own version.
+%
+% \item[\texttt{unrelated}]
+%
+% The order of code for \meta{label1} and \meta{label2} is
+% irrelevant. This rule is there to undo an incorrect rule
+% specified earlier.
+%
+% \end{itemize}
+%
+% The \meta{hook} and \meta{label} can be specified using the
+% dot-syntax to denote the current package name.
+% See section~\ref{sec:default-label}.
+% \end{function}
+%
+%
+% \begin{function}{\ClearHookRule}
+% \begin{syntax}
+% \cs{ClearHookRule}\Arg{hook}\Arg{label1}\Arg{label2}
+% \end{syntax}
+% Syntactic sugar for saying that \meta{label1} and \meta{label2}
+% are unrelated for the given \meta{hook}.
+% \end{function}
+%
+%
+%
+% \begin{function}{\DeclareDefaultHookRule}
+% \begin{syntax}
+% \cs{DeclareDefaultHookRule}\Arg{label1}\Arg{relation}\Arg{label2}
+% \end{syntax}
+% This sets up a relation between \meta{label1} and \meta{label2}
+% for all hooks unless overwritten by a specific rule for a hook.
+% Useful for cases where one package has a specific relation to
+% some other package, e.g., is \texttt{incompatible} or always
+% needs a special ordering \texttt{before} or \texttt{after}.
+% (Technically it is just a shorthand for using \cs{DeclareHookRule}
+% with \texttt{??} as the hook name.)
+%
+% Declaring default rules is only supported in the document
+% preamble.\footnotemark{}
+%
+% The \meta{label} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}\footnotetext{Trying to do so, e.g., via
+% \cs{DeclareHookRule} with \texttt{??} has bad side-effects and
+% is not supported (though not explicitly caught for performance
+% reasons).}
+%
+%
+%
+% \subsubsection{Querying hooks}
+% \label{sec:querying}
+%
+% Simpler data types, like token lists, have three possible states; they
+% can:
+% \begin{itemize}
+% \item exist and be empty;
+% \item exist and be non-empty; and
+% \item not exist (in which case emptiness doesn't apply);
+% \end{itemize}
+% Hooks are a bit more complicated: they have four possible states.
+% A hook may exist or not, and either way it may or may not be empty.
+% This means that even a hook that doesn't exist may be non-empty.
+%
+% This seemingly strange state may happen when, for example, package~$A$
+% defines hook \hook{A/foo}, and package $B$ adds some code to that
+% hook. However, a document may load package $B$ before package $A$, or
+% may not load package $A$ at all. In both cases some code is added to
+% hook \hook{A/foo} without that hook being defined yet, thus that
+% hook is said to be non-empty, whereas it doesn't exist. Therefore,
+% querying the existence of a hook doesn't imply its emptiness, neither
+% does the other way around.
+%
+% A hook is said to be empty when no code was added to it, either to
+% its permanent code pool, or to its ``next'' token list. The hook
+% doesn't need to be declared to have code added to its code pool.
+% A hook is said to exist when it was declared with \cs{NewHook} or
+% some variant thereof.
+%
+% \begin{function}[EXP]{\IfHookEmptyTF}
+% \begin{syntax}
+% \cs{IfHookEmptyTF} \Arg{hook} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests if the \meta{hook} is empty (\emph{i.e.}, no code was added to
+% it using either \cs{AddToHook} or \cs{AddToHookNext}), and
+% branches to either \meta{true code} or \meta{false code} depending
+% on the result.
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
+% \begin{function}[EXP]{\IfHookExistTF}
+% \begin{syntax}
+% \cs{IfHookExistTF} \Arg{hook} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests if the \meta{hook} exists (if it was created with either
+% \cs{NewHook}, \cs{NewReversedHook}, or \cs{NewMirroredHookPair}), and
+% branches to either \meta{true code} or \meta{false code} depending
+% on the result.
+%
+% The existence of a hook usually doesn't mean much from the viewpoint
+% of code that tries to add/remove code from that hook, since package
+% loading order may vary, thus the creation of hooks is asynchronous
+% to adding and removing code from it, so this test should be used
+% sparingly.
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
+% \fmi{Would be helpful if we provide some use cases}
+%
+% \subsubsection{Displaying hook code}
+%
+% If one has to adjust the code execution in a hook using a hook
+% rule it is helpful to get some information about the code
+% associated with a hook, its current order and the existing rules.
+%
+% \begin{function}{\ShowHook}
+% \begin{syntax}
+% \cs{ShowHook} \Arg{hook}
+% \end{syntax}
+% Displays information about the \meta{hook} such as
+% \begin{itemize}
+% \item
+% the code chunks (and their labels) added to it,
+% \item
+% any rules set up to order them,
+% \fmi{currently this is missing the default rules that apply,
+% guess that needs fixing}
+% \item
+% the computed order (if already defined),
+% \item
+% any code executed on the next invocation only.
+% \end{itemize}
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+%
+% \subsubsection{Debugging hook code}
+%
+% \begin{function}{\DebugHookOn,\DebugHookOff}
+% \begin{syntax}
+% \cs{DebugHookOn}
+% \end{syntax}
+% Turn the debugging of hook code on or off. This displays changes
+% made to the hook data structures. The output is rather coarse and
+% not really intended for normal use.
+% \end{function}
+%
+%
+% \subsection{L3 programming layer (\texttt{expl3}) interfaces}
+% \label{sec:l3hook-interface}
+%
+%
+% This is a quick summary of the \LaTeX3 programming interfaces for
+% use with packages written in \texttt{expl3}. In contrast to the
+% \LaTeXe{} interfaces they always use mandatory arguments only, e.g.,
+% you always have to specify the \meta{label} for a code chunk. We
+% therefore suggest to use the declarations discussed in the previous
+% section even in \texttt{expl3} packages, but the choice is yours.
+%
+%
+% \begin{function}
+% {\hook_new:n,\hook_new_reversed:n,\hook_new_pair:nn}
+% \begin{syntax}
+% \cs{hook_new:n}\Arg{hook}
+% \cs{hook_new_pair:nn}\Arg{hook-1}\Arg{hook-2}
+% \end{syntax}
+% Creates a new \meta{hook} with normal or reverse ordering of code
+% chunks. \cs{hook_new_pair:nn} creates a pair of such hooks with
+% \Arg{hook-2} being a reversed hook.
+% If a hook name is already taken, an error is raised and the hook
+% is not created.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+%
+%
+% \begin{function}{\hook_use:n}
+% \begin{syntax}
+% \cs{hook_use:n} \Arg{hook}
+% \end{syntax}
+% Executes the \Arg{hook} code followed (if set up) by the code for next
+% invocation only, then empties that next invocation code.
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
+% \begin{function}{\hook_use_once:n}
+% \begin{syntax}
+% \cs{hook_use_once:n} \Arg{hook}
+% \end{syntax}
+% Changes the \Arg{hook} status so that from now on any addition to
+% the hook code is executed immediately. Then execute any
+% \Arg{hook} code already set up.
+% \fmi{better L3 name?}
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
+% \begin{function}{\hook_gput_code:nnn}
+% \begin{syntax}
+% \cs{hook_gput_code:nnn} \Arg{hook} \Arg{label} \Arg{code}
+% \end{syntax}
+% Adds a chunk of \meta{code} to the \meta{hook} labeled
+% \meta{label}. If the label already exists the \meta{code} is
+% appended to the already existing code.
+%
+% If code is added to an external \meta{hook} (of the kernel or
+% another package) then the convention is to use the package name
+% as the \meta{label} not some internal module name or some other
+% arbitrary string.
+%
+% The \meta{hook} and \meta{label} can be specified using the
+% dot-syntax to denote the current package name.
+% See section~\ref{sec:default-label}.
+% \end{function}
+%
+% \begin{function}
+% {\hook_gput_next_code:nn}
+% \begin{syntax}
+% \cs{hook_gput_next_code:nn} \Arg{hook} \Arg{code}
+% \end{syntax}
+% Adds a chunk of \meta{code} for use only in the next invocation of the
+% \meta{hook}. Once used it is gone.
+%
+% This is simpler than \cs{hook_gput_code:nnn}, the code is simply
+% appended to the hook in the order of declaration at the very end,
+% i.e., after all standard code for the hook got executed.
+%
+% Thus if one needs to undo what the standard does one has to do
+% that as part of \meta{code}.
+%
+% The \meta{hook} can be specified using the dot-syntax to denote
+% the current package name. See section~\ref{sec:default-label}.
+% \end{function}
+%
+
+
+% \begin{function}{\hook_gremove_code:nn}
+% \begin{syntax}
+% \cs{hook_gremove_code:nn} \Arg{hook} \Arg{label}
+% \end{syntax}
+% Removes any code for \meta{hook} labeled \meta{label}.
+%
+% If the code for that \meta{label} wasn't yet added to the
+% \meta{hook}, an order is set so that when some code attempts to add
+% that label, the removal order takes action and the code is not
+% added.
+%
+% If the second argument is \texttt{*}, then all code chunks are
+% removed. This is rather dangerous as it drops code from other
+% packages one may not know about, so think twice before using
+% that!
+%
+% The \meta{hook} and \meta{label} can be specified using the
+% dot-syntax to denote the current package name.
+% See section~\ref{sec:default-label}.
+% \end{function}
+
+
+% \begin{function}{\hook_gset_rule:nnnn}
+% \begin{syntax}
+% \cs{hook_gset_rule:nnnn} \Arg{hook} \Arg{label1} \Arg{relation} \Arg{label2}
+% \end{syntax}
+% Relate \meta{label1} with \meta{label2} when used in \meta{hook}.
+% See \cs{DeclareHookRule} for the allowed \meta{relation}s.
+% If \meta{hook} is \texttt{??} a default rule is specified.
+%
+% The \meta{hook} and \meta{label} can be specified using the
+% dot-syntax to denote the current package name.
+% See section~\ref{sec:default-label}.
+% The dot-syntax is parsed in both \meta{label} arguments, but it
+% usually makes sense to be used in only one of them.
+% \end{function}
+%
+% \begin{function}[pTF]{\hook_if_empty:n}
+% \begin{syntax}
+% \cs{hook_if_empty:n} \Arg{hook} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests if the \meta{hook} is empty (\emph{i.e.}, no code was added to
+% it using either \cs{AddToHook} or \cs{AddToHookNext}), and
+% branches to either \meta{true code} or \meta{false code} depending
+% on the result.
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
+% \begin{function}[pTF]{\hook_if_exist:n}
+% \begin{syntax}
+% \cs{hook_if_exist:n} \Arg{hook} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests if the \meta{hook} exists (if it was created with either
+% \cs{NewHook}, \cs{NewReversedHook}, or \cs{NewMirroredHookPair}), and
+% branches to either \meta{true code} or \meta{false code} depending
+% on the result.
+%
+% \fmi{what are the results for generic hooks that do not need to be declared?}
+%
+% The existence of a hook usually doesn't mean much from the viewpoint
+% of code that tries to add/remove code from that hook, since package
+% loading order may vary, thus the creation of hooks is asynchronous
+% to adding and removing code from it, so this test should be used
+% sparingly.
+%
+% The \meta{hook} \emph{cannot} be specified using the dot-syntax.
+% A leading |.| is treated literally.
+% \end{function}
+%
+%
+% \begin{function}{\hook_debug_on:,\hook_debug_off:}
+% \begin{syntax}
+% \cs{hook_debug_on:}
+% \end{syntax}
+% Turns the debugging of hook code on or off. This displays changes
+% to the hook data.
+% \end{function}
+%
+%
+%
+% \subsection{On the order of hook code execution} \label{sec:order}
+%
+% Chunks of code for a \meta{hook} under different labels are supposed
+% to be independent if there are no special rules set up that
+% define a relation between the chunks. This means that you can't
+% make assumptions about the order of execution!
+%
+% Suppose you have the following declarations:
+%\begin{verbatim}
+% \NewHook{myhook}
+% \AddToHook{myhook}[packageA]{\typeout{A}}
+% \AddToHook{myhook}[packageB]{\typeout{B}}
+% \AddToHook{myhook}[packageC]{\typeout{C}}
+%\end{verbatim}
+% then executing the hook with \cs{UseHook} will produce the
+% typeout \texttt{A} \texttt{B} \texttt{C} in that order. In other
+% words, the execution order is computed to be \texttt{packageA},
+% \texttt{packageB}, \texttt{packageC} which you can verify with
+% \cs{ShowHook}\texttt{\{myhook\}}:
+%\begin{verbatim}
+% The hook 'myhook':
+% Code chunks:
+% packageA -> \typeout {A}
+% packageB -> \typeout {B}
+% packageC -> \typeout {C}
+% Extra code next invocation:
+% ---
+% Rules:
+% ---
+% Execution order:
+% packageA, packageB, packageC
+%\end{verbatim}
+% The reason is that the code chunks are internally saved in a property list
+% and the initial order of such a property list is the order in
+% which key-value pairs got added. However, that is only true if
+% nothing other than adding happens!
+%
+% Suppose, or example, you want to replace the code chunk for
+% \texttt{packageA}, e.g.,
+%\begin{verbatim}
+% \RemoveFromHook{myhook}[packageA]
+% \AddToHook{myhook}[packageA]{\typeout{A alt}}
+%\end{verbatim}
+% then your order becomes \texttt{packageB},
+% \texttt{packageC}, \texttt{packageA} because the label got removed
+% from the property list and then re-added (at its end).
+%
+% While that may not be too surprising, the execution order is
+% also sometimes altered if you add a redundant rule, e.g. if you specify
+%\begin{verbatim}
+% \DeclareHookRule{myhook}{packageA}{before}{packageB}
+%\end{verbatim}
+% instead of the previous lines we get
+%\begin{verbatim}
+% The hook 'myhook':
+% Code chunks:
+% packageA -> \typeout {A}
+% packageB -> \typeout {B}
+% packageC -> \typeout {C}
+% Extra code next invocation:
+% ---
+% Rules:
+% packageA|packageB with relation before
+% Execution order (after applying rules):
+% packageA, packageC, packageB
+%\end{verbatim}
+% As you can see the code chunks are still in the same order, but
+% in the execution order for the labels \texttt{packageB} and
+% \texttt{packageC} have
+% swapped places.
+% The reason is that, with the rule there are two orders that
+% satisfy it, and the algorithm for sorting happened to pick a
+% different one compared to the case without rules (where it
+% doesn't run at all as there is nothing to resolve).
+% Incidentally, if we had instead specified the redundant rule
+%\begin{verbatim}
+% \DeclareHookRule{myhook}{packageB}{before}{label-3}
+%\end{verbatim}
+% the execution order would not have changed.
+%
+% In summary: it is not possible to rely on the order of execution
+% unless there are rules that partially or fully define the order
+% (in which you can rely on them being fulfilled).
+%
+%
+% \subsection{The use of \enquote{reversed} hooks} \label{sec:reversed-order}
+%
+% You may have wondered why you can declare a \enquote{reversed} hook
+% with \cs{NewReversedHook} and what that does exactly.
+%
+% In short: the execution order of a reversed hook (without any
+% rules!) is exactly reversed to the order you would have gotten for
+% a hook declared with \cs{NewHook}.
+%
+% This is helpful if you have a pair of hooks where you expect to see
+% code added that involves grouping, e.g., starting an environment
+% in the first and closing that environment in the second hook.
+% To give a somewhat contrived example\footnote{there are simpler
+% ways to achieve the same effect.}, suppose there is a package
+% adding the following:
+%\begin{verbatim}
+% \AddToHook{env/quote/before}[package-1]{\begin{itshape}}
+% \AddToHook{env/quote/after} [package-1]{\end{itshape}}
+%\end{verbatim}
+% As a result, all quotes will be in italics.
+% Now suppose further that the user wants the quotes also in blue
+% and therefore adds:
+%\begin{verbatim}
+% \usepackage{color}
+% \AddToHook{env/quote/before}{\begin{color}{blue}}
+% \AddToHook{env/quote/after} {\end{color}}
+%\end{verbatim}
+% Now if the \hook{env/quote/after} hook would be a normal hook we
+% would get the same execution order in both hooks, namely:
+%\begin{verbatim}
+% package-1, top-level
+%\end{verbatim}
+% (or vice versa) and as a result, would get:
+%\begin{verbatim}
+% \begin{itshape}\begin{color}{blue} ...
+% \end{itshape}\end{color}
+%\end{verbatim}
+% and an error message that \verb=\begin{color}= ended by
+% \verb=\end{itshape}=.
+% With \hook{env/quote/after} declared as a reversed hook the
+% execution order is reversed and so all environments are closed in
+% the correct sequence and \cs{ShowHook} would give us the
+% following output:
+%\begin{verbatim}
+% The hook 'env/quote/after':
+% Code chunks:
+% package-1 -> \end {itshape}
+% top-level -> \end {color}
+% Extra code next invocation:
+% ---
+% Rules:
+% ---
+% Execution order (after reversal):
+% top-level, package-1
+%\end{verbatim}
+%
+% The reversal of the execution order happens before applying any
+% rules, so if you alter the order you will probably have to alter
+% it in both hooks, not just in one, but that depends on the use case.
+%
+%
+%
+%
+% \subsection{Private \LaTeX{} kernel hooks}
+%
+% There are a few places where it is absolutely essential for
+% \LaTeX{} to function correctly that code is executed in a precisely
+% defined order. Even that could have been implemented with the
+% hook management (by adding various rules to ensure the
+% appropriate ordering with respect to other code added by
+% packages). However, this makes every document unnecessary
+% slow, because there has to be sorting even through the result is
+% predetermined. Furthermore it forces package writers to
+% unnecessarily add such rules if they add further code to the hook
+% (or break \LaTeX{}).
+%
+% For that reason such code is not using the hook management, but
+% instead private kernel commands directly before or after a public
+% hook with the following naming
+% convention: \cs{@kernel@before@\meta{hookname}} or
+% \cs{@kernel@after@\meta{hookname}}. For example, in
+% \cs{enddocument} you find
+%\begin{verbatim}
+% \UseHook{enddocument}%
+% \@kernel@after@enddocument
+%\end{verbatim}
+% which means first the user/package-accessible \hook{enddocument}
+% hook is executed and then the internal kernel hook. As their name
+% indicates these kernel commands should not be altered by third-party
+% packages, so please refrain from that in the interest of
+% stability and instead use the public hook next to it.\footnote{As
+% with everything in \TeX{} there is not enforcement of this rule,
+% and by looking at the code it is easy to find out how the kernel
+% adds to them. The main reason of this section is therefore to say
+% \enquote{please don't do that, this is unconfigurable code!}}
+%
+%
+%
+% \subsection{Legacy \LaTeXe{} interfaces}
+%
+% \LaTeXe{} offered a small number of hooks together with commands to
+% add to them. They are listed here and are retained for backwards
+% compatibility.
+%
+% With the new hook management several additional hooks have been added
+% to \LaTeX\ and more will follow. See the next section for what
+% is already available.
+%
+%
+% \begin{function}{\AtBeginDocument}
+% \begin{syntax}
+% \cs{AtBeginDocument} \oarg{label} \Arg{code}
+% \end{syntax}
+% If used without the optional argument \meta{label}, it works essentially
+% like before, i.e., it is adding \meta{code} to the hook
+% \hook{begindocument}
+% (which is executed inside \verb=\begin{document}=).
+% However, all code added this way is labeled with the label
+% \hook{top-level} if done outside of a package or class or with the
+% package/class name if called inside such a file.
+%
+% This way one can add further code to the hook using
+% \cs{AddToHook} or \cs{AtBeginDocument} using a different label
+% and explicitly order the code chunks as necessary, e.g., run some
+% code before or after the \hook{top-level} code. When using the
+% optional argument the call is equivalent to running
+% \cs{AddToHook} \texttt{\{begindocument\}} \oarg{label}
+% \Arg{code}.
+%
+% For important packages with known order requirement we may over
+% time add rules to the kernel (or to those packages) so that they
+% work regardless of the loading-order in the document.
+% \end{function}
+%
+% \begin{function}{\AtEndDocument}
+% \begin{syntax}
+% \cs{AtEndDocument} \oarg{label} \Arg{code}
+% \end{syntax}
+% Like \cs{AtBeginDocument} but for the \hook{enddocument} hook.
+% \end{function}
+%
+%
+%
+% \begin{function}{\AtBeginDvi}
+% \begin{syntax}
+% \cs{AtBeginDvi} \oarg{label} \Arg{code}
+% \end{syntax}
+% This hook is discussed in conjunction with the shipout hooks.
+% \end{function}
+%
+%
+%
+% \subsection{\LaTeXe{} commands and environments augmented by
+% hooks}
+%
+% \emph{intro to be written}
+%
+% \subsubsection{Generic hooks for all environments}
+%
+% Every environment \meta{env} has now four associated hooks coming
+% with it:
+% \begin{description}
+% \item[\hook{env/\meta{env}/before}]
+%
+% This hook is executed as part of \cs{begin} as the very first
+% action, in particular prior to starting the environment group.
+% Its scope is therefore not restricted by the environment.
+%
+% \item[\hook{env/\meta{env}/begin}]
+%
+% This hook is executed as part of \cs{begin} directly in front
+% of the code specific to the environment start (e.g., the
+% second argument of \cs{newenvironment}). Its scope is the
+% environment body.
+%
+% \item[\hook{env/\meta{env}/end}]
+%
+% This is executed as part of \cs{end} directly in front of the
+% code specific to the end of the environment (e.g., the third
+% argument of \cs{newenvironment}).
+%
+% \item[\hook{env/\meta{env}/after}]
+%
+% This is executed as part of \cs{end} after the
+% code specific to the environment end and after the environment
+% group has ended.
+% Its scope is therefore not restricted by the environment.
+%
+% This hook is implemented as a reversed hook so if two packages
+% add code to \hook{env/\meta{env}/before} and to
+% \hook{env/\meta{env}/after} they can add surrounding
+% environments and the order of closing them happens in the
+% right sequence.
+%
+% \end{description}
+% In contrast to other hooks these hooks do not need to be declared
+% using \cs{NewHook}.
+%
+% The hooks are only executed if \cs{begin}\Arg{env} and
+% \cs{end}\Arg{env} is used. If the environment code is executed
+% via low-level calls to \cs{\meta{env}} and \cs{end\meta{env}}
+% (e.g., to avoid the environment grouping) they are not
+% available. If you want them available in code using this method,
+% you would need to add them yourself, i.e., write something like
+%\begin{verbatim}
+% \UseHook{env/quote/before}\quote
+% ...
+% \endquote\UseHook{env/quote/after}
+%\end{verbatim}
+% to add the outer hooks, etc.
+%
+%
+%
+% \subsubsection{Hooks provided by \cs{begin}\texttt{\{document\}}}
+%
+% Until 2020 \cs{begin}\texttt{\{document\}} offered exactly one
+% hook that one had to fill using \cs{AtBeginDocument}. Experience
+% has shown that this single hook in one place was not enough and
+% as part of adding the general hook management system a number of
+% additional hooks have been added at this point. The places for
+% hooks have been chosen to provide the same support as offered by
+% external packages, such as \pkg{etoolbox} and others that
+% augmented \cs{document} to gain better control.
+%
+% Supported are now the following hooks:
+% \begin{description}
+%
+% \item[\hook{env/document/before}]
+%
+% This is the generic environment hook executed effectively
+% before \verb=\begin{document}= starts, i.e., one can think of
+% it as a hook for code at the end of the preamble section.
+%
+% \item[\hook{env/document/begin}]
+%
+% This is the second generic environment hook that is executed
+% after the environment has started its group. But given that for the
+% \texttt{document} environment this group is canceled there is
+% little difference to the previous one as the two are directly
+% executed one after another (the only difference is that in this
+% hook \cs{@currenvir} is now set to \texttt{document} but
+% anybody adding to this hook would know that already).
+%
+%
+% \item[\hook{begindocument}]
+%
+% This hook is added to by \cs{AtBeginDocument} and is executed
+% after the \texttt{.aux} file as be read in and most
+% initialization are done, so they can be altered and inspected by
+% the hook code. It is followed by a small number of further
+% initializations that shouldn't be altered and are therefore
+% coming later.
+%
+% \item[\hook{begindocument/end}]
+%
+% This hook is executed at the end of the \cs{document} code in
+% other words at the beginning of the document body. The only
+% command that follows it is \cs{ignorespaces}.
+%
+% \end{description}
+%
+%
+%
+%
+% \subsubsection{Hooks provided by \cs{end}\texttt{\{document\}}}
+%
+% \LaTeXe{} always provided \cs{AtEndDocument} to add code to the
+% execution of \verb=\end{document}= just in front of the code that
+% is normally executed there. While this was a big improvement over
+% the situation in \LaTeX\,2.09 it was not flexible enough for a
+% number of use cases and so packages, such as \pkg{etoolbox},
+% \pkg{atveryend} and others patched \cs{enddocument} to add
+% additional points where code could be hooked into.
+%
+% Patching using packages is always problematical as leads to
+% conflicts (code availability, ordering of patches, incompatible
+% patches, etc.). For this reason a number of additional hooks
+% have been added to the \cs{enddocument} code to allow packages
+% to add code in various places in a controlled way without the
+% need for overwriting or patching the core code.
+%
+% Supported are now the following hooks:
+% \begin{description}
+%
+% \item[\hook{env/document/end}] The generic hook inside \cs{end}.
+%
+% \item[\hook{enddocument}]
+
+% The hook associated with \cs{AtEndDocument}. It is immediately
+% called after the previous hook so there could be just
+% one.\footnote{We could make \cs{AtEndDocument} just fill the
+% \hook{env/document/end} but maybe that is a bit confusing.}
+%
+% When this hook is executed there may be still unprocessed
+% material (e.g., floats on the deferlist) and the hook may add
+% further material to be typeset. After it, \cs{clearpage} is
+% called to ensure that all such material gets typeset. If there
+% is nothing waiting the \cs{clearpage} has no effect.
+%
+%
+% \item[\hook{enddocument/afterlastpage}]
+%
+% As the name indicates this hook should not receive code that
+% generates material for further pages. It is the right place to
+% do some final housekeeping and possibly write out some
+% information to the \texttt{.aux} file (which is still open at
+% this point to receive data). It is also the correct place to
+% set up any testing code to be run when the \texttt{.aux} file
+% is re-read in the next step.
+%
+%
+% After this hook has been executed the \texttt{.aux} file is
+% closed for writing and then read back in to do some tests
+% (e.g., looking for missing references or duplicated labels, etc.).
+%
+% \item[\hook{enddocument/afteraux}]
+%
+% At this point, the \texttt{.aux} file has been reprocessed and so
+% this is a possible place for final checks and display of
+% information to the user. However, for the latter you might
+% prefer the next hook, so that your information is displayed after the
+% (possibly longish) list of files if that got requested via \cs{listfiles}.
+%
+% \item[\hook{enddocument/info}]
+%
+% This hook is meant to receive code that write final information
+% messages to the terminal. It follows immediately after the
+% previous hook (so both could have been combined, but then
+% packages adding further code would always need to also supply
+% an explicit rule to specify where it should go.
+%
+% This hook already contains some code added by the kernel (under
+% the labels \texttt{kernel/filelist} and
+% \texttt{kernel/warnings}), namely the list of files when
+% \cs{listfiles} has been used and the warnings for duplicate
+% labels, missing references, font substitutions etc.
+%
+% \item[\hook{enddocument/end}]
+%
+% Finally, this hook is executed just in front of the final call
+% to \cs{@{}@end}.
+%
+% \end{description}
+%
+%
+% There is also the hook \hook{shipout/lastpage}. This hook is
+% executed as part of the last \cs{shipout} in the document to
+% allow package to add final \cs{special}'s to that page. Where
+% this hook is executed in relation to those from the above list
+% can vary from document to document. Furthermore to determine correctly
+% which of the \cs{shipout}s is the last one, \LaTeX{} needs to be run
+% several times, so initially it might get executed on the wrong
+% page. See section~\ref{sec:shipout} for where to find the details.
+%
+%
+% \subsubsection{Hooks provided \cs{shipout} operations}
+% \label{sec:shipout}
+%
+% There are several hooks and mechanisms added to \LaTeX{}'s
+% process of generating pages. These are documented in
+% \texttt{ltshipout-doc.pdf} or with code in
+% \texttt{ltshipout-code.pdf}.
+%
+%
+% \subsubsection{Hooks provided file loading operations}
+%
+% There are several hooks added to \LaTeX{}'s
+% process of loading file via its high-level interfaces such as
+% \cs{input}, \cs{include}, \cs{usepackage}, etc. These are documented in
+% \texttt{ltfilehook-doc.pdf} or with code in
+% \texttt{ltfilehook-code.pdf}.
+%
+%
+
+% \StopEventually{\setlength\IndexMin{200pt} \PrintIndex }
+%
+%
+% \section{The Implementation}
+% \begin{macrocode}
+%<@@=hook>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*2ekernel>
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ExplSyntaxOn
+% \end{macrocode}
+%
+%
+% \subsection{Debugging}
+%
+% \begin{macro}{\g_@@_debug_bool}
+% Holds the current debugging state.
+% \begin{macrocode}
+\bool_new:N \g_@@_debug_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\hook_debug_on:,\hook_debug_off:}
+% \begin{macro}{\@@_debug:n}
+% \begin{macro}{\@@_debug_gset:}
+% Turns debugging on and off by redefining \cs{@@_debug:n}.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_debug:n \use_none:n
+\cs_new_protected:Npn \hook_debug_on:
+ {
+ \bool_gset_true:N \g_@@_debug_bool
+ \@@_debug_gset:
+ }
+\cs_new_protected:Npn \hook_debug_off:
+ {
+ \bool_gset_false:N \g_@@_debug_bool
+ \@@_debug_gset:
+ }
+\cs_new_protected:Npn \@@_debug_gset:
+ {
+ \cs_gset_protected:Npx \@@_debug:n ##1
+ { \bool_if:NT \g_@@_debug_bool {##1} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+
+%
+%
+% \subsection{Borrowing from internals of other kernel modules}
+%
+%
+% \begin{macro}[EXP]{\@@_str_compare:nn}
+% Private copy of \cs{__str_if_eq:nn}
+% \begin{macrocode}
+\cs_new_eq:NN \@@_str_compare:nn \__str_if_eq:nn
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Declarations}
+%
+% \begin{macro}{\l_@@_return_tl,\l_@@_tmpa_tl,\l_@@_tmpb_tl}
+% Scratch variables used throughout the package.
+% \begin{macrocode}
+\tl_new:N \l_@@_return_tl
+\tl_new:N \l_@@_tmpa_tl
+\tl_new:N \l_@@_tmpb_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\g_@@_all_seq}
+% In a few places we need a list of all hook names ever defined so
+% we keep track if them in this sequence.
+% \begin{macrocode}
+\seq_new:N \g_@@_all_seq
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\g_@@_removal_list_prop}
+% A property list to hold delayed removals.
+% \begin{macrocode}
+\tl_new:N \g_@@_removal_list_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_cur_hook_tl}
+% Stores the name of the hook currently being sorted.
+% \begin{macrocode}
+\tl_new:N \l_@@_cur_hook_tl
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\g_@@_code_temp_prop}
+% A property list to temporarily save the original one so that it
+% isn't permanently changed during sorting.
+% \begin{macrocode}
+\prop_new:N \g_@@_code_temp_prop
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\g_@@_hook_curr_name_tl,\g_@@_name_stack_seq}
+% Default label used for hook commands, and a stack to keep track of
+% packages within packages.
+% \begin{macrocode}
+\tl_new:N \g_@@_hook_curr_name_tl
+\seq_new:N \g_@@_name_stack_seq
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_tmp:w}
+% Temporary macro for generic usage.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_tmp:w ?
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tl_gremove_once:Nx}
+% Some variants of \pkg{expl3} functions. \fmi{should be moved to expl3}
+% \begin{macrocode}
+\cs_generate_variant:Nn \tl_gremove_once:Nn { Nx }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\s_@@_mark}
+% Scan mark used for delimited arguments.
+% \begin{macrocode}
+\scan_new:N \s_@@_mark
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Providing new hooks}
+%
+% \begin{macro}{\g_@@_..._code_prop,\g_@@_..._rules_prop,
+% \g_@@_..._code_tl,\g_@@_..._next_code_tl}
+%
+% Hooks have a \meta{name} and for each hook we have to provide a number of
+% data structures. These are
+% \begin{description}
+% \item[\cs{g_@@_\meta{name}_code_prop}] A property list holding the code
+% for the hook in separate chunks. The keys are by default the
+% package names that add code to the hook, but it is possible
+% for packages to define other keys.
+%
+% \item[\cs{g_@@_\meta{name}_rules_prop}] A property listing holding
+% relation info how the code chunks should be ordered within a
+% hook. This is used for debugging only. The actual rule for a
+% \meta{hook} is stored in a separate token lists named
+% \cs[no-index]{g_@@_\meta{hook}_rule_\meta{label1}\string|\meta{label2}_tl}
+% for a pair of labels.
+%
+% \item[\cs{g_@@_\meta{name}_code_tl}] The code that is actually executed
+% when the hook is called in the document is stored in this token
+% list. It is constructed from the code chunks applying the
+% information.
+%
+% \item[\cs{g_@@_\meta{name}_next_code_tl}] Finally there is extra code
+% (normally empty) that is used on the next invocation of the hook
+% (and then deleted). This can be used to define some special
+% behavior for a single occasion from within the document.
+%
+% \end{description}
+% \end{macro}
+
+
+%
+%
+% \begin{macro}{\hook_new:n}
+% The \cs{hook_new:n} declaration declare a new hook and expects
+% the hook \meta{name} as its argument, e.g.,
+% \hook{begindocument}.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_new:n #1
+ {
+ \exp_args:Nx \@@_new:n
+ { \@@_parse_label_default:nn {#1} { top-level } }
+ }
+\cs_new_protected:Npn \@@_new:n #1 {
+% \end{macrocode}
+% We check for one of the internal data structures and if it
+% already exists we complain.
+% \begin{macrocode}
+ \hook_if_exist:nTF {#1}
+ { \ErrorHookExists }
+% \end{macrocode}
+% Otherwise we add the hook name to the list of all hooks and
+% allocate the necessary data structures for the new hook.
+% \begin{macrocode}
+ { \seq_gput_right:Nn \g_@@_all_seq {#1}
+% \end{macrocode}
+% This is only used by the actual code of the current hook, so
+% declare it normally:
+% \begin{macrocode}
+ \tl_new:c { g_@@_#1_code_tl }
+% \end{macrocode}
+% Now ensure that the base data structure for the hook exists:
+% \begin{macrocode}
+ \@@_declare:n {#1}
+% \end{macrocode}
+% The \cs{g_@@_\meta{hook}_labels_clist} holds the sorted list of
+% labels (once it got sorted). This is used only for debugging.
+% \begin{macrocode}
+ \clist_new:c {g_@@_#1_labels_clist}
+% \end{macrocode}
+% Some hooks should reverse the default order of code chunks. To
+% signal this we have a token list which is empty for normal hooks
+% and contains a \verb=-= for reversed hooks.
+% \begin{macrocode}
+ \tl_new:c { g_@@_#1_reversed_tl }
+% \end{macrocode}
+% The above is all in L3 convention, but we also provide an
+% interface to legacy \LaTeXe{} for use in the current kernel. This
+% is done in a separate macro.
+% \begin{macrocode}
+ \@@_provide_legacy_interface:n {#1}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+%
+%
+% \begin{macro}{\@@_declare:n}
+% This function declares the basic data structures for a hook without
+% actually declaring the hook itself. This is needed to allow adding
+% to undeclared hooks. Here it is unnecessary to check whether both
+% variables exist, since both are declared at the same time (either
+% both exist, or neither).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_declare:n #1
+ {
+ \@@_if_exist:nF {#1}
+ {
+ \prop_new:c { g_@@_#1_code_prop }
+ \tl_new:c { g_@@_#1_next_code_tl }
+ \prop_new:c { g_@@_#1_rules_prop } % only for debugging
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\hook_new_reversed:n}
+%
+% Declare a new hook. The default ordering of code chunks is
+% reversed, signaled by setting the token list to a minus sign.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_new_reversed:n #1 {
+ \hook_new:n {#1}
+ \tl_gset:cn { g_@@_#1_reversed_tl } { - }
+}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\hook_new_pair:nn}
+% A shorthand for declaring a normal and a (matching) reversed hook in one go.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_new_pair:nn #1#2 {
+ \hook_new:n {#1} \hook_new_reversed:n {#2}
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_provide_legacy_interface:n}
+% The \LaTeX{} legacy concept for hooks uses with hooks the
+% following naming scheme in the code: \cs{@...hook}.
+%
+% We follow this convention and insert the hook code using this
+% naming scheme in \LaTeXe{}. At least as long as this code is in a
+% package, some such hooks are already filled with data when we move
+% them over to the new scheme. We therefore insert already existing
+% code under the label \texttt{legacy} into the hook management
+% machinery and then replace the \cs{@...hook} with its counterpart
+% which is \cs{g_@@_\#1_code_tl}.\footnote{This means one extra
+% unnecessary expansion on each invocation in the document but
+% keeps the \LaTeXe{} and the L3 coding side properly separated.}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_provide_legacy_interface:n #1
+ {
+% \end{macrocode}
+% If the \pkg{expl3} code is run with checking on then assigning or
+% using non L3 names such as \cs{@enddocumenthook} with \pkg{expl3}
+% functions will trigger warnings so we run this code with
+% debugging explicitly suspended.
+% \begin{macrocode}
+ \debug_suspend:
+ \tl_if_exist:cT { @#1hook }
+% \end{macrocode}
+% Of course if the hook exists but is still empty, there is no need
+% to add anything under \texttt{legacy} or the current package name.
+% \begin{macrocode}
+ {
+ \tl_if_empty:cF { @#1hook }
+ {
+ \@@_gput_code:nxv {#1}
+ { \@@_parse_label_default:Vn \c_novalue_tl { legacy } }
+ { @#1hook }
+ }
+ }
+% \end{macrocode}
+% We need a global definition in case the declaration is done
+% inside a group (which happens below at the end of the file).
+% This is another reason why need to suspend checking, otherwise
+% \cs{tl_gset:co} would complain about \cs{@...hook} not starting
+% with \cs{g_}.
+% \begin{macrocode}
+ \tl_gset:co{@#1hook}{\cs:w g_@@_#1_code_tl\cs_end:}
+ \debug_resume:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Parsing a label}
+%
+% \begin{macro}[EXP]{\@@_parse_label_default:nn,\@@_parse_label_default:Vn}
+% This macro checks if a label was given (not \cs{c_novalue_tl}), and
+% if so, tries to parse the label looking for a leading \verb|.| to
+% replace for \cs{@currname}. Otherwise \cs{@@_currname_or_default:n}
+% is used to pick \cs{@currname} or the fallback value.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_label_default:nn #1 #2
+ {
+ \tl_if_novalue:nTF {#1}
+ { \@@_currname_or_default:n {#2} }
+ { \tl_trim_spaces_apply:nN {#1} \@@_parse_dot_label:nn {#2} }
+ }
+\cs_generate_variant:Nn \@@_parse_label_default:nn { V }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_parse_dot_label:nn}
+% \begin{macro}[EXP]{
+% \@@_parse_dot_label:nw,
+% \@@_parse_dot_label_cleanup:w,
+% \@@_parse_dot_label_aux:nw
+% }
+% Start by checking if the label is empty, which raises an error, and
+% uses the fallback value. If not,
+% split the label at a \verb|./|, if any, and check if no tokens are
+% before the \verb|./|, or if the only character is a \verb|.|.
+% If these requirements are fulfilled, the leading
+% \verb|.| is replaced with \cs{@@_currname_or_default:n}. Otherwise
+% the label is returned unchanged.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_dot_label:nn #1 #2
+ {
+ \tl_if_empty:nTF {#1}
+ {
+ \msg_expandable_error:nnn { hooks } { empty-label } {#2}
+ #2
+ }
+ {
+ \str_if_eq:nnTF {#1} { . }
+ { \@@_currname_or_default:n {#1} }
+ { \@@_parse_dot_label:nw {#2} #1 ./ \s_@@_mark }
+ }
+ }
+\cs_new:Npn \@@_parse_dot_label:nw #1 #2 ./ #3 \s_@@_mark
+ {
+ \tl_if_empty:nTF {#2}
+ { \@@_parse_dot_label_aux:nw {#1} #3 \s_@@_mark }
+ {
+ \tl_if_empty:nTF {#3}
+ {#2}
+ { \@@_parse_dot_label_cleanup:w #2 ./ #3 \s_@@_mark }
+ }
+ }
+\cs_new:Npn \@@_parse_dot_label_cleanup:w #1 ./ \s_@@_mark {#1}
+\cs_new:Npn \@@_parse_dot_label_aux:nw #1 #2 ./ \s_@@_mark
+ { \@@_currname_or_default:n {#1} / #2 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_currname_or_default:n}
+% Uses \cs{g_@@_hook_curr_name_tl} if it is set, otherwise tries
+% \cs{@currname}. If neither is set, uses the fallback value
+% \verb|#1| (usually \texttt{top-level}).
+% \begin{macrocode}
+\cs_new:Npn \@@_currname_or_default:n #1
+ {
+ \tl_if_empty:NTF \g_@@_hook_curr_name_tl
+ {
+ \tl_if_empty:NTF \@currname
+ {#1}
+ { \@currname }
+ }
+ { \g_@@_hook_curr_name_tl }
+ }
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \begin{macro}{\hook_gput_code:nnn}
+% \begin{macro}{\@@_gput_code:nnn,\@@_gput_code:nxv,\@@_hook_gput_code_do:nnn}
+%
+% With \cs{hook_gput_code:nnn}\Arg{hook}\Arg{label}\Arg{code} a
+% chunk of \meta{code} is added to an existing \meta{hook} labeled
+% with \meta{label}.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_gput_code:nnn #1 #2
+ {
+ \exp_args:Nxx \@@_gput_code:nnn
+ { \@@_parse_label_default:nn {#1} { top-level } }
+ { \@@_parse_label_default:nn {#2} { top-level } }
+ }
+\cs_new_protected:Npn \@@_gput_code:nnn #1 #2 #3
+ {
+% \end{macrocode}
+% First we check if the hook exists.
+% \begin{macrocode}
+ \@@_if_marked_removal:nnTF {#1} {#2}
+ { \@@_unmark_removal:nn {#1} {#2} }
+ {
+% \end{macrocode}
+% First we check if the hook exists.
+% \begin{macrocode}
+ \hook_if_exist:nTF {#1}
+% \end{macrocode}
+% If so we simply add (or append) the new code to the property list
+% holding different chunks for the hook. At \verb=\begin{document}=
+% this is then sorted into a token list for fast execution.
+% \begin{macrocode}
+ {
+ \@@_hook_gput_code_do:nnn {#1} {#2} {#3}
+% \end{macrocode}
+% However, if there is an update within the document we need to alter
+% this execution code which is done by
+% \cs{@@_update_hook_code:n}. In the preamble this does nothing.
+% \begin{macrocode}
+ \@@_update_hook_code:n {#1}
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+ { \@@_try_declaring_generic_hook:nnn {#1} {#2} {#3} }
+ }
+ }
+\cs_generate_variant:Nn \@@_gput_code:nnn { nxv }
+% \end{macrocode}
+%
+% This macro will unconditionally add a chunk of code to the given hook.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_hook_gput_code_do:nnn #1 #2 #3
+ {
+% However, first some debugging info if debugging is enabled:
+% \begin{macrocode}
+ \@@_debug:n{\iow_term:x{****~ Add~ to~
+ \hook_if_exist:nF {#1} { undeclared~ }
+ hook~ #1~ (#2)
+ \on@line\space <-~ \tl_to_str:n{#3}} }
+% \end{macrocode}
+% Then try to get the code chunk labeled \verb=#2= from the hook.
+% If there's code already there, then append \verb=#3= to that,
+% otherwise just put \verb=#3=.
+% \begin{macrocode}
+ \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+ {
+ \prop_gput:cno { g_@@_#1_code_prop } {#2}
+ { \l_@@_return_tl #3 }
+ }
+ { \prop_gput:cnn { g_@@_#1_code_prop } {#2} {#3} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_gput_undeclared_hook:nnn}
+% Often it may happen that a package $A$ defines a hook \verb=foo=,
+% but package $B$, that adds code to that hook, is loaded before $A$.
+% In such case we need to add code to the hook before its declared.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_gput_undeclared_hook:nnn #1 #2 #3
+ {
+ \@@_declare:n {#1}
+ \@@_hook_gput_code_do:nnn {#1} {#2} {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_try_declaring_generic_hook:nnn}
+% \begin{macro}{\@@_try_declaring_generic_next_hook:nn}
+% These entry-level macros just pass the arguments along to the
+% common \cs{@@_try_declaring_generic_hook:nNNnn} with the right
+% functions to execute when some action is to be taken.
+%
+% The wrapper \cs{@@_try_declaring_generic_hook:nnn} then defers
+% \cs{hook_gput_code:nnn} if the generic hook was declared, or to
+% \cs{@@_gput_undeclared_hook:nnn} otherwise (the hook was tested for
+% existence before, so at this point if it isn't generic, it doesn't
+% exist).
+%
+% The wrapper \cs{@@_try_declaring_generic_next_hook:nn} for
+% next-execution hooks does the same: it defers the code to
+% \cs{hook_gput_next_code:nn} if the generic hook was declared, or
+% to \cs{@@_gput_next_do:nn} otherwise.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_try_declaring_generic_hook:nnn #1
+ {
+ \@@_try_declaring_generic_hook:nNNnn {#1}
+ \hook_gput_code:nnn \@@_gput_undeclared_hook:nnn
+ }
+\cs_new_protected:Npn \@@_try_declaring_generic_next_hook:nn #1
+ {
+ \@@_try_declaring_generic_hook:nNNnn {#1}
+ \hook_gput_next_code:nn \@@_gput_next_do:nn
+ }
+% \end{macrocode}
+%
+% \begin{macro}{
+% \@@_try_declaring_generic_hook:nNNnn,
+% \@@_try_declaring_generic_hook_split:nNNnn
+% }
+% \begin{macro}[TF]{\@@_try_declaring_generic_hook:wn}
+% \cs{@@_try_declaring_generic_hook:nNNnn} now splits the hook name
+% at the first \texttt{/} (if any) and first checks if it is a
+% file-specific hook (they require some normalization) using
+% \cs{@@_if_file_hook:wTF}. If not then check it is one of a
+% predefined set for generic names. We also split off the second
+% component to see if we have to make a reversed hook. In either case
+% the function returns \meta{true} for a generic hook and \meta{false}
+% in other cases.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_try_declaring_generic_hook:nNNnn #1
+ {
+ \@@_if_file_hook:wTF #1 / / \s_@@_mark
+ {
+ \exp_args:Ne \@@_try_declaring_generic_hook_split:nNNnn
+ { \exp_args:Ne \@@_file_hook_normalise:n {#1} }
+ }
+ { \@@_try_declaring_generic_hook_split:nNNnn {#1} }
+ }
+\cs_new_protected:Npn \@@_try_declaring_generic_hook_split:nNNnn #1 #2 #3
+ {
+ \@@_try_declaring_generic_hook:wnTF #1 / / / \scan_stop: {#1}
+ { #2 }
+ { #3 } {#1}
+ }
+\prg_new_protected_conditional:Npnn \@@_try_declaring_generic_hook:wn
+ #1 / #2 / #3 / #4 \scan_stop: #5 { TF }
+ {
+ \tl_if_empty:nTF {#2}
+ { \prg_return_false: }
+ {
+ \prop_if_in:NnTF \c_@@_generics_prop {#1}
+ {
+ \hook_if_exist:nF {#5} { \hook_new:n {#5} }
+% \end{macrocode}
+% After having declared the hook we check the second component (for
+% file hooks) or the third component for environment hooks) and
+% if it is on the list of components for which we should have declared
+% a reversed hook we alter the hook data structure accordingly.
+% \begin{macrocode}
+ \prop_if_in:NnTF \c_@@_generics_reversed_ii_prop {#2}
+ { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
+ {
+ \prop_if_in:NnT \c_@@_generics_reversed_iii_prop {#3}
+ { \tl_gset:cn { g_@@_#5_reversed_tl } { - } }
+ }
+% \end{macrocode}
+% Now that we know that the hook is declared we can add the code to it.
+% \begin{macrocode}
+ \prg_return_true:
+ }
+ { \prg_return_false: }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\@@_if_file_hook:w}
+% \cs{@@_if_file_hook:wTF} checks if the argument is a valid
+% file-specific hook (not, for example, |file/before|, but
+% |file/before/foo.tex|). If it is a file-specific hook, then it
+% executes the \meta{true} branch, otherwise \meta{false}.
+%
+% A file-specific hook is \texttt{file/\meta{position}/\meta{name}}.
+% If any of these parts don't exist, it is a general file hook or not
+% a file hook at all, so the conditional evaluates to \meta{false}.
+% Otherwise, it checks that the first part is |file| and that the
+% \meta{position} is in the \cs{c_@@_generics_file_prop}.
+%
+% A property list is used here to avoid having to worry with catcodes,
+% because \pkg{expl3}'s file name parsing turns all characters into
+% catcode-12 tokens, which might differ from hand-input letters.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_file_hook:w
+ #1 / #2 / #3 \s_@@_mark { TF }
+ {
+ \str_if_eq:nnTF {#1} { file }
+ {
+ \bool_lazy_or:nnTF
+ { \tl_if_empty_p:n {#3} }
+ { \str_if_eq_p:nn {#3} { / } }
+ { \prg_return_false: }
+ {
+ \prop_if_in:NnTF \c_@@_generics_file_prop {#2}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_file_hook_normalise:n}
+% \begin{macro}[EXP]{\@@_strip_double_slash:n,\@@_strip_double_slash:w}
+% When a file-specific hook is found, before being declared it is
+% lightly normalized by \cs{@@_file_hook_normalise:n}. The current
+% implementation just replaces two consecutive slashes (|//|) by a
+% single one, to cope with simple cases where the user did something
+% like \verb|\def\input@path{{./mypath/}}|, in which case a hook would
+% have to be \verb|\AddToHook{file/after/./mypath//file.tex}|.
+% \begin{macrocode}
+\cs_new:Npn \@@_file_hook_normalise:n #1
+ { \@@_strip_double_slash:n {#1} }
+\cs_new:Npn \@@_strip_double_slash:n #1
+ { \@@_strip_double_slash:w #1 // \s_@@_mark }
+\cs_new:Npn \@@_strip_double_slash:w #1 // #2 \s_@@_mark
+ {
+ \tl_if_empty:nTF {#2}
+ {#1}
+ { \@@_strip_double_slash:w #1 / #2 \s_@@_mark }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+
+
+
+
+
+% \begin{macro}{\c_@@_generics_prop}
+% Clist holding the generic names. We don't provide any user
+% interface to this as this is meant to be static.
+% \begin{description}
+% \item[\texttt{env}]
+% The generic hooks used in \cs{begin} and \cs{end}.
+% \item[\texttt{file}]
+% The generic hooks used when loading a file
+% \end{description}
+% \begin{macrocode}
+\prop_const_from_keyval:Nn \c_@@_generics_prop
+ {env=,file=,package=,class=,include=}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\c_@@_generics_reversed_ii_prop,
+% \c_@@_generics_reversed_iii_prop,
+% \c_@@_generics_file_prop}
+% Some of the generic hooks are supposed to use reverse ordering, these are
+% the following (only the second or third sub-component is checked):
+% \begin{macrocode}
+\prop_const_from_keyval:Nn \c_@@_generics_reversed_ii_prop {after=,end=}
+\prop_const_from_keyval:Nn \c_@@_generics_reversed_iii_prop {after=}
+\prop_const_from_keyval:Nn \c_@@_generics_file_prop {before=,after=}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_update_hook_code:n}
+% Before \verb=\begin{document}= this does nothing, in the body it
+% reinitializes the hook code using the altered data.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_update_hook_code:n \use_none:n
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\hook_gremove_code:nn}
+% \begin{macro}{\@@_gremove_code:nn}
+%
+% With \cs{hook_gremove_code:nn}\Arg{hook}\Arg{label} any code
+% for \meta{hook} stored under \meta{label} is removed.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_gremove_code:nn #1 #2
+ {
+ \exp_args:Nxx \@@_gremove_code:nn
+ { \@@_parse_label_default:nn {#1} { top-level } }
+ { \@@_parse_label_default:nn {#2} { top-level } }
+ }
+\cs_new_protected:Npn \@@_gremove_code:nn #1 #2
+ {
+% \end{macrocode}
+% First check that the hook code pool exists. \cs{hook_if_exist:nTF}
+% isn't used here because it should be possible to remove code from a
+% hook before its defined (see section~\ref{sec:querying}).
+% \begin{macrocode}
+ \@@_if_exist:nTF {#1}
+% \end{macrocode}
+% Then remove the chunk and run \cs{@@_update_hook_code:n} so
+% that the execution token list reflects the change if we are after
+% \verb=\begin{document}=.
+% \begin{macrocode}
+ {
+ \str_if_eq:nnTF {#2} {*}
+ {
+ \prop_gclear:c { g_@@_#1_code_prop }
+ \clist_gclear:c { g_@@_#1_labels_clist } % for debugging only
+ }
+ {
+% \end{macrocode}
+% Check if the label being removed exists in the code pool. If it does,
+% just call \cs{@@_gremove_code_do:nn} to do the removal, otherwise mark it
+% to be removed.
+% \begin{macrocode}
+ \prop_get:cnNTF { g_@@_#1_code_prop } {#2} \l_@@_return_tl
+ { \@@_gremove_code_do:nn }
+ { \@@_mark_removal:nn }
+ {#1} {#2}
+ }
+% \end{macrocode}
+% Finally update the code, if the hook exists.
+% \begin{macrocode}
+ \hook_if_exist:nT {#1}
+ { \@@_update_hook_code:n {#1} }
+ }
+ { \@@_mark_removal:nn {#1} {#2} }
+ }
+% \end{macrocode}
+%
+% \begin{macro}{\@@_gremove_code_do:nn}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_gremove_code_do:nn #1 #2
+ {
+ \prop_gremove:cn { g_@@_#1_code_prop } {#2}
+% \end{macrocode}
+% Removing the dropped label from \verb=\g_@@_#1_labels_clist= is
+% rather tricky, because that clists holds the labels as strings
+% (i.e., not ordinary text which is what we have in \verb=#2=).
+% \begin{macrocode}
+ \exp_args:Nco \clist_gremove_all:Nn
+ { g_@@_#1_labels_clist } { \tl_to_str:n {#2} } % for debugging only
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+
+
+%
+% \begin{macro}{\@@_mark_removal:nn}
+% Marks \meta{label} (\verb=#2=) to be removed from \meta{hook}
+% (\verb=#1=).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_mark_removal:nn #1 #2
+ {
+ \tl_gput_right:Nx \g_@@_removal_list_tl
+ { \@@_removal_tl:nn {#1} {#2} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_unmark_removal:nn}
+% Unmarks \meta{label} (\verb=#2=) to be removed from \meta{hook}
+% (\verb=#1=). \cs{tl_gremove_once:Nx} is used rather than
+% \cs{tl_gremove_all:Nx} so that two additions are needed to cancel
+% two marked removals, rather than only one.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_unmark_removal:nn #1 #2
+ {
+ \tl_gremove_once:Nx \g_@@_removal_list_tl
+ { \@@_removal_tl:nn {#1} {#2} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[TF]{\@@_if_marked_removal:nn}
+% Checks if the \cs{g_@@_removal_list_tl} contains the current
+% \meta{label} (\verb=#2=) and \meta{hook} (\verb=#1=).
+% \begin{macrocode}
+\prg_new_protected_conditional:Npnn \@@_if_marked_removal:nn #1 #2 { TF }
+ {
+ \exp_args:NNx \tl_if_in:NnTF \g_@@_removal_list_tl
+ { \@@_removal_tl:nn {#1} {#2} }
+ { \prg_return_true: } { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[rEXP]{\@@_removal_tl:nn}
+% Builds a token list with \verb=#1= and \verb=#2= which can only be
+% matched by \verb=#1= and \verb=#2=.
+% \begin{macrocode}
+\cs_new:Npn \@@_removal_tl:nn #1 #2
+ { & \tl_to_str:n {#2} $ \tl_to_str:n {#1} $ }
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+%
+%
+%
+% \begin{macro}{
+% \g_@@_??_rules_prop,
+% \g_@@_??_code_prop,
+% \g_@@_??_code_tl,
+% \g_@@_??_reversed_tl,
+% }
+%
+% Default rules applying to all hooks are stored in this property
+% list. Initially it simply used an empty ``label'' name (not two
+% question marks). This was a bit unfortunate, because then
+% \texttt{l3doc} complains about \verb=__= in the middle of a
+% command name when trying to typeset the documentation. However
+% using a ``normal'' name such as \texttt{default} has the
+% disadvantage of that being not really distinguishable from a real
+% hook name. I now have settled for \texttt{??} which needs some
+% gymnastics to get it into the csname, but since this is used a
+% lot things should be fast, so this is not done with \texttt{c}
+% expansion in the code later on.
+%
+% \cs{g_@@_??_code_tl} isn't used, but it has to be defined to trick
+% the code into thinking that \verb=??= is actually a hook.
+% \begin{macrocode}
+\prop_new:c {g_@@_??_rules_prop}
+\prop_new:c {g_@@_??_code_prop}
+\prop_new:c {g_@@_??_code_tl}
+% \end{macrocode}
+%
+% Default rules are always given in normal ordering (never in
+% reversed ordering). If such a rule is applied to a reversed
+% hook it behaves as if the rule is reversed (e.g.,
+% \texttt{after} becomes \texttt{before})
+% because those rules are applied first and then the order is reversed.
+% \begin{macrocode}
+\tl_new:c {g_@@_??_reversed_tl}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\@@_debug_gset_rule:nnnn}
+%
+% \fmi{this needs cleanup and docu correction!}
+%
+% With
+% \cs{@@_debug_gset_rule:nnnn}\Arg{hook}\Arg{label1}\Arg{relation}\Arg{label2}
+% a relation is defined between the two code labels for the given
+% \meta{hook}. The special hook \texttt{??} stands for \emph{any}
+% hook describing a default rule.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_debug_gset_rule:nnnn #1#2#3#4
+ {
+% \end{macrocode}
+% If so we drop any existing rules with the two labels (in case
+% there are any).
+% \begin{macrocode}
+ \prop_gremove:cn{g_@@_#1_rules_prop}{#2|#4}
+ \prop_gremove:cn{g_@@_#1_rules_prop}{#4|#2}
+% \end{macrocode}
+% Then we add the new one (normalizing the input a bit, e.g., we
+% always use \texttt{before} and not \texttt{after} and
+% instead reorder the labels):
+% \begin{macrocode}
+ \str_case_e:nnF {#3}
+ {
+ {before} { \prop_gput:cnn {g_@@_#1_rules_prop}{#2|#4}{<} }
+ {after} { \prop_gput:cnn {g_@@_#1_rules_prop}{#4|#2}{<} }
+% \end{macrocode}
+% More special rule types \ldots
+% \begin{macrocode}
+ {incompatible-error} { \prop_gput:cnn {g_@@_#1_rules_prop}{#2|#4}{xE} }
+ {incompatible-warning} { \prop_gput:cnn {g_@@_#1_rules_prop}{#2|#4}{xW} }
+ {removes} { \prop_gput:cnn {g_@@_#1_rules_prop}{#2|#4}{->} }
+% \end{macrocode}
+% Undo a setting:
+% \begin{macrocode}
+ {unrelated}{ \prop_gremove:cn {g_@@_#1_rules_prop}{#2|#4}
+ \prop_gremove:cn {g_@@_#1_rules_prop}{#4|#2} }
+ }
+ { \ERRORunknownrule }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Setting rules for hooks code}
+%
+% \begin{macro}{\hook_gset_rule:nnnn}
+% \begin{macro}{\@@_gset_rule:nnnn}
+%
+% \fmi{needs docu correction given new implementation}
+%
+% With
+% \cs{hook_gset_rule:nnnn}\Arg{hook}\Arg{label1}\Arg{relation}\Arg{label2}
+% a relation is defined between the two code labels for the given
+% \meta{hook}. The special hook \texttt{??} stands for \emph{any}
+% hook describing a default rule.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_gset_rule:nnnn #1#2#3#4
+ {
+ \use:x
+ {
+ \@@_gset_rule:nnnn
+ { \@@_parse_label_default:nn {#1} { top-level } }
+ { \@@_parse_label_default:nn {#2} { top-level } }
+ {#3}
+ { \@@_parse_label_default:nn {#4} { top-level } }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_gset_rule:nnnn #1#2#3#4
+ {
+% \end{macrocode}
+% First we ensure the basic data structure of the hook exists:
+% \begin{macrocode}
+ \@@_declare:n {#1}
+% \end{macrocode}
+% Then we clear any previous relationship between both labels.
+% \begin{macrocode}
+ \@@_rule_gclear:nnn {#1} {#2} {#4}
+% \end{macrocode}
+% Then we call the function to handle the given rule. Throw an error if the
+% rule is invalid.
+% \begin{macrocode}
+ \debug_suspend:
+ \cs_if_exist_use:cTF { @@_rule_#3_gset:nnn }
+ {
+ {#1} {#2} {#4}
+ \@@_update_hook_code:n {#1}
+ }
+ { \ERRORunknownrule }
+ \debug_resume:
+ \@@_debug_gset_rule:nnnn {#1} {#2} {#3} {#4} % for debugging
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_rule_before_gset:nnn, \@@_rule_after_gset:nnn,
+% \@@_rule_<_gset:nnn, \@@_rule_>_gset:nnn}
+% Then we add the new rule. We need to normalize the rules here to
+% allow for faster processing later. Given a pair of labels
+% $l_A$ and $l_B$, the rule $l_A>l_B$ is the same as $l_B<l_A$\fmi{}
+% said differently. But normalizing the
+% forms of the rule to a single representation, say, $l_B<l_A$, then
+% the time spent looking for the rules later is considerably reduced.
+%
+% Here we do that normalization by using \cs[no-index]{(pdf)strcmp} to
+% lexically sort labels $l_A$ and $l_B$ to a fixed order. This order
+% is then enforced every time these two labels are used together.
+%
+% Here we use \cs{@@_label_pair:nn}~\Arg{hook}~\Arg{l_A}~\Arg{l_B}
+% to build a string \texttt{$l_B$\string|$l_A$} with a fixed order, and
+% use \cs{@@_label_ordered:nnTF} to apply the correct rule to the pair
+% of labels, depending if it was sorted or not.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_rule_before_gset:nnn #1#2#3
+ {
+ \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
+ { \@@_label_ordered:nnTF {#2} {#3} { < } { > } }
+ }
+\cs_new_eq:cN { @@_rule_<_gset:nnn } \@@_rule_before_gset:nnn
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_rule_after_gset:nnn #1#2#3
+ {
+ \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#3} {#2} _tl }
+ { \@@_label_ordered:nnTF {#3} {#2} { < } { > } }
+ }
+\cs_new_eq:cN { @@_rule_>_gset:nnn } \@@_rule_after_gset:nnn
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_rule_removes_gset:nnn}
+% This rule removes (clears, actually) the code from label |#3| if
+% label |#2| is in the hook |#1|.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_rule_removes_gset:nnn #1#2#3
+ {
+ \tl_gset:cx { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl }
+ { \@@_label_ordered:nnTF {#2} {#3} { -> } { <- } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_rule_incompatible-error_gset:nnn,
+% \@@_rule_incompatible-warning_gset:nnn,
+% }
+% These relations make an error/warning if labels |#2| and |#3| appear
+% together in hook |#1|.
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_rule_incompatible-error_gset:nnn } #1#2#3
+ { \tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xE } }
+\cs_new_protected:cpn { @@_rule_incompatible-warning_gset:nnn } #1#2#3
+ { \tl_gset:cn { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } { xW } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_rule_unrelated_gset:nnn, \@@_rule_gclear:nnn}
+% Undo a setting. \cs{@@_rule_unrelated_gset:nnn} doesn't need to do anything,
+% since we use \cs{@@_rule_gclear:nnn} before setting any rule.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_rule_unrelated_gset:nnn #1#2#3 { }
+\cs_new_protected:Npn \@@_rule_gclear:nnn #1#2#3
+ { \cs_undefine:c { g_@@_#1_rule_ \@@_label_pair:nn {#2} {#3} _tl } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_label_pair:nn}
+% Ensure that the lexically greater label comes first.
+% \begin{macrocode}
+\cs_new:Npn \@@_label_pair:nn #1#2
+ {
+ \if_case:w \@@_str_compare:nn {#1} {#2} \exp_stop_f:
+ #1 | #1 % 0
+ \or: #1 | #2 % +1
+ \else: #2 | #1 % -1
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\@@_label_ordered:nn}
+% Check that labels |#1| and |#2| are in the correct order (as
+% returned by \cs{@@_label_pair:nn}) and if so return true, else
+% return false.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_label_ordered:nn #1#2 { TF }
+ {
+ \if_int_compare:w \@@_str_compare:nn {#1} {#2} > 0 \exp_stop_f:
+ \prg_return_true:
+ \else
+ \prg_return_false:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_if_label_case:nnnnn}
+% To avoid doing the string comparison twice in \cs{@@_initialize_single:NNNNn}
+% (once with \cs{str_if_eq:nn} and again with \cs{@@_label_ordered:nn}),
+% we use a three-way branching macro that will compare |#1| and |#2|
+% and expand to \cs{use_i:nnn} if they are equal, \cs{use_ii:nn} if
+% |#1| is lexically greater, and \cs{use_iii:nn} otherwise.
+% \begin{macrocode}
+\cs_new:Npn \@@_if_label_case:nnnnn #1#2
+ {
+ \cs:w use_
+ \if_case:w \@@_str_compare:nn {#1} {#2}
+ i \or: ii \else: iii \fi: :nnn
+ \cs_end:
+ }
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_initialize_all:}
+% Initialize all known hooks (at \verb=\begin{document}=), i.e.,
+% update the fast execution token lists to hold the necessary code
+% in the right order.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_initialize_all: {
+% \end{macrocode}
+% First we change \cs{@@_update_hook_code:n} which so far was a
+% no-op to now initialize one hook. This way any later updates to
+% the hook will run that code and also update the execution token
+% list.
+% \begin{macrocode}
+ \cs_gset_eq:NN \@@_update_hook_code:n \@@_initialize_hook_code:n
+% \end{macrocode}
+% Now we loop over all hooks that have been defined and update each
+% of them.
+% \begin{macrocode}
+ \@@_debug:n { \prop_gclear:N \g_@@_used_prop }
+ \seq_map_inline:Nn \g_@@_all_seq
+ {
+ \@@_update_hook_code:n {##1}
+ }
+% \end{macrocode}
+% If we are debugging we show results hook by hook for all hooks
+% that have data.
+% \begin{macrocode}
+ \@@_debug:n
+ { \iow_term:x{^^JAll~ initialized~ (non-empty)~ hooks:}
+ \prop_map_inline:Nn \g_@@_used_prop
+ { \iow_term:x{^^J~ ##1~ ->~
+ \exp_not:v {g_@@_##1_code_tl}~ }
+ }
+ }
+%
+% \end{macrocode}
+% After all hooks are initialized we change the ``use'' to just
+% call the hook code and not initialize it (as it was done in the
+% preamble.
+% \begin{macrocode}
+ \cs_gset_eq:NN \hook_use:n \@@_use_initialized:n
+ \cs_gset_eq:NN \@@_preamble_hook:n \use_none:n
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\@@_initialize_hook_code:n}
+% Initializing or reinitializing the fast execution hook code. In
+% the preamble this is selectively done in case a hook gets used
+% and at \verb=\begin{document}= this is done for all hooks and
+% afterwards only if the hook code changes.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_initialize_hook_code:n #1 {
+ \@@_debug:n{ \iow_term:x{^^JUpdate~ code~ for~ hook~
+ '#1' \on@line :^^J} }
+% \end{macrocode}
+% This does the sorting and the updates. If there aren't any code
+% chunks for the current hook, there is no point in even starting
+% the sorting routine so we make a quick test for that and in that
+% case just update \cs{g_@@_\meta{hook}_code_tl} to hold the next
+% code. If there are code chunks we call
+% \cs{@@_initialize_single:NNNNn} and pass to it ready made csnames
+% as they are needed several times inside. This way we save a bit
+% on processing time if we do that up front.
+% \begin{macrocode}
+ \hook_if_exist:nT {#1}
+ {
+ \prop_if_empty:cTF {g_@@_#1_code_prop}
+ { \tl_gset:co {g_@@_#1_code_tl}
+ {\cs:w g_@@_#1_next_code_tl \cs_end: } }
+ {
+% \end{macrocode}
+% By default the algorithm sorts the code chunks and then saves the
+% result in a token list for fast execution by adding the code one
+% after another using \cs{tl_gput_right:NV}. When we sort code for
+% a reversed hook, all we have to do is to add the code chunks in
+% the opposite order into the token list. So all we have to do
+% in preparation is to change two definitions used later on.
+% \begin{macrocode}
+ \@@_if_reversed:nTF {#1}
+ { \cs_set_eq:NN \@@_tl_gput:NV \tl_gput_left:NV
+ \cs_set_eq:NN \@@_clist_gput:NV \clist_gput_left:NV }
+ { \cs_set_eq:NN \@@_tl_gput:NV \tl_gput_right:NV
+ \cs_set_eq:NN \@@_clist_gput:NV \clist_gput_right:NV }
+% \end{macrocode}
+%
+% When sorting, some relations (namely \verb|->| \verb|<-|) need to
+% act destructively on the code property lists to remove code that
+% shouldn't appear in the sorted hook token list.
+% \begin{macrocode}
+ \prop_gset_eq:Nc \g_@@_code_temp_prop { g_@@_#1_code_prop }
+ \@@_initialize_single:ccccn
+ { g_@@_#1_code_prop } { g_@@_#1_code_tl }
+ { g_@@_#1_next_code_tl } { g_@@_#1_labels_clist }
+ {#1}
+ \prop_gset_eq:cN { g_@@_#1_code_prop } \g_@@_code_temp_prop
+% \end{macrocode}
+% For debug display we want to keep track of those hooks that
+% actually got code added to them, so we record that in plist. We
+% use a plist to ensure that we record each hook name only once,
+% i.e., we are only interested in storing the keys and the value is arbitrary
+% \begin{macrocode}
+ \@@_debug:n{ \exp_args:NNx \prop_gput:Nnn \g_@@_used_prop {#1}{} }
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\g_@@_used_prop}
+% All hooks that receive code (for use in debugging display).
+% \begin{macrocode}
+\prop_new:N\g_@@_used_prop
+% \end{macrocode}
+% \end{macro}
+
+
+%
+% \begin{macro}[EXP]{\@@_tl_csname:n,\@@_seq_csname:n}
+% It is faster to pass a single token and expand it when necessary
+% than to pass a bunch of character tokens around.
+% \fmi{note to myself: verify}
+% \begin{macrocode}
+\cs_new:Npn \@@_tl_csname:n #1 { l_@@_label_#1_tl }
+\cs_new:Npn \@@_seq_csname:n #1 { l_@@_label_#1_seq }
+% \end{macrocode}
+% \end{macro}
+%
+
+%
+%
+% \begin{macro}{\l_@@_labels_seq,\l_@@_labels_int,\l_@@_front_tl,
+% \l_@@_rear_tl,\l_@@_label_0_tl}
+%
+% For the sorting I am basically implementing Knuth's algorithm for
+% topological sorting as given in TAOCP volume 1 pages 263--266.
+% For this algorithm we need a number of local variables:
+% \begin{itemize}
+% \item
+% List of labels used in the current hook to label code chunks:
+% \begin{macrocode}
+\seq_new:N \l_@@_labels_seq
+% \end{macrocode}
+% \item
+% Number of labels used in the current hook. In Knuth's algorithm
+% this is called $N$:
+% \begin{macrocode}
+\int_new:N \l_@@_labels_int
+% \end{macrocode}
+% \item
+% The sorted code list to be build is managed using two pointers
+% one to the front of the queue and one to the rear. We model this
+% using token list pointers. Knuth calls them $F$ and $R$:
+% \begin{macrocode}
+\tl_new:N \l_@@_front_tl
+\tl_new:N \l_@@_rear_tl
+% \end{macrocode}
+% \item
+% The data for the start of the queue is kept in this token list,
+% it corresponds to what Don calls \texttt{QLINK[0]} but since we
+% aren't manipulating individual words in memory it is slightly
+% differently done:
+% \begin{macrocode}
+\tl_new:c { \@@_tl_csname:n { 0 } }
+% \end{macrocode}
+%
+% \end{itemize}
+% \end{macro}
+
+
+% \begin{macro}{\@@_initialize_single:NNNNn,\@@_initialize_single:ccccn}
+%
+% \cs{@@_initialize_single:NNNNn} implements the sorting of the code
+% chunks for a hook and saves the result in the token list for fast
+% execution (\verb=#3=). The arguments are \meta{hook-code-plist},
+% \meta{hook-code-tl}, \meta{hook-next-code-tl},
+% \meta{hook-ordered-labels-clist} and \meta{hook-name} (the latter
+% is only used for debugging---the \meta{hook-rule-plist} is accessed
+% using the \meta{hook-name}).
+%
+% The additional complexity compared to Don's algorithm is that we
+% do not use simple positive integers but have arbitrary
+% alphanumeric labels. As usual Don's data structures are chosen in
+% a way that one can omit a lot of tests and I have mimicked that as
+% far as possible. The result is a restriction I do not test for at
+% the moment: a label can't be equal to the number 0! \fmi{Needs
+% checking for, just in case}
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_initialize_single:NNNNn #1#2#3#4#5 {
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \debug_suspend:
+% \end{macrocode}
+% Step T1: Initialize the data structure \ldots
+% \begin{macrocode}
+ \seq_clear:N \l_@@_labels_seq
+ \int_zero:N \l_@@_labels_int
+% \end{macrocode}
+%
+% Store the name of the hook:
+% \begin{macrocode}
+ \tl_set:Nn \l_@@_cur_hook_tl {#5}
+% \end{macrocode}
+%
+% We loop over the property list holding the code and record all
+% labels listed there. Only rules for those labels are of interest
+% to us. While we are at it we count them (which gives us the $N$
+% in Knuth's algorithm. The prefix |label_| is added to the variables
+% to ensure that labels named |front|, |rear|, |labels|, or |return|
+% don't interact with our code.
+% \begin{macrocode}
+ \prop_map_inline:Nn #1
+ {
+ \int_incr:N \l_@@_labels_int
+ \seq_put_right:Nn \l_@@_labels_seq {##1}
+ \tl_set:cn { \@@_tl_csname:n {##1} }{0} % the counter k for number of
+ % j before k rules
+ \seq_clear_new:c { \@@_seq_csname:n {##1} } % sequence of successors to k
+ % i.e., k before j rules (stores
+ % the names of the j's)
+ }
+% \end{macrocode}
+% Steps T2 and T3: Sort the relevant rules into the data structure\ldots
+%
+% This loop constitutes a square matrix of the labels in |#1| in the
+% vertical and the horizontal directions. However since the rule
+% $l_A\meta{rel}l_B$ is the same as $l_B\meta{rel}^{-1}l_A$ we can cut
+% the loop short at the diagonal of the matrix (\emph{i.e.}, when
+% both labels are equal), saving a good amount of time. The way the
+% rules were set up (see the implementation of \cs{@@_rule_before_gset:nnn}
+% above) ensures that we have no rule in the ignored side of the
+% matrix, and all rules are seen. The rules are applied in
+% \cs{@@_apply_label_pair:nnn}, which takes the properly-ordered pair
+% of labels as argument.
+% \begin{macrocode}
+ \prop_map_inline:Nn #1
+ {
+ \prop_map_inline:Nn #1
+ {
+ \@@_if_label_case:nnnnn {##1} {####1}
+ { \prop_map_break: }
+ { \@@_apply_label_pair:nnn {##1} {####1} }
+ { \@@_apply_label_pair:nnn {####1} {##1} }
+ {#5}
+ }
+ }
+% \end{macrocode}
+% Take a breath and take a look at the data structures that have
+% been set up:
+% \begin{macrocode}
+ \@@_debug:n { \@@_debug_label_data:N #1 }
+% \end{macrocode}
+%
+%
+% Step T4:
+% \begin{macrocode}
+ \tl_set:Nn \l_@@_rear_tl { 0 }
+ \tl_set:cn { \@@_tl_csname:n { 0 } } { 0 } % really {l_@@_label_ \l_@@_rear_tl _tl}
+ \seq_map_inline:Nn \l_@@_labels_seq
+ {
+ \int_compare:nNnT { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
+ {
+ \tl_set:cn { \@@_tl_csname:n { \l_@@_rear_tl } }{##1}
+ \tl_set:Nn \l_@@_rear_tl {##1}
+ }
+ }
+ \tl_set_eq:Nc \l_@@_front_tl { \@@_tl_csname:n { 0 } }
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \tl_gclear:N #2
+ \clist_gclear:N #4
+% \end{macrocode}
+%
+% The whole loop combines steps T5--T7:
+% \begin{macrocode}
+ \bool_while_do:nn { ! \str_if_eq_p:Vn \l_@@_front_tl { 0 } }
+ {
+% \end{macrocode}
+% This part is step T5:
+% \begin{macrocode}
+ \int_decr:N \l_@@_labels_int
+ \prop_get:NVN #1 \l_@@_front_tl \l_@@_return_tl
+ \@@_tl_gput:NV #2 \l_@@_return_tl
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \@@_clist_gput:NV #4 \l_@@_front_tl
+ \@@_debug:n{ \iow_term:x{Handled~ code~ for~ \l_@@_front_tl} }
+% \end{macrocode}
+%
+% This is step T6 except that we don't use a pointer $P$ to move
+% through the successors, but instead use \verb=##1= of the mapping
+% function.
+% \begin{macrocode}
+ \seq_map_inline:cn { \@@_seq_csname:n { \l_@@_front_tl } }
+ {
+ \tl_set:cx { \@@_tl_csname:n {##1} }
+ { \int_eval:n { \cs:w \@@_tl_csname:n {##1} \cs_end: - 1 } }
+ \int_compare:nNnT { \cs:w \@@_tl_csname:n {##1} \cs_end: } = 0
+ {
+ \tl_set:cn { \@@_tl_csname:n { \l_@@_rear_tl } } {##1}
+ \tl_set:Nn \l_@@_rear_tl {##1}
+ }
+ }
+% \end{macrocode}
+% and step T7:
+% \begin{macrocode}
+ \tl_set_eq:Nc \l_@@_front_tl { \@@_tl_csname:n { \l_@@_front_tl } }
+% \end{macrocode}
+%
+% This is step T8: If we haven't moved the code for all labels
+% (i.e., if \cs{l_@@_labels_int} is still greater than zero) we
+% have a loop and our partial order can't be flattened out.
+% \begin{macrocode}
+ }
+ \int_compare:nNnF \l_@@_labels_int = 0
+ {
+ \iow_term:x{====================}
+ \iow_term:x{Error:~ label~ rules~ are~ incompatible:}
+% \end{macrocode}
+%
+% This is not really the information one needs in the error case
+% but will do for now \ldots \fmi{fix}
+% \begin{macrocode}
+ \@@_debug_label_data:N #1
+ \iow_term:x{====================}
+ }
+% \end{macrocode}
+% After we have added all hook code to \verb=#2= we finish it off
+% with adding extra code for a one time execution. That is stored
+% in \verb=#3= but is normally empty.
+% \begin{macrocode}
+ \tl_gput_right:Nn #2 {#3}
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \debug_resume:
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_generate_variant:Nn \@@_initialize_single:NNNNn {cccc}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\@@_tl_gput:NV,\@@_clist_gput:NV}
+% These append either on the right (normal hook) or on the left
+% (reversed hook). This is setup up in
+% \cs{@@_initialize_hook_code:n}, elsewhere their behavior is undefined.
+% \begin{macrocode}
+\cs_new:Npn \@@_tl_gput:NV {\ERROR}
+\cs_new:Npn \@@_clist_gput:NV {\ERROR}
+% \end{macrocode}
+% \end{macro}
+
+
+%
+% \begin{macro}{\@@_apply_label_pair:nnn,\@@_label_if_exist_apply:nnnF}
+%
+% This is the payload of steps T2 and T3 executed in the loop described
+% above. This macro assumes |#1| and |#2| are ordered, which means that
+% any rule pertaining the pair |#1| and |#2| is
+% \cs{g_@@_\meta{hook}_rule_\#1\string|\#2_tl}, and not
+% \cs{g_@@_\meta{hook}_rule_\#2\string|\#1_tl}. This also saves a great deal
+% of time since we only need to check the order of the labels once.
+%
+% The arguments here are \meta{label1}, \meta{label2}, \meta{hook}, and
+% \meta{hook-code-plist}. We are about to apply the next rule and
+% enter it into the data structure. \cs{@@_apply_label_pair:nnn} will
+% just call \cs{@@_label_if_exist_apply:nnnF} for the \meta{hook}, and
+% if no rule is found, also try the \meta{hook} name \verb=??=
+% denoting a default hook rule.
+%
+% \cs{@@_label_if_exist_apply:nnnF} will check if the rule exists for
+% the given hook, and if so call \cs{@@_apply_rule:nnn}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_apply_label_pair:nnn #1#2#3
+ {
+% \end{macrocode}
+% Extra complication: as we use default rules and local hook specific
+% rules we first have to check if there is a local rule and if that
+% exist use it. Otherwise check if there is a default rule and use
+% that.
+% \begin{macrocode}
+ \@@_label_if_exist_apply:nnnF {#1} {#2} {#3}
+ {
+% \end{macrocode}
+% If there is no hook-specific rule we check for a default one and
+% use that if it exists.
+% \begin{macrocode}
+ \@@_label_if_exist_apply:nnnF {#1} {#2} { ?? } { }
+ }
+ }
+\cs_new_protected:Npn \@@_label_if_exist_apply:nnnF #1#2#3
+ {
+ \if_cs_exist:w g_@@_ #3 _rule_ #1 | #2 _tl \cs_end:
+% \end{macrocode}
+% What to do precisely depends on the type of rule we have
+% encountered. If it is a \texttt{before} rule it will be handled by the
+% algorithm but other types need to be managed differently. All
+% this is done in \cs{@@_apply_rule:nnnN}.
+% \begin{macrocode}
+ \@@_apply_rule:nnn {#1} {#2} {#3}
+ \exp_after:wN \use_none:n
+ \else:
+ \use:nn
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \begin{macro}{\@@_apply_rule:nnn}
+% This is the code executed in steps T2 and T3 while looping through
+% the matrix This is part of step T3. We are about to apply the next
+% rule and enter it into the data structure. The arguments are
+% \meta{label1}, \meta{label2}, \meta{hook-name}, and \meta{hook-code-plist}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_apply_rule:nnn #1#2#3
+ {
+ \cs:w @@_apply_
+ \cs:w g_@@_#3_reversed_tl \cs_end: rule_
+ \cs:w g_@@_ #3 _rule_ #1 | #2 _tl \cs_end: :nnn \cs_end:
+ {#1} {#2} {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_apply_rule_<:nnn,\@@_apply_rule_>:nnn}
+% The most common cases are \texttt{\string<} and \texttt{\string>} so we handle
+% that first. They are relations $\prec$ and $\succ$ in TAOCP, and
+% they dictate sorting.
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_apply_rule_<:nnn } #1#2#3
+ {
+ \@@_debug:n { \@@_msg_pair_found:nnn {#1} {#2} {#3} }
+ \tl_set:cx { \@@_tl_csname:n {#2} }
+ { \int_eval:n{ \cs:w \@@_tl_csname:n {#2} \cs_end: + 1 } }
+ \seq_put_right:cn{ \@@_seq_csname:n {#1} }{#2}
+ }
+\cs_new_protected:cpn { @@_apply_rule_>:nnn } #1#2#3
+ {
+ \@@_debug:n { \@@_msg_pair_found:nnn {#1} {#2} {#3} }
+ \tl_set:cx { \@@_tl_csname:n {#1} }
+ { \int_eval:n{ \cs:w \@@_tl_csname:n {#1} \cs_end: + 1 } }
+ \seq_put_right:cn{ \@@_seq_csname:n {#2} }{#1}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_apply_rule_xE:nnn,\@@_apply_rule_xW:nnn}
+% These relations make two labels incompatible within a hook.
+% |xE| makes raises an error if the labels are found in the same
+% hook, and |xW| makes it a warning.
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_apply_rule_xE:nnn } #1#2#3
+ {
+ \@@_debug:n { \@@_msg_pair_found:nnn {#1} {#2} {#3} }
+ \msg_error:nnnnnn { hooks } { labels-incompatible }
+ {#1} {#2} {#3} { 1 }
+ \use:c { @@_apply_rule_->:nnn } {#1} {#2} {#3}
+ \use:c { @@_apply_rule_<-:nnn } {#1} {#2} {#3}
+ }
+\cs_new_protected:cpn { @@_apply_rule_xW:nnn } #1#2#3
+ {
+ \@@_debug:n { \@@_msg_pair_found:nnn {#1} {#2} {#3} }
+ \msg_warning:nnnnnn { hooks } { labels-incompatible }
+ {#1} {#2} {#3} { 0 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_apply_rule_->:nnn,\@@_apply_rule_<-:nnn}
+% If we see \texttt{\detokenize{->}} we have to drop code for label
+% \verb=#3= and carry on. We could do a little better and trop
+% everything for that label since it doesn't matter where we sort
+% in the empty code. However that would complicate the algorithm a
+% lot with little gain. So we still unnecessarily try to sort it in
+% and depending on the rules that might result in a loop that is
+% otherwise resolved. If that turns out to be a real issue, we can
+% improve the code.
+%
+% Here the code is removed from \cs{l_@@_cur_hook_tl} rather than
+% \verb=#3= because the latter may be \verb=??=, and the default
+% hook doesn't store any code. Removing from \cs{l_@@_cur_hook_tl}
+% makes default rules \verb=->= and \verb=<-= work properly.
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_apply_rule_->:nnn } #1#2#3
+ {
+ \@@_debug:n
+ {
+ \@@_msg_pair_found:nnn {#1} {#2} {#3}
+ \iow_term:x{--->~ Drop~ '#2'~ code~ from~
+ \iow_char:N \\ g_@@_ \l_@@_cur_hook_tl _code_prop ~ because~ of~ '#1' }
+ }
+ \prop_gput:cnn { g_@@_ \l_@@_cur_hook_tl _code_prop } {#2} { }
+ }
+\cs_new_protected:cpn { @@_apply_rule_<-:nnn } #1#2#3
+ {
+ \@@_debug:n
+ {
+ \@@_msg_pair_found:nnn {#1} {#2} {#3}
+ \iow_term:x{--->~ Drop~ '#1'~ code~ from~
+ \iow_char:N \\ g_@@_ \l_@@_cur_hook_tl _code_prop ~ because~ of~ '#2' }
+ }
+ \prop_gput:cnn { g_@@_ \l_@@_cur_hook_tl _code_prop } {#1} { }
+ }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{
+% \@@_apply_-rule_<:nnn,
+% \@@_apply_-rule_>:nnn,
+% \@@_apply_-rule_<-:nnn,
+% \@@_apply_-rule_->:nnn,
+% \@@_apply_-rule_x:nnn,
+% }
+% Reversed rules.
+% \begin{macrocode}
+\cs_new_eq:cc { @@_apply_-rule_<:nnn } { @@_apply_rule_>:nnn }
+\cs_new_eq:cc { @@_apply_-rule_>:nnn } { @@_apply_rule_<:nnn }
+\cs_new_eq:cc { @@_apply_-rule_<-:nnn } { @@_apply_rule_<-:nnn }
+\cs_new_eq:cc { @@_apply_-rule_->:nnn } { @@_apply_rule_->:nnn }
+\cs_new_eq:cc { @@_apply_-rule_xE:nnn } { @@_apply_rule_xE:nnn }
+\cs_new_eq:cc { @@_apply_-rule_xW:nnn } { @@_apply_rule_xW:nnn }
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_msg_pair_found:nnn}
+% A macro to avoid moving this many tokens around.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_msg_pair_found:nnn #1#2#3
+ {
+ \iow_term:x{~ \str_if_eq:nnTF {#3} {??} {default} {~normal} ~
+ rule~ \@@_label_pair:nn {#1} {#2}:~
+ \use:c { g_@@_#3_rule_ \@@_label_pair:nn {#1} {#2} _tl } ~ found}
+ }
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_debug_label_data:N}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_debug_label_data:N #1 {
+ \iow_term:x{Code~ labels~ for~ sorting:}
+ \iow_term:x{~ \seq_use:Nnnn\l_@@_labels_seq {~and~}{,~}{~and~} } % fix name!
+ \iow_term:x{^^J Data~ structure~ for~ label~ rules:}
+ \prop_map_inline:Nn #1
+ {
+ \iow_term:x{~ ##1~ =~ \tl_use:c{ \@@_tl_csname:n {##1} }~ ->~
+ \seq_use:cnnn{ \@@_seq_csname:n {##1} }{~->~}{~->~}{~->~}
+ }
+ }
+ \iow_term:x{}
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\hook_log:n}
+% This writes out information about the hook given in its argument
+% onto the terminal and the \texttt{.log} file.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_log:n #1
+ {
+ \exp_args:Nx \@@_log:n
+ { \@@_parse_label_default:nn {#1} { top-level } }
+ }
+\cs_new_protected:Npn \@@_log:n #1
+ {
+ \iow_term:x{^^JThe~ hook~ '#1':}
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \hook_if_exist:nF {#1}
+ { \iow_term:x {~Hook~ is~ not~ declared!} }
+ \@@_if_exist:nTF {#1}
+ {
+ \iow_term:x{~Code~ chunks:}
+ \prop_if_empty:cTF {g_@@_#1_code_prop}
+ { \iow_term:x{\@spaces ---} }
+ {
+ \prop_map_inline:cn {g_@@_#1_code_prop}
+ { \iow_term:x{\@spaces ##1~ ->~ \tl_to_str:n{##2} } }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \iow_term:x{~Extra~ code~ next~ invocation:}
+ \iow_term:x{\@spaces
+ \tl_if_empty:cTF { g_@@_#1_next_code_tl }
+ {---} {->~ \str_use:c{g_@@_#1_next_code_tl} } }
+% \end{macrocode}
+%
+% \fmi{This is currently only displaying the local rules, but it
+% should also show the matching global rules!}
+%
+% \begin{macrocode}
+ \iow_term:x{~Rules:}
+ \prop_if_empty:cTF {g_@@_#1_rules_prop}
+ { \iow_term:x{\@spaces ---} }
+ { \prop_map_inline:cn {g_@@_#1_rules_prop}
+ { \iow_term:x{\@spaces ##1~ with~ relation~ ##2} }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \hook_if_exist:nT {#1}
+ { \iow_term:x { ~Execution~ order
+ \prop_if_empty:cTF {g_@@_#1_rules_prop}
+ { \@@_if_reversed:nT {#1}
+ { ~ (after~ reversal) }
+ }
+ { ~ (after~
+ \@@_if_reversed:nT {#1} {reversal~ and~}
+ applying~ rules)
+ }
+ :
+ }
+ \iow_term:x { \@spaces
+ \clist_if_empty:cTF{g_@@_#1_labels_clist}
+ {not~ set~ yet}
+ { \clist_use:cnnn {g_@@_#1_labels_clist}
+ { ,~ } { ,~ } { ,~ } }
+ }
+ }
+ }
+ { \iow_term:n { ~The~hook~is~empty. } }
+ \iow_term:n { }
+ }
+% \end{macrocode}
+%
+% \end{macro}
+
+
+
+% \subsection{Specifying code for next invocation}
+%
+%
+%
+%
+%
+% \begin{macro}{\hook_gput_next_code:nn}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_gput_next_code:nn #1
+ {
+ \exp_args:Nx \@@_gput_next_code:nn
+ { \@@_parse_label_default:nn {#1} { top-level } }
+ }
+\cs_new_protected:Npn \@@_gput_next_code:nn #1 #2
+ {
+ \@@_declare:n {#1}
+ \hook_if_exist:nTF {#1}
+ { \@@_gput_next_do:nn {#1} {#2} }
+ { \@@_try_declaring_generic_next_hook:nn {#1} {#2} }
+ }
+\cs_new_protected:Npn \@@_gput_next_do:nn #1 #2
+ {
+ \tl_gput_right:cn { g_@@_#1_next_code_tl }
+ { #2 \tl_gclear:c { g_@@_#1_next_code_tl } }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Using the hook}
+%
+% \begin{macro}{\hook_use:n}
+% \begin{macro}[EXP]{\@@_use_initialized:n}
+% \begin{macro}{\@@_preamble_hook:n}
+% \cs{hook_use:n} as defined here is used in the preamble, where
+% hooks aren't initialized by default. \cs{@@_use_initialized:n} is
+% also defined, which is the non-\tn{protected} version for use within
+% the document. Their definition is identical, except for the
+% \cs{@@_preamble_hook:n} (which wouldn't hurt in the expandable
+% version, but it would be an unnecessary extra expansion).
+%
+% \cs{@@_use_initialized:n} holds the expandable definition while in
+% the preamble. \cs{@@_preamble_hook:n} initializes the hook in the
+% preamble, and is redefined to \cs{use_none:n} at |\begin{document}|.
+%
+% Both versions do the same internally: check if the hook exist as
+% given, and if so use it as quickly as possible. If it doesn't
+% exist, the a call to \cs{@@_use:wn} checks for file hooks.
+%
+% At |\begin{document}|, all hooks are initialized, and any change in
+% them causes an update, so \cs{hook_use:n} can be made expandable.
+% This one is better not protected so that it can expand into nothing
+% if containing no code. Also important in case of generic hooks that
+% we do not generate a \cs{relax} as a side effect of checking for a
+% csname. In contrast to the \TeX{} low-level
+% \verb=\csname ...\endcsname= construct \cs{tl_if_exist:c} is
+% careful to avoid this.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_use:n #1
+ {
+ \tl_if_exist:cTF { g_@@_#1_code_tl }
+ {
+ \@@_preamble_hook:n {#1}
+ \cs:w g_@@_#1_code_tl \cs_end:
+ }
+ { \@@_use:wn #1 / \s_@@_mark {#1} }
+ }
+\cs_new:Npn \@@_use_initialized:n #1
+ {
+ \tl_if_exist:cTF { g_@@_#1_code_tl }
+ { \cs:w g_@@_#1_code_tl \cs_end: }
+ { \@@_use:wn #1 / \s_@@_mark {#1} }
+ }
+\cs_new_protected:Npn \@@_preamble_hook:n #1
+ { \@@_initialize_hook_code:n {#1} }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\@@_use:wn}
+% \begin{macro}{\@@_try_file_hook:n,\@@_if_exist_use:n}
+% \cs{@@_use:wn} does a quick check to test if the current hook is a
+% file hook: those need a special treatment. If it is not, the hook
+% does not exist. If it is, then \cs{@@_try_file_hook:n} is called,
+% and checks that the current hook is a file-specific hook using
+% \cs{@@_if_file_hook:wTF}. If it's not, then it's a generic |file/|
+% hook and is used if it exist.
+%
+% If it is a file-specific hook, it passes through the same
+% normalization as during declaration, and then it is used if defined.
+% \cs{@@_if_exist_use:n} checks if the hook exist, and calls
+% \cs{@@_preamble_hook:n} if so, then uses the hook.
+% \begin{macrocode}
+\cs_new:Npn \@@_use:wn #1 / #2 \s_@@_mark #3
+ {
+ \str_if_eq:nnTF {#1} { file }
+ { \@@_try_file_hook:n {#3} }
+ { } % Hook doesn't exist
+ }
+\cs_new_protected:Npn \@@_try_file_hook:n #1
+ {
+ \@@_if_file_hook:wTF #1 / / \s_@@_mark
+ {
+ \exp_args:Ne \@@_if_exist_use:n
+ { \exp_args:Ne \@@_file_hook_normalise:n {#1} }
+ }
+ { \@@_if_exist_use:n {#1} } % file/ generic hook (e.g. file/before)
+ }
+\cs_new_protected:Npn \@@_if_exist_use:n #1
+ {
+ \tl_if_exist:cT { g_@@_#1_code_tl }
+ {
+ \@@_preamble_hook:n {#1}
+ \cs:w g_@@_#1_code_tl \cs_end:
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\hook_use_once:n}
+% For hooks that can and should be used only once we have a special
+% use command that remembers the hook name in
+% \cs{g_@@_execute_immediately_clist}. This has the effect that any
+% further code added to the hook is executed immediately rather
+% than stored in the hook.
+% \begin{macrocode}
+\cs_new_protected:Npn \hook_use_once:n #1
+ {
+ \tl_if_exist:cT { g_@@_#1_code_tl }
+ {
+ \clist_gput_left:Nn \g_@@_execute_immediately_clist {#1}
+ \hook_use:n {#1}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+
+% \subsection{Querying a hook}
+%
+% Simpler data types, like token lists, have three possible states; they
+% can exist and be empty, exist and be non-empty, and they may not
+% exist, in which case emptiness doesn't apply (though
+% \cs{tl_if_empty:N} returns false in this case).
+%
+% Hooks are a bit more complicated: they have four possible states.
+% A hook may exist or not, and either way it may or may not be empty
+% (even a hook that doesn't exist may be non-empty).
+%
+% A hook is said to be empty when no code was added to it, either to
+% its permanent code pool, or to its ``next'' token list. The hook
+% doesn't need to be declared to have code added to its code pool
+% (it may happen that a package $A$ defines a hook \hook{foo}, but
+% it's loaded after package $B$, which adds some code to that hook.
+% In this case it is important that the code added by package $B$ is
+% remembered until package $A$ is loaded).
+%
+% A hook is said to exist when it was declared with \cs{hook_new:n} or
+% some variant thereof.
+%
+% \begin{macro}[pTF]{\hook_if_empty:n}
+% Test if a hook is empty (that is, no code was added to that hook).
+% A hook being empty means that \emph{both} its
+% \cs[no-index]{g_@@_\meta{hook}_code_prop} and its
+% \cs[no-index]{g_@@_\meta{hook}_next_code_tl} are empty.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \hook_if_empty:n #1 { p , T , F , TF }
+ {
+ \@@_if_exist:nTF {#1}
+ {
+ \bool_lazy_and:nnTF
+ { \prop_if_empty_p:c { g_@@_#1_code_prop } }
+ { \tl_if_empty_p:c { g_@@_#1_next_code_tl } }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ { \prg_return_true: }
+ }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}[pTF]{\hook_if_exist:n}
+% A canonical way to test if a hook exists. A hook exists if the
+% token list that stores the sorted code for that hook,
+% \cs[no-index]{g_@@_\meta{hook}_code_tl}, exists. The property list
+% \cs[no-index]{g_@@_\meta{hook}_code_prop} cannot be used here
+% because often it is necessary to add code to a hook without knowing
+% if such hook was already declared, or even if it will ever be
+% (for example, in case the package that defines it isn't loaded).
+% \begin{macrocode}
+\prg_new_conditional:Npnn \hook_if_exist:n #1 { p , T , F , TF }
+ {
+ \tl_if_exist:cTF { g_@@_#1_code_tl }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}[pTF]{\@@_if_exist:n}
+% An internal check if the hook has already been declared with
+% \cs{@@_declare:n}. This means that the hook was already used somehow
+% (a code chunk or rule was added to it), but it still wasn't declared
+% with \cs{hook_new:n}.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_exist:n #1 { p , T , F , TF }
+ {
+ \prop_if_exist:cTF { g_@@_#1_code_prop }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\@@_if_reversed:n}
+% An internal conditional that checks if a hook is reversed.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_reversed:n #1 { p , T , F , TF }
+ {
+ \if_int_compare:w \cs:w g_@@_#1_reversed_tl \cs_end: 1 < 0 \exp_stop_f:
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\g_@@_execute_immediately_clist}
+% List of hooks that from no on should not longer receive code.
+% \begin{macrocode}
+\clist_new:N \g_@@_execute_immediately_clist
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Messages}
+%
+% \begin{macrocode}
+\msg_new:nnnn { hooks } { labels-incompatible }
+ {
+ Labels~`#1'~and~`#2'~are~incompatible
+ \str_if_eq:nnF {#3} {??} { ~in~hook~`#3' } .~
+ \int_compare:nNnT {#4} = { 1 }
+ { The~code~for~both~labels~will~be~dropped. }
+ }
+ {
+ LaTeX~found~two~incompatible~labels~in~the~same~hook.~
+ This~indicates~an~incompatibility~between~packages.
+ }
+\msg_new:nnn { hooks } { empty-label }
+ { Empty~code~label~\msg_line_context:.~Using~`#1'~instead. }
+% \end{macrocode}
+%
+% \subsection{\LaTeXe{} package interface commands}
+%
+
+
+% \begin{macro}{\NewHook,\NewReversedHook,\NewMirroredHookPair}
+% Declaring new hooks \ldots
+% \begin{macrocode}
+\NewDocumentCommand \NewHook { m }{ \hook_new:n {#1} }
+\NewDocumentCommand \NewReversedHook { m }{ \hook_new_reversed:n {#1} }
+\NewDocumentCommand \NewMirroredHookPair { mm }{ \hook_new_pair:nn {#1}{#2} }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\AddToHook}
+%
+% \begin{macrocode}
+\NewDocumentCommand \AddToHook { m o +m }
+ {
+ \clist_if_in:NnTF \g_@@_execute_immediately_clist {#1}
+ {#3}
+ { \hook_gput_code:nnn {#1} {#2} {#3} }
+ }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\AddToHookNext}
+%
+% \begin{macrocode}
+\NewDocumentCommand \AddToHookNext { m +m }
+ { \hook_gput_next_code:nn {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\RemoveFromHook}
+%
+% \begin{macrocode}
+\NewDocumentCommand \RemoveFromHook { m o }
+ { \hook_gremove_code:nn {#1} {#2} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\DeclareDefaultHookLabel}
+% \begin{macro}{\@@_curr_name_push:n,\@@_curr_name_pop:}
+% The token list \cs{g_@@_hook_curr_name_tl} stores the name of the
+% current package/file to be used as label for hooks.
+% Providing a consistent interface is tricky, because packages can
+% be loaded within packages, and some packages may not use
+% \cs{DeclareDefaultHookLabel} to change the default label (in which case
+% \cs{@currname} is used, if set).
+%
+% To pull that off, we keep a stack that contains the default label
+% for each level of input. The bottom of the stack contains the
+% default label for the top-level. Since the string \verb|top-level|
+% is hardcoded, here this item of the stack is empty. Also, since
+% we're in an input level, add \verb|lthooks| to the stack as well.
+% This stack should never go empty, so we loop through \LaTeXe's
+% file name stack, and add empty entries to \cs{g_@@_name_stack_seq}
+% for each item in that stack. The last item is the \verb|top-level|,
+% which also gets an empty entry.
+%
+% Also check for the case we're loading \texttt{lthooks} in the
+% \LaTeXe{} kernel. In that case, \cs{@currname} isn't \verb|lthooks|
+% and just the top-level is added to the stack as an empty entry.
+% \begin{macrocode}
+\str_if_eq:VnTF \@currname { lthooks }
+ {
+ \seq_gpush:Nn \g_@@_name_stack_seq { lthooks }
+ \cs_set_protected:Npn \@@_tmp:w #1 #2 #3
+ {
+ \quark_if_recursion_tail_stop:n {#1}
+ \seq_gput_right:Nn \g_@@_name_stack_seq { }
+ \@@_tmp:w
+ }
+ \exp_after:wN \@@_tmp:w
+ \@currnamestack
+ \q_recursion_tail \q_recursion_tail
+ \q_recursion_tail \q_recursion_stop
+ }
+ { \seq_gpush:Nn \g_@@_name_stack_seq { } }
+% \end{macrocode}
+%
+% Two commands keep track of the stack: when a file is input,
+% \cs{@@_curr_name_push:n} pushes an (empty by default) label to the
+% stack:
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_curr_name_push:n #1
+ {
+ \seq_gpush:Nn \g_@@_name_stack_seq {#1}
+ \tl_gset:Nn \g_@@_hook_curr_name_tl {#1}
+ }
+%
+% \end{macrocode}
+% and when an input is over, the topmost item of the stack is popped,
+% since the label will not be used again, and \cs{g_@@_hook_curr_name_tl}
+% is updated to the now topmost item of the stack:
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_curr_name_pop:
+ {
+ \seq_gpop:NN \g_@@_name_stack_seq \l_@@_return_tl
+ \seq_get:NNTF \g_@@_name_stack_seq \l_@@_return_tl
+ { \tl_gset_eq:NN \g_@@_hook_curr_name_tl \l_@@_return_tl }
+ { \ERROR_should_not_happen }
+ }
+% \end{macrocode}
+%
+% The token list \cs{g_@@_hook_curr_name_tl} is but a mirror of the top
+% of the stack.
+%
+% Now define a wrapper that replaces the top of the stack with the
+% argument, and updates \cs{g_@@_hook_curr_name_tl} accordingly.
+% \begin{macrocode}
+\NewDocumentCommand \DeclareDefaultHookLabel { m }
+ {
+ \seq_gpop:NN \g_@@_name_stack_seq \l_@@_return_tl
+ \@@_curr_name_push:n {#1}
+ }
+% \begin{macrocode}
+%
+% The push and pop macros are injected in \cs{@pushfilename} and
+% \cs{@popfilename} so that they correctly keep track of the label.s
+% \begin{macrocode}
+% TODO! \pho{Properly integrate in the kernel}
+\tl_gput_left:Nn \@pushfilename { \@@_curr_name_push:n { } }
+\tl_gput_left:Nn \@popfilename { \@@_curr_name_pop: }
+% TODO! \pho{Properly integrate in the kernel}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+%
+%
+% \begin{macro}{\UseHook}
+% Avoid the overhead of \pkg{xparse} and its protection that we
+% don't want here (since the hook should vanish without trace if empty)!
+% \begin{macrocode}
+\newcommand \UseHook { \hook_use:n }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\UseOneTimeHook}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \UseOneTimeHook { \hook_use_once:n }
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\ShowHook}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \ShowHook { \hook_log:n }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\DebugHookOn,\DebugHookOff}
+%
+% \begin{macrocode}
+\cs_new_protected:Npn \DebugHookOn { \hook_debug_on: }
+\cs_new_protected:Npn \DebugHookOff { \hook_debug_off: }
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\DeclareHookRule}
+%
+% \begin{macrocode}
+\NewDocumentCommand \DeclareHookRule { m m m m }
+{ \hook_gset_rule:nnnn {#1}{#2}{#3}{#4} }
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\DeclareDefaultHookRule}
+% This declaration is only supported before \verb=\begin{document}=.
+% \begin{macrocode}
+\NewDocumentCommand \DeclareDefaultHookRule { m m m }
+ { \hook_gset_rule:nnnn {??}{#1}{#2}{#3} }
+\@onlypreamble\DeclareDefaultHookRule
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ClearHookRule}
+% A special setup rule that removes an existing relation.
+% Basically {@@_rule_gclear:nnn} plus fixing the property list for debugging.
+% \fmi{Need an L3 interface, or maybe it should get dropped}
+% \begin{macrocode}
+\NewDocumentCommand \ClearHookRule { m m m }
+{ \hook_gset_rule:nnnn {#1}{#2}{unrelated}{#3} }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\IfHookExistTF,\IfHookEmptyTF}
+% \begin{macrocode}
+\NewExpandableDocumentCommand \IfHookExistTF { m }
+ { \hook_if_exist:nTF {#1} }
+\NewExpandableDocumentCommand \IfHookEmptyTF { m }
+ { \hook_if_empty:nTF {#1} }
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \begin{macro}{\AtBeginDocument}
+%
+% \begin{macrocode}
+\renewcommand\AtBeginDocument{\AddToHook{begindocument}}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\AtEndDocument}
+%
+% \begin{macrocode}
+\renewcommand\AtEndDocument {\AddToHook{enddocument}}
+%\renewcommand\AtEndDocument {\AddToHook{env/document/end}} % alternative impl
+% \end{macrocode}
+%
+% \end{macro}
+
+
+
+% \subsection{Set up existing \LaTeXe{} hooks}
+%
+% As we are in a package calling \cs{NewHook} would label any
+% already set up hook code under the package name, but we want it
+% under the name \hook{top-level} so we pretend that \cs{@currname}
+% is empty.
+% \begin{macrocode}
+\begingroup
+ \def\@currname{}
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \NewHook{begindocument}
+ \NewHook{enddocument}
+% \end{macrocode}
+% We need to initialize the mechanism at \verb=\begin{document}=
+% but obviously before everything else, so we sneak\footnote{This
+% needs to move to \cs{document} directly.}
+% \cs{@@_initialize_all:} into the \LaTeXe{} hook name.
+%
+% We can't use \cs{tl_gput_left:Nn} because that complains about
+% \cs{@begindocumenthook} not starting with \cs{g_} so we do this
+% through the backdoor.
+% \begin{macrocode}
+% \tex_global:D\tl_put_left:Nn \@begindocumenthook
+% {\@@_initialize_all:}
+% \end{macrocode}
+% There aren't many other hooks at the moment:
+% \begin{macrocode}
+ \NewHook{rmfamily}
+ \NewHook{sffamily}
+ \NewHook{ttfamily}
+ \NewHook{defaultfamily}
+% \end{macrocode}
+% Not checked what this one does and whether it should be there (or
+% is a real ``hook''.
+% \begin{macrocode}
+ \NewHook{documentclass}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\endgroup
+% \end{macrocode}
+%
+%
+%
+% \section{Generic hooks for environments}
+%
+%
+% \begin{macrocode}
+\let\begin\relax % avoid redeclaration message
+% \end{macrocode}
+%
+% \begin{macrocode}
+\DeclareRobustCommand*\begin[1]{%
+ \UseHook{env/#1/before}%
+ \@ifundefined{#1}%
+ {\def\reserved@a{\@latex@error{Environment~#1~undefined}\@eha}}%
+ {\def\reserved@a{\def\@currenvir{#1}%
+ \edef\@currenvline{\on@line}%
+ \@execute@begin@hook{#1}%
+ \csname #1\endcsname}}%
+ \@ignorefalse
+ \begingroup\@endpefalse\reserved@a}
+% \end{macrocode}
+%
+% Before the \cs{document} code is executed we have to first undo
+% the \cs{endgroup} as there should be none for this environment to
+% avoid that changes on top-level unnecessarily go to \TeX's
+% savestack, and we have to initialize all hooks in the hook system.
+% So we need to test for this environment name. But once it has be
+% found all this testing is no longer needed and so we redefine
+% \cs{@execute@begin@hook} to simply use the hook
+% \begin{macrocode}
+\def\@execute@begin@hook #1{%
+ \expandafter\ifx\csname #1\endcsname\document
+ \endgroup
+ \gdef\@execute@begin@hook##1{\UseHook{env/##1/begin}}%
+ \@@_initialize_all:
+ \@execute@begin@hook{#1}%
+% \end{macrocode}
+% If this is an environment before \verb=\begin{document}= we just
+% run the hook.
+% \begin{macrocode}
+ \else
+ \UseHook{env/#1/begin}%
+ \fi
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\@namedef{end~}#1{%
+ \UseHook{env/#1/end}%
+ \csname end#1\endcsname\@checkend{#1}%
+ \expandafter\endgroup\if@endpe\@doendpe\fi
+ \UseHook{env/#1/after}%
+ \if@ignore\@ignorefalse\ignorespaces\fi}%
+% \end{macrocode}
+% Version that fixes tlb3722 but the change should perhaps be made in
+% \pkg{tabularx} instead.
+% \begin{macrocode}
+\@namedef{end~}#1{%
+\romannumeral
+\IfHookEmptyTF{env/#1/end}%
+ {\expandafter\z@}%
+ {\z@\UseHook{env/#1/end}}%
+\csname end#1\endcsname\@checkend{#1}%
+\expandafter\endgroup\if@endpe\@doendpe\fi
+\UseHook{env/#1/after}%
+\if@ignore\@ignorefalse\ignorespaces\fi}%
+% \end{macrocode}
+%
+%
+%
+% We provide 4 high-level hook interfaces directly, the others only when
+% etoolbox is loaded
+% \begin{macrocode}
+\newcommand\AtBeginEnvironment[1] {\AddToHook{env/#1/begin}}
+\newcommand\AtEndEnvironment[1] {\AddToHook{env/#1/end}}
+\newcommand\BeforeBeginEnvironment[1]{\AddToHook{env/#1/before}}
+\newcommand\AfterEndEnvironment[1] {\AddToHook{env/#1/after}}
+% \end{macrocode}
+%
+%
+%
+%
+%
+%
+%
+%
+%
+%
+%
+% \section{Generic hooks for file loads}
+%
+%
+%
+%
+%
+%
+%
+% \section{Hooks in \cs{begin} document}
+%
+% Can't have \texttt{@{}@} notation here as this is \LaTeXe{} code
+% \ldots{} and makes for puzzling errors if the double \texttt{@}
+% signs get substituted.
+% \begin{macrocode}
+%<@@=>
+\ExplSyntaxOff
+% \end{macrocode}
+%
+% The \hook{begindocument} hook was already set up earlier, here is now
+% the additional one (which was originally from the \pkg{etoolbox}
+% package under the name \texttt{afterpreamble}.
+% \begin{macrocode}
+\NewHook{begindocument/end}
+% \end{macrocode}
+%
+%
+
+% \begin{macro}{\document}
+%
+% \begin{macrocode}
+\def\document{%
+% \end{macrocode}
+% We do cancel the grouping as part of the \cs{begin} handling
+% (this is now done inside \cs{begin} instead) so that the
+% \hook{env/\meta{env}/begin} hook is not hidden inside \cs{begingroup}
+% \texttt{...} \cs{endgroup}.
+% \begin{macrocode}
+% \endgroup
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \@kernel@after@env@document@begin
+% \end{macrocode}
+%
+% Added hook to load \textsf{l3backend} code:
+% \begin{macrocode}
+ \@expl@sys@load@backend@@
+ \ifx\@unusedoptionlist\@empty\else
+ \@latex@warning@no@line{Unused global option(s):^^J%
+ \@spaces[\@unusedoptionlist]}%
+ \fi
+ \@colht\textheight
+ \@colroom\textheight \vsize\textheight
+ \columnwidth\textwidth
+ \@clubpenalty\clubpenalty
+ \if@twocolumn
+ \advance\columnwidth -\columnsep
+ \divide\columnwidth\tw@ \hsize\columnwidth \@firstcolumntrue
+ \fi
+ \hsize\columnwidth \linewidth\hsize
+ \begingroup\@floatplacement\@dblfloatplacement
+ \makeatletter\let\@writefile\@gobbletwo
+ \global \let \@multiplelabels \relax
+ \@input{\jobname.aux}%
+ \endgroup
+ \if@filesw
+ \immediate\openout\@mainaux\jobname.aux
+ \immediate\write\@mainaux{\relax}%
+ \fi
+ \process@table
+ \let\glb@currsize\@empty % Force math initialization.
+ \normalsize
+ \everypar{}%
+ \ifx\normalsfcodes\@empty
+ \ifnum\sfcode`\.=\@m
+ \let\normalsfcodes\frenchspacing
+ \else
+ \let\normalsfcodes\nonfrenchspacing
+ \fi
+ \fi
+ \ifx\document@default@language\m@ne
+ \chardef\document@default@language\language
+ \fi
+ \@noskipsecfalse
+ \let \@refundefined \relax
+% \end{macrocode}
+%
+% \begin{macrocode}
+% \let\AtBeginDocument\@firstofone
+% \@begindocumenthook
+ \UseOneTimeHook{begindocument}%
+ \@kernel@after@begindocument
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \ifdim\topskip<1sp\global\topskip 1sp\relax\fi
+ \global\@maxdepth\maxdepth
+ \global\let\@begindocumenthook\@undefined
+ \ifx\@listfiles\@undefined
+ \global\let\@filelist\relax
+ \global\let\@addtofilelist\@gobble
+ \fi
+ \gdef\do##1{\global\let ##1\@notprerr}%
+ \@preamblecmds
+ \global\let \@nodocument \relax
+ \global\let\do\noexpand
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \UseOneTimeHook{begindocument/end}%
+ \ignorespaces}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\let\@kernel@after@begindocument\@empty
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\@kernel@after@env@document@begin,\@kernel@hook@begindocument}
+%
+% \begin{macrocode}
+\edef \@kernel@after@env@document@begin{%
+ \let\expandafter\noexpand\csname
+ g__hook_env/document/begin_code_tl\endcsname
+ \noexpand\@empty}
+% \end{macrocode}
+% \begin{macrocode}
+\let\@kernel@hook@begindocument\@empty
+% \end{macrocode}
+%
+% \end{macro}
+%
+%
+% \section{Hooks in \cs{enddocument}}
+%
+%
+%
+% The \hook{enddocument} hook was already set up earlier, here are now
+% the additional ones:
+% \begin{macrocode}
+\NewHook{enddocument/afterlastpage}
+\NewHook{enddocument/afteraux}
+\NewHook{enddocument/info}
+\NewHook{enddocument/end}
+% \end{macrocode}
+
+
+
+% \begin{macro}{\enddocument}
+%
+%
+% \begin{macrocode}
+\def\enddocument{%
+ \UseHook{enddocument}%
+ \@kernel@after@enddocument
+ \@checkend{document}%
+ \clearpage
+ \UseHook{enddocument/afterlastpage}%
+ \@kernel@after@enddocument@afterlastpage
+ \begingroup
+ \if@filesw
+ \immediate\closeout\@mainaux
+ \let\@setckpt\@gobbletwo
+ \let\@newl@bel\@testdef
+ \@tempswafalse
+ \makeatletter \@@input\jobname.aux
+ \fi
+ \UseHook{enddocument/afteraux}%
+% \end{macrocode}
+% Next hook is expect to contain only code for writing info
+% messages on the terminal.
+% \begin{macrocode}
+ \UseHook{enddocument/info}%
+ \endgroup
+ \UseHook{enddocument/end}%
+ \deadcycles\z@\@@end}
+% \end{macrocode}
+% The two kernel hooks above are used by the shipout code.
+% \begin{macrocode}
+\let\@kernel@after@enddocument\@empty
+\let\@kernel@after@enddocument@afterlastpage\@empty
+% \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \begin{macro}{\@enddocument@kernel@warnings}
+%
+% \begin{macrocode}
+\def\@enddocument@kernel@warnings{%
+ \ifdim \font@submax >\fontsubfuzz\relax
+ \@font@warning{Size substitutions with differences\MessageBreak
+ up to \font@submax\space have occurred.\@gobbletwo}%
+ \fi
+ \@defaultsubs
+ \@refundefined
+ \if@filesw
+ \ifx \@multiplelabels \relax
+ \if@tempswa
+ \@latex@warning@no@line{Label(s) may have changed.
+ Rerun to get cross-references right}%
+ \fi
+ \else
+ \@multiplelabels
+ \fi
+ \fi
+}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\AddToHook{enddocument/info}[kernel/filelist]{\@dofilelist}
+\AddToHook{enddocument/info}[kernel/warnings]{\@enddocument@kernel@warnings}
+\DeclareHookRule{enddocument/info}{kernel/filelist}{before}{kernel/warnings}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Adjusting at \pkg{atveryend} interfaces}
+%
+% With the new hook management all of \pkg{atveryend} is taken care
+% of.
+%
+% We therefore prevent the package from loading:
+% \begin{macrocode}
+\expandafter\let\csname ver@atveryend.sty\endcsname\fmtversion
+% \end{macrocode}
+%
+%
+% Here are new definitions for its interfaces now pointing to the
+% hooks in \cs{enddocument}
+% \begin{macrocode}
+\newcommand\AfterLastShipout {\AddToHook{enddocument/afterlastpage}}
+\newcommand\AtVeryEndDocument {\AddToHook{enddocument/afteraux}}
+% \end{macrocode}
+% Next one is a bit of a fake, but the result should normally be as
+% expected. If not one needs to add a rule to sort the code chunks
+% in \hook{enddocument/info}.
+% \begin{macrocode}
+\newcommand\AtEndAfterFileList{\AddToHook{enddocument/info}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\newcommand\AtVeryVeryEnd {\AddToHook{enddocument/end}}
+% \end{macrocode}
+
+% \begin{macro}{\BeforeClearDocument}
+% This one is the only one we don't implement or rather don't have
+% a dedicated hook in the code.
+% \begin{macrocode}
+\ExplSyntaxOn
+\newcommand\BeforeClearDocument[1]
+ { \AtEndDocument{#1}
+ \@DEPRECATED{BeforeClearDocument \tl_to_str:n{#1}}
+ }
+\cs_new:Npn\@DEPRECATED #1
+ {\iow_term:x{======~DEPRECATED~USAGE~#1~==========}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ExplSyntaxOff
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</2ekernel>
+% \end{macrocode}
+
+%
+% \section{A package version of the code for testing}
+%
+
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+
+
+
+% \begin{macrocode}
+\RequirePackage{xparse}
+\ProvidesExplPackage{lthooks}{\lthooksdate}{\lthooksversion}
+ {Hook management interface for LaTeX2e}
+% \end{macrocode}
+%
+%
+% \subsection{Core hook management code (kernel part)}
+%
+% This should run in older formats so we can't use
+% \cs{IfFormatAtLeastTF} right now.
+% \begin{macrocode}
+\@ifl@t@r\fmtversion{2020/10/01}
+ {}
+ {\input{lthooks.ltx}
+ \input{ltshipout.ltx}
+ \input{ltfilehook.ltx}
+ }
+% \end{macrocode}
+%
+% \subsection{Package options}
+%
+% For now we offer a simple debug option which turns on a lot of
+% strange \cs{typeout} messages, nothing fancy.
+% \begin{macrocode}
+\ExplSyntaxOn
+% \end{macrocode}
+%
+% \begin{macrocode}
+\hook_debug_off:
+\DeclareOption { debug } { \hook_debug_on:
+ \shipout_debug_on: }
+% \end{macrocode}
+%
+%
+% For now we offer a simple debug option which turns on a lot of
+% strange \cs{typeout} messages, nothing fancy.
+% \begin{macrocode}
+\shipout_debug_off:
+\DeclareOption { debug-shipout } { \shipout_debug_on: }
+% \end{macrocode}
+%
+% \begin{macrocode}
+\ProcessOptions
+% \end{macrocode}
+%
+%
+% \subsection{Temporarily patching package until changed}
+%
+%
+%
+% \pkg{filehook} support until that package is patched:
+% \begin{macrocode}
+\RequirePackage{filehook-ltx}
+% \end{macrocode}
+%
+%
+%
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+%
+%
+%
+% \Finale
+%
+
+
diff --git a/Master/texmf-dist/source/latex-dev/base/lthooks.ins b/Master/texmf-dist/source/latex-dev/base/lthooks.ins
new file mode 100644
index 00000000000..4218fb8b259
--- /dev/null
+++ b/Master/texmf-dist/source/latex-dev/base/lthooks.ins
@@ -0,0 +1,76 @@
+%%
+%% This file will generate fast loadable files and documentation
+%% driver files from the dtx file(s) in this package when run through
+%% LaTeX or TeX.
+%%
+%% Copyright 2020 Frank Mittelbach
+%%
+%%
+%% This file is part of the lthooks Bundle for LaTeX.
+%% -------------------------------------------------------
+%%
+%% It may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either version 1.3c
+%% of this license or (at your option) any later version.
+%% The latest version of this license is in
+%% http://www.latex-project.org/lppl.txt
+%% and version 1.3c or later is part of all distributions of LaTeX
+%% version 2008 or later.
+%%
+%% In particular, NO PERMISSION is granted to modify the contents of this
+%% file since it contains the legal notices that are placed in the files
+%% it generates.
+%%
+%%
+%%
+%% --------------- start of docstrip commands ------------------
+%%
+\input docstrip
+
+\keepsilent
+
+\preamble
+
+This is a generated file.
+
+Copyright 2020 Frank Mittelbach
+
+This file was generated from file(s) of the LaTeX `lthooks Bundle'.
+--------------------------------------------------------------------------
+
+It may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either version 1.3c
+of this license or (at your option) any later version.
+The latest version of this license is in
+ http://www.latex-project.org/lppl.txt
+and version 1.3c or later is part of all distributions of LaTeX
+version 2005/12/01 or later.
+
+This file may only be distributed together with a copy of the LaTeX
+`lthooks Bundle'. You may however distribute the `lthooks Bundle'
+without such generated files.
+
+The newest sources can be found below
+
+ https://github.com/FrankMittelbach/fmitex/
+
+where one can also log issues in case there are any.
+
+
+\endpreamble
+
+
+\generate{\file{lthooks.ltx}{\from{lthooks.dtx}{2ekernel}}}
+\generate{\file{ltshipout.ltx}{\from{ltshipout.dtx}{2ekernel}}}
+\generate{\file{ltfilehook.ltx}{\from{ltfilehook.dtx}{2ekernel}}}
+
+
+\generate{\file{structuredlog.sty}{\from{ltfilehook.dtx}{structuredlog}}}
+
+\generate{\file{lthooks.sty}{\from{lthooks.dtx}{package}}}
+
+\generate{\file{filehook-ltx.sty}{\from{ltfilehook.dtx}{filehook-draft}}}
+
+\generate{\file{srclfile-ltx.sty}{\from{ltfilehook.dtx}{scrlfile-draft}}}
+
+\endbatchfile
diff --git a/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx b/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx
index d7ca7d05ecd..2e692a993b9 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltluatex.dtx
@@ -23,12 +23,12 @@
%<tex> \ProvidesFile\undefined\begingroup\def\ProvidesFile
%<tex> #1#2[#3]{\endgroup\immediate\write-1{File: #1 #3}}
%<tex>\fi
-%<plain>\ProvidesFile{ltluatex.tex}
+%<plain>\ProvidesFile{ltluatex.tex}%
%<*driver>
\ProvidesFile{ltluatex.dtx}
%</driver>
%<*tex>
-[2020/03/07 v1.1m
+[2020/06/10 v1.1n
%</tex>
%<plain> LuaTeX support for plain TeX (core)
%<*tex>
@@ -406,6 +406,14 @@
\fi
% \end{macrocode}
%
+% \changes{v1.1n}{2020/06/10}{Define \cs{@gobble}/\cs{@firstofone} even for \LaTeX\ to allow early loading.}
+% Two simple \LaTeX\ macros from |ltdefns.dtx| have to be defined here
+% because ltdefns.dtx is not loaded yet when ltluatex.dtx is executed.
+% \begin{macrocode}
+\long\def\@gobble#1{}
+\long\def\@firstofone#1{#1}
+% \end{macrocode}
+%
% \subsection{Older \LaTeX{}/Plain \TeX\ setup}
%
% \begin{macrocode}
@@ -521,12 +529,6 @@
\fi}%
% \end{macrocode}
%
-% Two simple \LaTeX\ macros used in |ltlatex.sty|.
-% \begin{macrocode}
-\long\def\@gobble#1{}
-\long\def\@firstofone#1{#1}
-% \end{macrocode}
-%
% Fix up allocations not to clash with |etex.src|.
%
% \begin{macrocode}
@@ -544,7 +546,6 @@
%</tex>
% \end{macrocode}
%
-%
% \subsection{Attributes}
%
% \begin{macro}{\newattribute}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx b/Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx
index 5fb4e77d903..c48384b8bdc 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltmiscen.dtx
@@ -32,7 +32,7 @@
%<*driver>
% \fi
\ProvidesFile{ltmiscen.dtx}
- [2020/04/24 v1.1t LaTeX Kernel (Misc. Environments)]
+ [2020/05/31 v1.1u LaTeX Kernel (Misc. Environments)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltmiscen.dtx}
@@ -780,33 +780,39 @@
% \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
-%<latexrelease>\IncludeInRelease{2019/10/01}%
-%<latexrelease> {\centering}{Make commands robust}%
+%<latexrelease>\IncludeInRelease{2020/10/01}%
+%<latexrelease> {\centering}{Set finaldhypendemerits}%
% \end{macrocode}
%
% \begin{macro}{\centering}
+% \changes{v1.1u}{2020/05/31}{Added \cs{finalhyphendemerits} setting (gh/247)}
% \begin{macrocode}
\DeclareRobustCommand\centering{%
\let\\\@centercr
\rightskip\@flushglue\leftskip\@flushglue
+ \finalhyphendemerits=\z@
\parindent\z@\parfillskip\z@skip}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\raggedright}
+% \changes{v1.1u}{2020/05/31}{Added \cs{finalhyphendemerits} setting (gh/247)}
% \begin{macrocode}
\DeclareRobustCommand\raggedright{%
\let\\\@centercr\@rightskip\@flushglue \rightskip\@rightskip
+ \finalhyphendemerits=\z@
\leftskip\z@skip
\parindent\z@}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\raggedleft}
+% \changes{v1.1u}{2020/05/31}{Added \cs{finalhyphendemerits} setting (gh/247)}
% \begin{macrocode}
\DeclareRobustCommand\raggedleft{%
\let\\\@centercr
\rightskip\z@skip\leftskip\@flushglue
+ \finalhyphendemerits=\z@
\parindent\z@\parfillskip\z@skip}
% \end{macrocode}
% \end{macro}
@@ -814,6 +820,23 @@
% \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
+%<latexrelease>\IncludeInRelease{2019/10/01}%
+%<latexrelease> {\centering}{Make commands robust}%
+%<latexrelease>
+%<latexrelease>\DeclareRobustCommand\centering{%
+%<latexrelease> \let\\\@centercr
+%<latexrelease> \rightskip\@flushglue\leftskip\@flushglue
+%<latexrelease> \parindent\z@\parfillskip\z@skip}
+%<latexrelease>\DeclareRobustCommand\raggedright{%
+%<latexrelease> \let\\\@centercr\@rightskip\@flushglue \rightskip\@rightskip
+%<latexrelease> \leftskip\z@skip
+%<latexrelease> \parindent\z@}
+%<latexrelease>\DeclareRobustCommand\raggedleft{%
+%<latexrelease> \let\\\@centercr
+%<latexrelease> \rightskip\z@skip\leftskip\@flushglue
+%<latexrelease> \parindent\z@\parfillskip\z@skip}
+%<latexrelease>\EndIncludeInRelease
+%<latexrelease>
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease> {\centering}{Make commands robust}%
%<latexrelease>
diff --git a/Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx b/Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx
index 8831b5655f8..59c20f37700 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltoutenc.dtx
@@ -44,7 +44,7 @@
%<*driver>
% \fi
\ProvidesFile{ltoutenc.dtx}
- [2020/04/22 v2.0p LaTeX Kernel (font encodings)]
+ [2021/07/04 v2.0q LaTeX Kernel (font encodings)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltoutenc.dtx}
@@ -2869,28 +2869,70 @@
% \end{macrocode}
%
% LuaTeX.
+% For Lua\TeX~1.10+, define a Lua function to disable any handing by the font code.
+% Otherwise we reload the font without TeX ligatures.
+% \changes{v2.0q}{2020/07/04}{%
+% Implement \cs{remove@tlig} in Lua\TeX without font reloading}
% \begin{macrocode}
\def\UnicodeFontTeXLigatures{+tlig;}
-% \end{macrocode}
-%
-% \begin{macrocode}
- \def\reserved@a#1{%
- \def\@remove@tlig##1{\@remove@tlig@##1\@nil#1\@nil\relax}
- \def\@remove@tlig@##1#1{\@remove@tlig@@##1}}
- \edef\reserved@b{\detokenize{+tlig;}}
- \expandafter\reserved@a\expandafter{\reserved@b}
- \def\@remove@tlig@@#1\@nil#2\relax{#1}
-% \end{macrocode}
-%
-% \begin{macrocode}
- \def\remove@tlig#1{%
- \begingroup
- \font\remove@tlig
- \expandafter\@remove@tlig\expandafter{\fontname\font}%
- \remove@tlig
- \char#1\relax
- \endgroup
- }
+ \ifnum\luatexversion<110
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \def\reserved@a#1{%
+ \def\@remove@tlig##1{\@remove@tlig@##1\@nil#1\@nil\relax}
+ \def\@remove@tlig@##1#1{\@remove@tlig@@##1}}
+ \edef\reserved@b{\detokenize{+tlig;}}
+ \expandafter\reserved@a\expandafter{\reserved@b}
+ \def\@remove@tlig@@#1\@nil#2\relax{#1}
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \def\remove@tlig#1{%
+ \begingroup
+ \font\remove@tlig
+ \expandafter\@remove@tlig\expandafter{\fontname\font}%
+ \remove@tlig
+ \char#1\relax
+ \endgroup
+ }
+ \else
+ \newluafunction\@remove@tlig@@@@
+% \end{macrocode}
+% We are in the format and Lua functions can not be dumped, so we have to repeat
+% the code during |\everyjob|. Therefore we first define a helper to both execute
+% some code and same it for |\everyjob|:
+% \begin{macrocode}
+ \def\now@and@everyjob#1{\toksapp\everyjob{#1}#1}
+% \end{macrocode}
+% Now we can define the function. Mostly we just have to insert a protected glyph
+% node, which is a glyph node with subtype 256. But we have to keep track of the
+% current mode to avoid inserting the glyph into a vlist.
+% \begin{macrocode}
+ \now@and@everyjob{\directlua{
+ local rawchar_func = token.create'@remove@tlig@@@@'.index
+ local forcehmode = tex.forcehmode
+ local put_next = token.put_next
+ local glyph_id = node.id'glyph'
+ local rawchar_token = token.new(rawchar_func, token.command_id'lua_call')
+ lua.get_functions_table()[rawchar_func] = function()
+ local mode = tex.nest.top.mode
+ if mode == 1 or mode == -1 then
+ put_next(rawchar_token)
+ return forcehmode(true)
+ end
+ local n = node.new(glyph_id, 256)
+ n.font = font.current()
+ n.char = token.scan_int()
+ return node.write(n)
+ end
+ token.set_lua('@remove@tlig@@@', rawchar_func, 'global', 'protected')
+ }}
+% \end{macrocode}
+% Now \verb+\remove@tlig+ can be implemented almost as in XeTeX.
+% \begin{macrocode}
+ \def\remove@tlig#1{\@remove@tlig@@@#1\relax}
+ \fi
% \end{macrocode}
%
% \begin{macrocode}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx b/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx
new file mode 100644
index 00000000000..8d6150b5930
--- /dev/null
+++ b/Master/texmf-dist/source/latex-dev/base/ltshipout.dtx
@@ -0,0 +1,1425 @@
+% \iffalse meta-comment
+%
+%% File: ltshipout.dtx (C) Copyright 2020 Frank Mittelbach, LaTeX Team
+%
+% 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
+%
+%
+% The development version of the bundle can be found below
+%
+% https://github.com/FrankMittelbach/...
+%
+% for those people who are interested or want to report an issue.
+%
+% \begin{macrocode}
+\providecommand\ltshipoutversion{v0.9a}
+\providecommand\ltshipoutdate{2020/07/15}
+% \end{macrocode}
+%
+%<*driver>
+
+\documentclass{l3doc}
+
+% bug fix fo l3doc.cls
+\ExplSyntaxOn
+\cs_set_protected:Npn \__codedoc_macro_typeset_one:nN #1#2
+ {
+ \vbox_set:Nn \l__codedoc_macro_box
+ {
+ \vbox_unpack_drop:N \l__codedoc_macro_box
+ \hbox { \llap { \__codedoc_print_macroname:nN {#1} #2
+ \MacroFont % <----- without it the \ is in lmr10 if a link is made
+ \
+ } }
+ }
+ \int_incr:N \l__codedoc_macro_int
+ }
+\ExplSyntaxOff
+
+\EnableCrossrefs
+\CodelineIndex
+\begin{document}
+ \DocInput{ltshipout.dtx}
+\end{document}
+%</driver>
+%
+% \fi
+%
+%
+% \long\def\fmi#1{\begin{quote}\itshape Todo: #1\end{quote}}
+%
+% \newcommand\hook[1]{\texttt{#1}}
+%
+%
+% \title{The \texttt{ltshipout} package\thanks{This package has version
+% \ltshipoutversion\ dated \ltshipoutdate, \copyright\ \LaTeX\
+% Project.}}
+%
+% \author{Frank Mittelbach}
+%
+% \maketitle
+%
+%
+% \tableofcontents
+%
+% \section{Introduction}
+%
+% The code provides an interface to the \cs{shipout} primitive of
+% \TeX{} which is called when a finished pages is finally
+% \enquote{shipped out} to the target output file, e.g., the
+% \texttt{.dvi} or \texttt{.pdf} file.
+% A good portion of the code is based on ideas by Heiko Oberdiek
+% implemented in his packages \pkg{atbegshi} and \pkg{atenddvi}
+% even though the interfaces are somewhat
+% different.\footnote{Heiko's interfaces are emulated by the kernel
+% code, if a document requests his packages, so older documents
+% will continue to work.}
+%
+% \subsection{Overloading the \cs{shipout} primitive}
+%
+%
+% \begin{function}{\shipout}
+% With this implementation \TeX's shipout primitive is no longer
+% available for direct use. Instead \cs{shipout} is running some
+% (complicated) code that picks up the box to be shipped out
+% regardless of how that is done, i.e., as a constructed \cs{vbox}
+% or \cs{hbox} or as a box register.
+%
+% It then stores it in a named box register. This box can then be
+% manipulated through a set of hooks after which it is shipped out
+% for real.
+% \end{function}
+
+% \begin{variable}{\ShipoutBox,\l_shipout_box}
+% This box register is called \cs{ShipoutBox} (alternatively available via the
+% L3 name \cs{l_shipout_box}).
+% \end{variable}
+%
+
+% \begin{variable}{\l_shipout_box_ht_dim,
+% \l_shipout_box_dp_dim,\l_shipout_box_wd_dim,
+% \l_shipout_box_ht_plus_dp_dim}
+% The shipout box dimensions are available in the L3 registers
+% \cs{l_shipout_box_ht_dim}, etc.\ (there are no \LaTeXe{}
+% names).\footnotemark{} These variables can be used
+% inside the hook code for \hook{shipout/before},
+% \hook{shipout/foreground} and \hook{shipout/background} if needed.
+% \end{variable}
+% \footnotetext{Might need changing, but HO's version as strings
+% is not really helpful I think).}
+%
+%
+%
+%
+% \subsection{Provided hooks}
+%
+% \begin{variable}{shipout/before,
+% shipout/foreground,shipout/background,
+% shipout/firstpage,
+% shipout/lastpage}
+% The code offers a number of hooks into which packages (or the
+% user) can add code to support different use cases.
+% These are:
+% \begin{description}
+% \item[\hook{shipout/before}]
+%
+% This hook is executed after the finished page has been stored in
+% \cs{ShipoutBox} / \cs{l_shipout_box}).
+% It can be used to alter that box content or to discard it
+% completely (see \cs{DiscardShipoutBox} below).
+%
+% \item[\hook{shipout/background}]
+%
+% This hook adds a picture environment into the background of
+% the page (with the \texttt{(0,0)} coordinate in the top-left
+% corner using a \cs{unitlength} of \texttt{1pt}.
+%
+% It should therefore only receive \cs{put} commands or other
+% commands suitable in a \texttt{picture} environment and the
+% vertical coordinate values would normally be
+% negative.
+%
+% \fmi{Again, mainly \pkg{atbegshi} compatibility. Not
+% sure it is best to have to always use negative
+% coordinates.}
+%
+% Technically this is implemented by adding a zero-sized
+% \cs{hbox} as the very first item into the \cs{ShipoutBox}
+% containing that \texttt{picture} environment. Thus the rest of
+% the box content will overprint what ever is typeset by that hook.
+%
+%
+% \item[\hook{shipout/foreground}]
+%
+% This hook adds a picture environment into the foreground of
+% the page (with the \texttt{(0,0)} coordinate in the top-left
+% corner using a \cs{unitlength} of \texttt{1pt}.
+%
+% Technically this is implemented by adding a zero-sized
+% \cs{hbox} as the very last item into the \cs{ShipoutBox} and
+% raising it up so that it still has its \texttt{(0,0)} point in
+% the top-left corner.
+% But being placed after the main box content it will be typeset
+% later and thus overprints it (i.e., is in the foreground).
+%
+%
+% \item[\hook{shipout/firstpage}]
+%
+% The material from this hook is executed only once at the very
+% beginning of the first output page. It should only contain
+% \cs{special} commands needed to direct post processors
+% handling the \texttt{.dvi} or \texttt{.pdf} output.\fmi{not
+% sure it has to be that restrictive.}
+%
+% In \LaTeXe{} that was already existing but implemented as a box
+% register \cs{@begindvibox}.
+% \fmi{drop or at least mark the obsolete code in latex.ltx}
+%
+%
+% \item[\hook{shipout/lastpage}]
+%
+% The corresponding hook to add \cs{special}s at the very end of
+% the output file. It is only entered on the very last page.
+%
+% It may not be possible for \LaTeX{} to correctly determine which page is
+% the last one without several reruns. If this happens and the
+% hook is non-empty then \LaTeX{} will add an extra page to
+% place the material and also request a rerun to get the correct
+% placement sorted out.
+%
+% \end{description}
+% \end{variable}
+%
+% As mentioned above the hook \hook{shipout/before} is executed
+% first and can manipulate the prepared shipout box stored in
+% \cs{ShipoutBox} or set things up for use in \cs{write} during the
+% actual shipout. The other hooks are added inside hboxes to the
+% box being shipped out in the following
+% order:
+% \begin{center}
+% \begin{tabular}{ll}
+% \hook{shipout/firstpage} & only on the first page \\
+% \hook{shipout/background} & \\
+% \meta{boxed content of \cs{ShipoutBox}} & \\
+% \hook{shipout/foreground} & \\
+% \hook{shipout/lastpage} & only on the last page \\
+% \end{tabular}
+% \end{center}
+% If any of the hooks has no code then that particular no box is
+% added at that point.
+%
+% In a document that doesn't produce pages, e.g., only makes
+% \cs{typeout}s, none of the hooks are executed (as there is no
+% \cs{shipout}) not even the \hook{shipout/lastpage} hook.
+%
+% \begin{function}{\AtBeginDvi,\AtEndDvi}
+% \cs{AtBeginDvi} is the existing \LaTeXe{} interface to fill the
+% \hook{shipout/firstpage} hook. This is not really a good name
+% as it is not just supporting \texttt{.dvi} but also \texttt{.pdf}
+% output or \texttt{.dvx}.
+%
+% \cs{AtEndDvi} is the counterpart that was not available in the
+% kernel but only through the package \pkg{atenddvi}. It fills the
+% \hook{shipout/lastpage} hook.
+%
+% \fmi{better names? Any suggestions?}
+%
+% \end{function}
+%
+% \subsection{Special commands for use inside the hooks}
+%
+% \begin{function}{\DiscardShipoutBox,\shipout_discard_box:}
+% \begin{syntax}
+% \cs{AddToHookNext} \texttt{\{shipout/before\} \{...\cs{DiscardShipoutBox}...\}}
+% \end{syntax}
+% The \cs{DiscardShipoutBox} declaration (L3 name
+% \cs{shipout_discard_box:})
+% requests that on the next
+% shipout the page box is thrown away instead of being shipped to
+% the \texttt{.dvi} or \texttt{.pdf} file.
+%
+% Typical applications wouldn't do this unconditionally, but have
+% some processing logic that decides to use or not to use the page.
+%
+% Note that if this declaration is used directly in the document it
+% may depend on the placement to which page it applies, given that
+% \LaTeX{} output routine is called in an asynchronous manner!
+%
+% \fmi{Once we have a new mark mechanism available we can improve
+% on that and make sure that the declaration applies to the page
+% that contains it.}
+% \end{function}
+%
+% In the \pkg{atbegshi} package there are a number of additional
+% commands for use inside the \hook{shipout/before} hook. They
+% should normally not be needed any more as one can instead simply
+% add code to the hooks \hook{shipout/before},
+% \hook{shipout/background} or
+% \hook{shipout/foreground}.\footnote{If that assumption turns out to
+% be wrong it would be trivial to change them to public functions
+% (right now they are private).} If \pkg{atbegshi} gets loaded then
+% those commands become available as public functions with their original
+% names as given below.
+%
+%
+% \subsection{Information counters}
+%
+%
+% \begin{variable}{\ReadonlyShipoutCounter,\g_shipout_readonly_int}
+% \begin{syntax}
+% \cs{ifnum}\cs{ReadOnlyShipoutCounter}\texttt{=...}
+% \cs{int_use:N} \cs{g_shipout_readonly_int} \texttt{\% expl3 usage}
+% \end{syntax}
+% This integer holds the number of pages shipped out up to now
+% (including the one to be shipped out when inside the output
+% routine). More precisely, it is incremented only after it is
+% clear that a page will be shipped out, i.e., after the
+% \hook{shipout/before} hook (because that might discard the page)!
+
+% Just like with the \texttt{page} counter its value is
+% only accurate within the output routine. In the body of the
+% document it may be off by one as the output routine is called
+% asynchronously!
+%
+% Also important: it \emph{must not} be set, only read. There are
+% no provisions to prevent that but if you do, chaos will be the
+% result. To emphasize this fact it is not provided as a \LaTeX{}
+% counter but as a \TeX{} counter (i.e., a command), so
+% \cs{Alph}\Arg{\cs{ReadonlyShipoutCounter}} etc, would not work.
+% \end{variable}
+%
+% \begin{variable}{totalpages,\g_shipout_totalpages_int}
+% \begin{syntax}
+% \cs{arabic}\texttt{\{totalpages\}}
+% \cs{int_use:N} \cs{g_shipout_totalpage_int} \texttt{\% expl3 usage}
+% \end{syntax}
+% In contrast to \cs{ReadonlyShipoutCounter}, the
+% \texttt{totalpages} counter is a \LaTeX{} counter and incremented
+% for each shipout attempt including those pages that are discarded
+% for one or the other reason. Again \hook{shipout/before} sees
+% the counter before it is incremented).
+%
+% Furthermore, while it is incremented for each page, its value is
+% never used by \LaTeX. It can therefore be freely reset or changed by user
+% code, for example, to additionally count a number of pages that
+% are not build by \LaTeX\ but are added in a later part of the
+% process, e.g., cover pages or picture pages made externally.
+%
+% Important: as this is a page-related counter its value is only
+% reliable inside the output routine!
+% \end{variable}
+%
+
+%
+% \subsection{Debugging shipout code}
+%
+% \begin{function}{\DebugShipoutOn,\DebugShipoutOff,
+% \shipout_debug_on:,\shipout_debug_off:}
+% \begin{syntax}
+% \cs{DebugShipoutOn}
+% \end{syntax}
+% Turn the debugging of shipout code on or off. This displays
+% changes made to the shipout data structures. \fmi{This needs
+% some rationalizing and will probably not stay this way.}
+% \end{function}
+%
+%
+
+%
+% \section{Emulating commands from other packages}
+%
+% The packages in this section are no longer necessary but as they
+% are used in other packages they are emulated when they are loaded
+% via \cs{usepackage} or \cs{RequirePackage}.
+%
+%
+% \subsection{Emulating \pkg{atbegshi}}
+%
+%
+% \begin{function}{\AtBeginShipoutUpperLeft,\AtBeginShipoutUpperLeftForeground}
+% \begin{syntax}
+% \cs{AddToHook} \texttt{\{shipout/before\} \{...\cs{AtBeginShipoutUpperLeft}}\Arg{code}\texttt{...\}}
+% \end{syntax}
+% This adds a \texttt{picture} environment into the background of the shipout
+% box expecting \meta{code} to contain \texttt{picture}
+% commands. The same effect can be obtained by simply using kernel
+% features as follows:
+% \begin{quote}
+% \cs{AddToHook}\texttt{\{shipout/background\}}\Arg{code}
+% \end{quote}
+% There is one technical difference: if
+% \cs{AtBeginShipoutUpperLeft} is used several times each
+% invocation is put into its own box inside the shipout box whereas
+% all \meta{code} going into \hook{shipout/background} ends up
+% all in the same box in the order it is added or sorted based on
+% the rules for the hook chunks.
+%
+% \cs{AtBeginShipoutUpperLeftForeground} is similar with the
+% difference that the \texttt{picture} environment is placed in the
+% foreground. To model it with the kernel functions use the hook
+% \hook{shipout/foreground} instead.
+% \end{function}
+%
+%
+% \begin{function}{\AtBeginShipoutAddToBox,\AtBeginShipoutAddToBoxForeground}
+% \begin{syntax}
+% \cs{AddToHook} \texttt{\{shipout/before\} \{...\cs{AtBeginShipoutAddToBox}}\Arg{code}\texttt{...\}}
+% \end{syntax}
+% These work like \cs{AtBeginShipoutUpperLeft} and
+% \cs{AtBeginShipoutUpperLeftForeground} with the difference that
+% \meta{code} is directly placed into an \cs{hbox} inside the
+% shipout box and not surrounded by a \texttt{picture} environment.
+%
+% To emulate them using \hook{shipout/background} or
+% \hook{shipout/foreground} you may have to wrap \meta{code} into
+% a \cs{put} statement but if the code is not doing any typesetting
+% just adding it to the hook should be sufficient.
+% \end{function}
+%
+
+
+% \begin{function}{\AtBeginShipoutBox}
+% This is the name of the shipout box as \pkg{atbegshi} knows it.
+% \end{function}
+%
+% \begin{function}{\AtBeginShipoutInit}
+% By default \pkg{atbegshi} delayed its action until
+% \verb=\beg{document}=. This command was forcing it in an earlier
+% place. With the new concept it does nothing.
+% \end{function}
+%
+% \begin{function}{\AtBeginShipout,\AtBeginShipoutNext}
+% \begin{syntax}
+% \cs{AtBeginShipout}\Arg{code} $\equiv$ \cs{AddToHook}\texttt{\{shipout/before\}}\Arg{code}
+% \cs{AtBeginShipoutNext}\Arg{code} $\equiv$ \cs{AddToHookNext}\texttt{\{shipout/before\}}\Arg{code}
+% \end{syntax}
+% This is equivalent to filling the \hook{shipout/before} hook
+% by either using \cs{AddToHook} or \cs{AddToHookNext}, respectively.
+% \end{function}
+%
+% \begin{function}{\AtBeginShipoutFirst,\AtBeginShipoutDiscard}
+% The \pkg{atbegshi} names for \cs{AtBeginDvi} and \cs{DiscardShipoutBox}.
+% \end{function}
+%
+
+
+
+% \subsection{Emulating \pkg{everyshi}}
+%
+
+
+% \begin{function}{\EveryShipout}
+% \begin{syntax}
+% \cs{EveryShipout}\Arg{code} $\equiv$ \cs{AddToHook}\texttt{\{shipout/before\}}\Arg{code}
+% \end{syntax}
+% \end{function}
+%
+% \begin{function}{\AtNextShipout}
+% \begin{syntax}
+% \cs{AtNextShipout}\Arg{code} $\equiv$ \cs{AddToHookNext}\texttt{\{shipout/before\}}\Arg{code}
+% \end{syntax}
+% \end{function}
+%
+
+
+% \subsection{Emulating \pkg{atenddvi}}
+%
+% The \pkg{atenddvi} package implemented only a single command:
+% \cs{AtEndDvi} and that is now available out of the box.
+
+
+
+% \subsection{Emulating \pkg{everypage}}
+%
+% This page takes over the original \cs{@begindvi} hook and replaces
+% it. It should be all covered by the hooks offered here (details
+% need checking) and thus could simply use the provided hooks
+% rather than defining its own.
+%
+%
+%
+% \StopEventually{\setlength\IndexMin{200pt} \PrintIndex }
+%
+%
+% \section{The Implementation}
+% \begin{macrocode}
+%<*2ekernel>
+%<@@=shipout>
+\ExplSyntaxOn
+% \end{macrocode}
+%
+%
+% \subsection{Debugging}
+%
+% \begin{macro}{\g_@@_debug_bool}
+% Holds the current debugging state.
+% \begin{macrocode}
+\bool_new:N \g_@@_debug_bool
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\shipout_debug_on:,\shipout_debug_off:}
+% \begin{macro}{\@@_debug:n}
+% \begin{macro}{\@@_debug_gset:}
+% Turns debugging on and off by redefining \cs{@@_debug:n}.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_debug:n \use_none:n
+\cs_new_protected:Npn \shipout_debug_on:
+ {
+ \bool_gset_true:N \g_@@_debug_bool
+ \@@_debug_gset:
+ }
+\cs_new_protected:Npn \shipout_debug_off:
+ {
+ \bool_gset_false:N \g_@@_debug_bool
+ \@@_debug_gset:
+ }
+\cs_new_protected:Npn \@@_debug_gset:
+ {
+ \cs_gset_protected:Npx \@@_debug:n ##1
+ { \bool_if:NT \g_@@_debug_bool {##1} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+
+% \begin{macro}{shipout/before,
+% shipout/foreground,shipout/background,
+% shipout/firstpage,
+% shipout/lastpage}
+% Declaring all hooks for the shipout code.
+% \begin{macrocode}
+\hook_new:n{shipout/before}
+\hook_new:n{shipout/foreground}
+\hook_new:n{shipout/background}
+\hook_new:n{shipout/firstpage}
+\hook_new:n{shipout/lastpage}
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \begin{macro}{\ShipoutBox,\l_shipout_box}
+% The box filled with the page to be shipped out (both L3 and
+% \LaTeXe{} name).
+% \begin{macrocode}
+\box_new:N \l_shipout_box
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_set_eq:NN \ShipoutBox \l_shipout_box
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \begin{macro}{\@@_execute:}
+% This is going to the be the code run by \cs{shipout}. The code
+% follows closely the ideas from \pkg{atbegshi}, so not
+% documenting that here for now.
+% \begin{macrocode}
+\cs_set:Npn\@@_execute: {
+ \tl_set:Nx \l_@@_group_level_tl
+ { \int_value:w \tex_currentgrouplevel:D }
+ \tex_afterassignment:D \@@_execute_test_level:
+ \tex_setbox:D \l_shipout_box
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\shipout}
+% Overloading the \cs{shipout} primitive:
+% \begin{macrocode}
+\cs_gset_eq:NN \shipout \@@_execute:
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\l_@@_group_level_tl}
+% Helper token list to record the group level at which
+% \cs{@@_execute:} is encountered. \begin{macrocode}
+\tl_new:N \l_@@_group_level_tl
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\@@_execute_test_level:}
+% If the group level has changed then we are still constructing
+% \cs{l_shipout_box} and to continue we need to wait until the
+% current group has finished, hence the \cs{tex_aftergroup:D}.
+% \begin{macrocode}
+\cs_new:Npn \@@_execute_test_level: {
+ \int_compare:nNnT
+ \l_@@_group_level_tl < \tex_currentgrouplevel:D
+ \tex_aftergroup:D
+ \@@_execute_cont:
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_execute_cont:}
+% When we have reached this point the shipout box has been
+% processed and is available in \cs{l_shipout_box} and ready for
+% real ship out (perhaps)..
+%
+% First we quickly check if it is void (can't happen in the
+% standard \LaTeX{} output routine but \cs{shipout} might be called
+% from a package that has some special processing logic). If it is
+% void we aren't shipping anything out and processing ends.\footnote{In that
+% case we don't reset the deadcyles, that would be up to the OR
+% processing logic to do.}
+% \begin{macrocode}
+\cs_new:Npn \@@_execute_cont: {
+ \box_if_empty:NTF \l_shipout_box
+ { \PackageWarning{ltshipout}{Ignoring~ void~ shipout~ box} }
+ {
+% \end{macrocode}
+% Otherwise we assume that we will ship something and prepare for
+% final adjustments (in particular setting the state of
+% \cs{protect} while we are running the hook code).
+% \begin{macrocode}
+ \bool_gset_false:N \g_@@_discard_bool
+ \set@typeset@protect
+% \end{macrocode}
+% We also store the current shipout box dimension in registers, so that
+% they can be used in the hook code.\footnote{This is not really
+% necessary as the code could access them via \cs{box_ht:N}, etc.,
+% but it is perhaps convenient.}
+% \begin{macrocode}
+ \@@_get_box_size:N \l_shipout_box
+% \end{macrocode}
+% Then we execute the \hook{shipout/before} hook.
+% \begin{macrocode}
+ \hook_use:n {shipout/before}
+% \end{macrocode}
+% In \cs{g_shipout_totalpages_int} we count all shipout attempts so
+% we increment that counter already here (the other one is
+% incremented later when we know for sure that we do a
+% \cs{shipout}.
+%
+% We increment it after running the above hook so that the values
+% for \cs{g_shipout_totalpages_int} and \cs{} are in sync while the
+% hook is executed (in the case that totalpages isn't manually
+% altered or through discarding pages that is).
+% \begin{macrocode}
+ \int_gincr:N \g_shipout_totalpages_int
+% \end{macrocode}
+% The above hook might contain code that requests the page to be discarded so
+% we now test for it.
+% \begin{macrocode}
+ \bool_if:NTF \g_@@_discard_bool
+ { \PackageInfo{ltshipout}{Completed~ page~ discarded}
+ \bool_gset_false:N \g_@@_discard_bool
+% \end{macrocode}
+% As we are discarding the page box and not shipping anything out,
+% we need to do some house cleaning and reset \TeX's deadcycles so
+% that it doesn't complain about too many calls to the OR without
+% any shipout.
+% \begin{macrocode}
+ \tex_deadcycles:D \c_zero_int
+% \end{macrocode}
+% \fmi{In \pkg{atbegshi} the box was dropped but is that actually
+% needed? Or the resetting of \cs{protect} to its kernel value?}
+% \begin{macrocode}
+% \group_begin:
+% \box_set_eq_drop:NN \l_shipout_box \l_shipout_box
+% \group_end:
+% \cs_set_eq:NN \protect \exp_not:N
+ }
+% \end{macrocode}
+% Even if there was no explicit request to discard the box it is
+% possible that the code for the hook \hook{shipout/before} has
+% voided the box (by mistake or deliberately). We therefore test
+% once more but this time make it a warning, because the best
+% practice way is to use the request mechanism.
+% \begin{macrocode}
+ { \box_if_empty:NTF \l_shipout_box
+ { \PackageWarning{ltshipout}{
+ Shipout~ box~ was~ voided~ by~ hook,\MessageBreak
+ ignoring~ shipout~ box }
+ }
+% \end{macrocode}
+% Finally, if the box is still non-empty we are nearly ready to
+% ship it out.
+% First we increment the total page counter so that we can later
+% test if we have reached the final page according to our available
+% information.\footnote{Doing that earlier would be wrong because we
+% might end up with the last page counted but discard and then we
+% have no place to add the final objects into the output file.}
+% \begin{macrocode}
+ {
+ \int_gincr:N \g_shipout_readonly_int
+ \@@_debug:n {
+ \typeout{Absolute~ page~ =~ \int_use:N \g_shipout_readonly_int
+ \space (target:~ \@abspage@last)}
+ }
+% \end{macrocode}
+% Then we store the box sizes again (as they may have
+% changed) and then look at the hooks \hook{shipout/foreground}
+% and \hook{shipout/background}. If either or both are non-empty
+% we add a \texttt{picture} environment to the box (in the
+% foreground and or in the background) and execute the hook code
+% inside that environment.
+%
+% \begin{macrocode}
+ \@@_get_box_size:N \l_shipout_box
+ \@kernel@before@shipout@foreground
+ \hook_if_empty:nF {shipout/foreground}
+ { \@@_add_foreground_picture:n
+ { \hook_use:n {shipout/foreground} } }
+ \hook_if_empty:nF {shipout/background}
+ { \@@_add_background_picture:n
+ { \hook_use:n {shipout/background} } }
+% \end{macrocode}
+% We then run \cs{@@_execute_firstpage_hook:} that adds
+% the content of the hook \hook{shipout/firstpage} to the
+% start of the first page (if non-empty). It is then redefined to
+% do nothing on later pages.
+% \begin{macrocode}
+ \@@_execute_firstpage_hook:
+% \end{macrocode}
+% The we check if we have to add the \hook{shipout/lastpage} hook
+% because we have reached the last page. This test will be false for
+% all but one (and hopefully the correct) page.
+% \begin{macrocode}
+ \int_compare:nNnT \@abspage@last = \g_shipout_readonly_int
+ { \hook_if_empty:nF {shipout/lastpage}
+ { \@@_debug:n { \typeout{Executing~ lastpage~ hook~
+ on~ page~ \int_use:N \g_shipout_readonly_int } }
+ \_@@_add_foreground_box:n { \UseHook{shipout/lastpage}
+ \@kernel@after@shipout@lastpage }
+ }
+ \bool_gset_true:N \g_@@_lastpage_handled_bool
+ }
+% \end{macrocode}
+% Finally we run the actual \TeX{} primitive for shipout. As that will
+% expand delayed \cs{write} statements inside the page in which
+% protected commands should not expand we first change \cs{protect}
+% to the appropriate definition for that case.
+% \begin{macrocode}
+ \cs_set_eq:NN \protect \exp_not:N
+ \tex_shipout:D \box_use:N \l_shipout_box
+ }
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\@kernel@after@shipout@lastpage,\@kernel@before@shipout@foreground}
+%
+% \begin{macrocode}
+\let\@kernel@after@shipout@lastpage\@empty
+\let\@kernel@before@shipout@foreground\@empty
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_execute_firstpage_hook: }
+% This command adds any specials into a box and adds that to the
+% very beginning of the first box shipped out. After that we
+% redefine it to do nothing on later pages.
+% \begin{macrocode}
+\cs_new:Npn \@@_execute_firstpage_hook: {
+% \end{macrocode}
+% Adding something to the beginning means adding it to the
+% background as that layer is done first in the output. Of course
+% that is only needed if the hook actually contains anything.
+% \begin{macrocode}
+ \hook_if_empty:nF {shipout/firstpage}
+ { \@@_add_background_box:n { \UseHook{shipout/firstpage} } }
+% \end{macrocode}
+% Once we are here we change the definition to do nothing next time
+% and we also change the command used to implement \cs{AtBeginDvi}
+% to become a warning and not add further material to a hook that
+% is never used again.
+% \begin{macrocode}
+ \cs_gset_eq:NN \@@_execute_firstpage_hook: \prg_do_nothing:
+ \cs_gset:Npn \@@_add_firstpage_material:Nn ##1 ##2 {
+ \PackageWarning{ltshipout}{
+ First~ page~ is~ already~ shipped~ out,~ ignoring\MessageBreak
+ \string##1 }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\g_@@_lastpage_handled_bool}
+% A boolean to signal if we have already handled the
+% \hook{shipout/lastpage} hook.
+% \begin{macrocode}
+\bool_new:N \g_@@_lastpage_handled_bool
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\@@_add_firstpage_material:Nn}
+% This command adds material to the
+% \hook{shipout/firstpage} hook. It is used in
+% \cs{AtBeginDvi}, etc. The first argument is the
+% command through which is it called. Initially this is ignored but
+% once we are passed the first page it can be used to generate a
+% warning message mentioning the right user command.
+% \begin{macrocode}
+\cs_new:Npn \@@_add_firstpage_material:Nn #1#2 {
+ \AddToHook{shipout/firstpage}{#2}
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+
+
+
+% \begin{macro}{\@@_get_box_size:N}
+% Store the box dimensions in dimen registers.
+% \fmi{This could/should perhaps be generalized to set height depth and
+% width given an arbitrary box.}
+% \begin{macrocode}
+\cs_new:Npn \@@_get_box_size:N #1 {
+ \dim_set:Nn \l_shipout_box_ht_dim { \box_ht:N #1 }
+ \dim_set:Nn \l_shipout_box_dp_dim { \box_dp:N #1 }
+ \dim_set:Nn \l_shipout_box_wd_dim { \box_wd:N #1 }
+ \dim_set:Nn \l_shipout_box_ht_plus_dp_dim { \l_shipout_box_ht_dim +
+ \l_shipout_box_dp_dim }
+}
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\l_shipout_box_ht_dim,
+% \l_shipout_box_dp_dim,\l_shipout_box_wd_dim,
+% \l_shipout_box_ht_plus_dp_dim}
+% And here are the variables set by \cs{@@_get_box_size:N}.
+% \begin{macrocode}
+\dim_new:N \l_shipout_box_ht_dim
+\dim_new:N \l_shipout_box_dp_dim
+\dim_new:N \l_shipout_box_wd_dim
+\dim_new:N \l_shipout_box_ht_plus_dp_dim
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+
+% \begin{macro}{\g_@@_discard_bool}
+% Indicate whether or not the current page box should be discarded
+% \begin{macrocode}
+\bool_new:N \g_@@_discard_bool
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\l_@@_tmp_box,\l_@@_saved_badness_tl}
+% We need a box for the background and foreground material and a
+% token register to remember badness settings as we disable them
+% during te buildup below.
+% \begin{macrocode}
+\box_new:N \l_@@_tmp_box
+\tl_new:N \l_@@_saved_badness_tl
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_add_background_box:n}
+% In standard \LaTeX{} the shipout box is always a \cs{vbox} but
+% here we are allow for other usage as well, in case some package
+% has its own output routine.
+% \begin{macrocode}
+\cs_new:Npn \@@_add_background_box:n #1
+{ \@@_get_box_size:N \l_shipout_box
+% \end{macrocode}
+% But we start testing for a vertical box as that should be the
+% normal case.
+% \begin{macrocode}
+ \box_if_vertical:NTF \l_shipout_box
+ {
+% \end{macrocode}
+% Save current values of \cs{vfuzz} and \cs{vbadness} then change
+% them to allow box manipulations without warnings.
+% \begin{macrocode}
+ \tl_set:Nx \l_@@_saved_badness_tl
+ { \vfuzz=\the\vfuzz\relax
+ \vbadness=\the\vbadness\relax }
+ \vfuzz=\c_max_dim
+ \vbadness=\c_max_int
+% \end{macrocode}
+% Then we reconstruct \cs{l_shipout_box} \ldots
+% \begin{macrocode}
+ \vbox_set_to_ht:Nnn \l_shipout_box \l_shipout_box_ht_plus_dp_dim
+ {
+% \end{macrocode}
+% \ldots{} the material in \verb=#1= is placed into a horizontal
+% box with zero dimensions.
+% \begin{macrocode}
+ \hbox_set:Nn \l_@@_tmp_box
+ { \l_@@_saved_badness_tl #1 }
+ \box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
+% \end{macrocode}
+% The we typeset that box followed by whatever was in
+% \cs{l_shipout_box} before (unpacked).
+% \begin{macrocode}
+ \skip_zero:N \baselineskip
+ \skip_zero:N \lineskip
+ \skip_zero:N \lineskiplimit
+ \box_use:N \l_@@_tmp_box
+ \vbox_unpack:N \l_shipout_box
+% \end{macrocode}
+% The \cs{kern} ensures that the box has no depth which is
+% afterwards explicitly corrected.
+% \begin{macrocode}
+ \kern \c_zero_dim
+ }
+ \box_set_ht:Nn \l_shipout_box \l_shipout_box_ht_dim
+ \box_set_dp:Nn \l_shipout_box \l_shipout_box_dp_dim
+% \end{macrocode}
+% \fmi{The whole boxing maneuver looks a bit like overkill to me, but for
+% the moment I leave.}
+% \begin{macrocode}
+ \l_@@_saved_badness_tl
+ }
+ {
+% \end{macrocode}
+% A horizontal box is handled in a similar way. The last case would
+% be a void box in which case we do nothing hence the missing
+% \texttt{F} branch.
+% \begin{macrocode}
+ \box_if_horizontal:NT \l_shipout_box
+ {
+ \tl_set:Nx \l_@@_saved_badness_tl
+ { \hfuzz=\the\hfuzz\relax
+ \hbadness=\the\hbadness\relax }
+ \hfuzz=\c_max_dim
+ \hbadness=\c_max_int
+ \hbox_set_to_wd:Nnn \l_shipout_box \l_shipout_box_wd_dim
+ {
+ \hbox_set:Nn \l_@@_tmp_box
+ { \l_@@_saved_badness_tl #1 }
+ \box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
+ \box_move_up:nn
+ \l_shipout_box_ht_dim
+ { \box_use:N \l_@@_tmp_box }
+ \hbox_unpack:N \l_shipout_box
+ }
+ \l_@@_saved_badness_tl
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \begin{macro}{\@@_add_foreground_box:n}
+% Foreground boxes are done in the same way, only the order and
+% placement of boxes has to be done differently.
+% \begin{macrocode}
+\cs_new:Npn \@@_add_foreground_box:n #1
+{
+ \box_if_vertical:NTF \l_shipout_box
+ {
+ \tl_set:Nx \l_@@_saved_badness_tl
+ { \vfuzz=\the\vfuzz\relax
+ \vbadness=\the\vbadness\relax }
+ \vfuzz=\c_max_dim
+ \vbadness=\c_max_int
+ \vbox_set_to_ht:Nnn \l_shipout_box \l_shipout_box_ht_plus_dp_dim
+ {
+ \hbox_set:Nn \l_@@_tmp_box
+ { \l_@@_saved_badness_tl #1 }
+ \box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
+ \skip_zero:N \baselineskip
+ \skip_zero:N \lineskip
+ \skip_zero:N \lineskiplimit
+ \vbox_unpack:N \l_shipout_box
+ \kern -\l_shipout_box_ht_plus_dp_dim
+ \box_use:N \l_@@_tmp_box
+ \kern \l_shipout_box_ht_plus_dp_dim
+ }
+ \l_@@_saved_badness_tl
+ \box_set_ht:Nn \l_shipout_box \l_shipout_box_ht_dim
+ \box_set_dp:Nn \l_shipout_box \l_shipout_box_dp_dim
+ }
+ {
+ \box_if_horizontal:NT \l_shipout_box
+ {
+ \tl_set:Nx \l_@@_saved_badness_tl
+ { \hfuzz=\the\hfuzz\relax
+ \hbadness=\the\hbadness\relax }
+ \hfuzz=\c_max_dim
+ \hbadness=\c_max_int
+ \hbox_set_to_wd:Nnn \l_shipout_box \l_shipout_box_wd_dim
+ {
+ \hbox_unpack:N \l_shipout_box
+ \kern -\box_wd:N \l_shipout_box
+ \hbox_set:Nn \l_@@_tmp_box
+ { \l_@@_saved_badness_tl #1 }
+ \box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
+ \box_move_up:nn { \box_ht:N \l_shipout_box }
+ { \box_use:N \l_@@_tmp_box }
+ \kern \box_wd:N \l_shipout_box
+ }%
+ \l_@@_saved_badness_tl
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \begin{macro}{\c_@@_horigin_tl,\c_@@_vorigin_tl}
+% Two constants holding the offset of the top-left with respect to
+% the media box.
+%
+% Setting the constants this way is courtesy of Bruno.
+% \begin{macrocode}
+\tl_gput_right:Nn \@kernel@after@begindocument {
+ \tl_const:Nx \c_@@_horigin_tl
+ {
+ \cs_if_exist_use:NTF \pdfvariable { horigin }
+ { \cs_if_exist_use:NF \pdfhorigin { 1in } }
+ }
+ \tl_const:Nx \c_@@_vorigin_tl
+ {
+ \cs_if_exist_use:NTF \pdfvariable { vorigin }
+ { \cs_if_exist_use:NF \pdfvorigin { 1in } }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_picture_overlay:n}
+% Put the argument into a \texttt{picture} environment that doesn't take up
+% any size and uses \texttt{1pt} for \cs{unitlength}.
+% \fmi{Could perhaps be generalized as it might be useful elsewhere. For
+% not it is not.}
+% \begin{macrocode}
+\cs_new:Npn \@@_picture_overlay:n #1 {
+ \kern -\c_@@_horigin_tl \scan_stop:
+ \vbox_to_zero:n {
+ \kern -\c_@@_vorigin_tl \scan_stop:
+ \unitlength 1pt \scan_stop:
+ \hbox_set_to_wd:Nnn \l_@@_tmp_box \c_zero_dim { \ignorespaces #1 }
+% \box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
+ \box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
+ \box_use:N \l_@@_tmp_box
+ \tex_vss:D
+ }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\@@_add_background_picture:n}
+% Put a \texttt{picture} env in the background of the shipout box
+% with its reference point in the top-left corner.
+% \begin{macrocode}
+\cs_new:Npn \@@_add_background_picture:n #1 {
+ \@@_add_background_box:n { \@@_picture_overlay:n {#1} }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\@@_add_foreground_picture:n}
+%
+% Put a \texttt{picture} env in the foreground of the shipout box
+% with its reference point in the top-left corner.
+% \begin{macrocode}
+\cs_new:Npn \@@_add_foreground_picture:n #1 {
+ \@@_add_foreground_box:n { \@@_picture_overlay:n {#1} }
+}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\shipout_discard:}
+% Request that the next shipout box should be discarded. At the
+% moment this is just setting a boolean, but we may want to augment
+% this behavior that the position of the call is taken into account
+% (in case \LaTeX{} looks ahead and is not using the position for
+% on the next page).
+% \begin{macrocode}
+\cs_new:Npn \shipout_discard: {
+ \bool_gset_true:N \g_@@_discard_bool
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \subsection{Handling the end of job hook}
+
+% At the moment this is partly solved by using the existing hooks.
+% But rather than putting the code into these hooks it should be
+% moved to the right place directly as we shouldn't prefill hooks
+% with material unless it needs to interact with other code.
+%
+
+%
+% \begin{macro}{\g_shipout_readonly_int,\ReadonlyShipoutCounter}
+% We count every shipout activity that makes a page (but not those
+% that are discarded) in order to know how many pages got produced.
+% \begin{macrocode}
+\int_new:N \g_shipout_readonly_int
+% \end{macrocode}
+% For \LaTeXe{} it is available as a command (i.e., a \TeX{}
+% counter only.
+% \begin{macrocode}
+\cs_new_eq:NN \ReadonlyShipoutCounter \g_shipout_readonly_int
+% \end{macrocode}
+% \end{macro}
+
+% \begin{macro}{\g_shipout_totalpages_int,\c@totalpages}
+% We count every shipout attempt (even those that are discarded) in
+% tis counter. It is not used in the code but may get used in user
+% code.
+% \begin{macrocode}
+\int_new:N \g_shipout_totalpages_int
+% \end{macrocode}
+% For \LaTeXe{} this is offered as a \LaTeX{} counter so can be
+% easily typeset inside the output routine to display things like
+% \enquote{\cs{thepage}\texttt{/}\cs{thetotalpages}}, etc.
+% \begin{macrocode}
+\cs_new_eq:NN \c@totalpages \g_shipout_totalpages_int
+\cs_new:Npn \thetotalpages { \arabic{totalpages} }
+% \end{macrocode}
+% \end{macro}
+%
+
+
+
+% \begin{macro}{\@abspage@last}
+% In \cs{@abspage@last} record the number of pages from the last
+% run. This is written to the \texttt{.aux} and this way made
+% available to the next run. In case there is no \texttt{.aux} file
+% or the statement is missing from it we initialize it with the
+% largest possible number in \TeX{}. We use this a s the default
+% because then we are inserting the \hook{shipout/lastpage} on
+% the last page (or after the last page but not on page 1 for a
+% multipage document.
+% \begin{macrocode}
+\xdef\@abspage@last{\number\maxdimen}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\enddocument}
+%
+% Instead of using the hooks \hook{enddocument} and
+% \hook{enddocument/afterlastpage} we add this code to private
+% kernel hooks to be 100\% when it is executed and to avoid
+% cluttering the hooks with data that is always there.
+%
+% Inside \cs{enddocument} there is a \cs{clearpage}. Just before
+% that we execute this code here. There is a good change that we
+% are on the last page. Therefore, if we don't know the value from
+% the last run, we assume that the current page is the right
+% one. So we set \cs{@abspage@last} and as a result the next
+% shipout will run the \hook{shipout/lastpage} code. Of course,
+% if there are floats that still need a placement this guess will
+% be wrong but then rerunning the document will give us the correct
+% value next time around.
+%
+% \begin{macro}{\@kernel@after@enddocument}
+% \begin{macrocode}
+\g@addto@macro \@kernel@after@enddocument {
+ \int_compare:nNnT \@abspage@last = \maxdimen
+ {
+% \end{macrocode}
+% We use \LaTeXe{} coding as \cs{@abspage@last} is not an L3 name.
+% \begin{macrocode}
+ \xdef\@abspage@last{ \int_eval:n {\g_shipout_readonly_int + 1} }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@kernel@after@enddocument@afterlastpage}
+% Once the \cs{clearpage} has done its work inside \cs{enddocument}
+% we know for sure how many pages this document has, so we record
+% that in the \texttt{.aux} file for the next run.
+%
+% \begin{macrocode}
+\g@addto@macro \@kernel@after@enddocument@afterlastpage {
+% \end{macrocode}
+% There is one special case: If no output is produced then there is
+% no point in a) recording the number as 0 will never match the
+% page number of a real page and b) adding an extra page to ran the
+% \hook{shipout/lastpage} is pointless as well (as it would
+% remain forever). So we test for this and run the code only if
+% there have been pages.
+% \begin{macrocode}
+ \int_compare:nNnF \g_shipout_readonly_int = 0
+ {
+% \end{macrocode}
+% This ends up in the \texttt{.aux} so we use \LaTeXe{} names here.
+% \fmi{this needs an interface for \cs{nofiles} in expl3, doesn't at the moment!}
+% \begin{macrocode}
+ \if@filesw
+ \iow_now:Nx \@auxout {
+ \gdef\string\@abspage@last {\int_use:N \g_shipout_readonly_int}}
+ \fi
+% \end{macrocode}
+% But we may have guessed wrongly earlier and we still have to run the
+% \hook{shipout/lastpage} even though there is no page to place
+% it into. If that is the case we make a trivial extra page and put
+% it there. This temporary page will then vanish again on the next
+% run but helps to keep pdf viewers happy.
+% \begin{macrocode}
+ \bool_if:NF \g_@@_lastpage_handled_bool
+ { \tex_shipout:D\vbox to\textheight{
+ \hbox{\UseHook{shipout/lastpage} \@kernel@after@shipout@lastpage }
+% \end{macrocode}
+% This extra page could be totally empty except for the hook
+% content, but to help the user understanding why it is there we
+% put some text into it.
+% \begin{macrocode}
+ \@@_excuse_extra_page:
+ \null
+ }
+% \end{macrocode}
+% At this point we should also signal to \LaTeX{} that a rerun is
+% necessary so that an appropriate message can be shown on the
+% terminal.
+%
+% \fmi{integrate warning ``Rerun \ldots'' }
+% \begin{macrocode}
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+
+
+
+% \begin{macro}{\@@_excuse_extra_page:}
+% Say mea culpa \ldots
+% \begin{macrocode}
+\cs_new:Npn \@@_excuse_extra_page: {
+ \vfil
+ \begin{center}
+ \bfseries Temporary~ page!
+ \end{center}
+ \LaTeX{}~ was~ unable~ to~ guess~ the~ total~ number~ of~ pages~
+ correctly.~ ~ As~ there~ was~ some~ unprocessed~ data~ that~
+ should~ have~ been~ added~ to~ the~ final~ page~ this~ extra~
+ page~ has~ been~ added~ to~ receive~ it.
+ \par
+ If~ you~ rerun~ the~ document~ (without~ altering~ it)~ this~
+ surplus~ page~ will~ go~ away,~ because~ \LaTeX{}~ now~ knows~
+ how~ many~ pages~ to~ expect~ for~ this~ document.
+ \vfil
+}
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+% \section{Legacy \LaTeXe{} interfaces}
+
+
+
+% \begin{macro}{\DiscardShipoutBox}
+% Request that the next shipout box is to be discarded.
+% \begin{macrocode}
+\cs_new_eq:NN \DiscardShipoutBox \shipout_discard:
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\AtBeginDvi}
+%
+% \begin{macrocode}
+\renewcommand \AtBeginDvi {\@@_add_firstpage_material:Nn \AtBeginDvi}
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\DebugShipoutOn,\DebugShipoutOff}
+%
+% \begin{macrocode}
+\cs_new_eq:NN \DebugShipoutOn \shipout_debug_on:
+\cs_new_eq:NN \DebugShipoutOff \shipout_debug_off:
+% \end{macrocode}
+% \end{macro}
+
+
+
+
+
+% \section{Package emulation for compatibility}
+
+
+% \subsection{Package \pkg{atbegshi} emulation}
+
+% \begin{macro}{\AtBeginShipoutBox}
+% \begin{macrocode}
+\cs_new_eq:NN \AtBeginShipoutBox \ShipoutBox
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\AtBeginShipoutInit}
+% Compatibility only, we aren't delaying \ldots
+% \begin{macrocode}
+\cs_set_eq:NN\AtBeginShipoutInit\@empty
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\AtBeginShipout,\AtBeginShipoutNext}
+% Filling hooks
+% \begin{macrocode}
+\newcommand\AtBeginShipout {\AddToHook{shipout/before}}
+\newcommand\AtBeginShipoutNext {\AddToHookNext{shipout/before}}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% \begin{macro}{\AtBeginShipoutFirst}
+% Slightly more complex as we need to know the name of the command under which the
+% \hook{shipout/firstpage} hook is filled.
+% \begin{macrocode}
+\newcommand\AtBeginShipoutFirst{\@@_add_firstpage_material:Nn \AtBeginShipoutFirst}
+% \end{macrocode}
+% \end{macro}
+
+
+
+% This is somewhat different from the original where
+% \cs{ShipoutBoxHeight} etc.\ only holds the \verb=\the\ht<box>= value. This
+% may has some implications in some use cases and if that is a problem
+% then it might need changing.
+%
+% \begin{macrocode}
+\cs_new:Npn \ShipoutBoxHeight { \dim_use:N \l_shipout_box_ht_dim }
+\cs_new:Npn \ShipoutBoxDepth { \dim_use:N \l_shipout_box_dp_dim }
+\cs_new:Npn \ShipoutBoxWidth { \dim_use:N \l_shipout_box_wd_dim }
+% \end{macrocode}
+
+
+% \begin{macro}{\AtBeginShipoutDiscard}
+% Just a different name.
+% \begin{macrocode}
+\cs_new_eq:NN \AtBeginShipoutDiscard \DiscardShipoutBox
+% \end{macrocode}
+% \end{macro}
+
+
+% \begin{macro}{\AtBeginShipoutAddToBox,\AtBeginShipoutAddToBoxForeground,
+% \AtBeginShipoutUpperLeft,\AtBeginShipoutUpperLeftForeground}
+% We don't expose them.
+% \begin{macrocode}
+\cs_new_eq:NN \AtBeginShipoutAddToBox \@@_add_background_box:n
+\cs_new_eq:NN \AtBeginShipoutAddToBoxForeground \@@_add_foreground_box:n
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new_eq:NN\AtBeginShipoutUpperLeft \@@_add_background_picture:n
+\cs_new_eq:NN\AtBeginShipoutUpperLeftForeground \@@_add_foreground_picture:n
+% \end{macrocode}
+% \end{macro}
+
+%
+%
+% We prevent the package \pkg{atbegshi} from loading:
+% \begin{macrocode}
+\expandafter\cs_set_eq:NN\csname ver@atbegshi.sty\endcsname\fmtversion
+% \end{macrocode}
+% \pkg{hyperref} code (and \pkg{ltxcmds}) doesn't understand 2020-10-01
+% and thinks it is before 1994, so for now \ldots
+% \begin{macrocode}
+\@namedef {ver@atbegshi.sty}{2020/10/01}
+% \end{macrocode}
+
+
+
+% \subsection{Package \pkg{everyshi} emulation}
+%
+% \begin{macro}{\EveryShipout,\AtNextShipout}
+% This package has only two public commands to simulating it is easy:
+% \begin{macrocode}
+\cs_new_eq:NN\EveryShipout\AtBeginShipout
+\cs_new_eq:NN\AtNextShipout\AtBeginShipoutNext
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\expandafter\cs_set_eq:NN\csname ver@everyshi.sty\endcsname\fmtversion
+\@namedef {ver@everyshi.sty}{2020/10/01}
+% \end{macrocode}
+
+
+
+% \subsection{Package \pkg{atenddvi} emulation}
+%
+% \begin{macro}{\AtEndDvi}
+% This package has only one public command to simulating it is easy:
+% \begin{macrocode}
+\cs_new:Npn \AtEndDvi {\AddToHook{shipout/lastpage}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macrocode}
+\expandafter\cs_set_eq:NN\csname ver@atenddvi.sty\endcsname\fmtversion
+\@namedef {ver@atenddvi.sty}{2020/10/01}
+% \end{macrocode}
+
+
+
+
+% \begin{macrocode}
+\ExplSyntaxOff
+%</2ekernel>
+% \end{macrocode}
+
+% \Finale
+%
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\endinput
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
diff --git a/Master/texmf-dist/source/latex-dev/base/ltvers.dtx b/Master/texmf-dist/source/latex-dev/base/ltvers.dtx
index dd39a67896a..ff6c9ef2445 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltvers.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltvers.dtx
@@ -115,7 +115,7 @@
{2020-10-01}
%</2ekernel|latexrelease>
%<*2ekernel>
-\def\patch@level{-6}
+\def\patch@level{-7}
% \end{macrocode}
%
% \begin{macro}{\development@branch@name}
diff --git a/Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx b/Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx
index f250b2cb193..3b82ccd7597 100644
--- a/Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx
+++ b/Master/texmf-dist/source/latex-dev/base/ltxdoc.dtx
@@ -30,7 +30,7 @@
%
%<class>\NeedsTeXFormat{LaTeX2e}
%<class>\ProvidesClass{ltxdoc}
-%<class> [2019/09/16 v2.0y Standard LaTeX documentation class]
+%<class> [2020/05/17 v2.0z Standard LaTeX documentation class]
%
%<*driver>
\documentclass{ltxdoc}
@@ -422,6 +422,8 @@
\def\partname{File}
% \end{macrocode}
%
+% \changes{v2.0z}{2020/05/17}{Support spaces \emph{within} filenames
+% (gh/218)}
% \begin{macrocode}
\newcommand*{\DocInclude}[1]{%
\relax
@@ -432,13 +434,16 @@
{\def\currentfile{#1.dtx}}%
\ifnum\@auxout=\@partaux
\@latexerr{\string\include\space cannot be nested}\@eha
- \else \@docinclude#1 \fi}
+ \else
+ \set@curr@file@trim@spaces{#1}%
+ \expandafter\@docinclude\expandafter{\@curr@file}
+ \fi}
\def\@docinclude#1 {\clearpage
-\if@filesw \immediate\write\@mainaux{\string\@input{#1.aux}}\fi
+\if@filesw \immediate\write\@mainaux{\string\@input{"#1.aux"}}\fi
\@tempswatrue\if@partsw \@tempswafalse\edef\@tempb{#1}\@for
\@tempa:=\@partlist\do{\ifx\@tempa\@tempb\@tempswatrue\fi}\fi
\if@tempswa \let\@auxout\@partaux \if@filesw
-\immediate\openout\@partaux #1.aux
+\immediate\openout\@partaux "#1.aux"
\immediate\write\@partaux{\relax}\fi
% \end{macrocode}
% We need to save (and later restore) various index-related
diff --git a/Master/texmf-dist/source/latex-dev/base/unpack.ins b/Master/texmf-dist/source/latex-dev/base/unpack.ins
index b03dd5c6b1b..ed8cb572c7d 100644
--- a/Master/texmf-dist/source/latex-dev/base/unpack.ins
+++ b/Master/texmf-dist/source/latex-dev/base/unpack.ins
@@ -123,6 +123,7 @@
\batchinput{latexrelease.ins}
+\batchinput{lthooks.ins}
\Msg{}
\Msg{*********************************************}
diff --git a/Master/texmf-dist/source/latex-dev/graphics/lscape.dtx b/Master/texmf-dist/source/latex-dev/graphics/lscape.dtx
index e14462c9d42..ac5c16d7c20 100644
--- a/Master/texmf-dist/source/latex-dev/graphics/lscape.dtx
+++ b/Master/texmf-dist/source/latex-dev/graphics/lscape.dtx
@@ -17,7 +17,7 @@
%<driver> \ProvidesFile{lscape.drv}
% \fi
% \ProvidesFile{lscape.dtx}
- [2000/10/22 v3.01 Landscape Pages (DPC)]
+ [2020/05/28 v3.02 Landscape Pages (DPC)]
%
% \iffalse
%<*driver>
@@ -61,6 +61,7 @@
% \changes{v3.00}{1994/10/05}{Update using LaTeX2e graphics package}
% \changes{v3.01}{1999/06/22}{Added better pdfTeX support
% by Scott Pakin, from graphics/3063}
+% \changes{v3.02}{2020/05/28}{delay saving \cs{@makefcolumn} gh340}
%
%
% \begin{macrocode}
@@ -90,8 +91,6 @@
% \end{macrocode}
%
% \begin{macrocode}
-\let\LS@makecol=\@makecol
-\let\LS@makefcolumn=\@makefcolumn
\def\LS@rot{%
\setbox\@outputbox\vbox{\hbox{\rotatebox{90}{\box\@outputbox}}}}
% \end{macrocode}
@@ -99,6 +98,8 @@
% First set up the page size for landscape.
% \begin{macrocode}
\def\landscape{%
+ \let\LS@makecol=\@makecol
+ \let\LS@makefcolumn=\@makefcolumn
\clearpage
\begingroup
\vsize=\textwidth
diff --git a/Master/texmf-dist/source/latex-dev/tools/array.dtx b/Master/texmf-dist/source/latex-dev/tools/array.dtx
index a84d4faf510..ff963d7f514 100644
--- a/Master/texmf-dist/source/latex-dev/tools/array.dtx
+++ b/Master/texmf-dist/source/latex-dev/tools/array.dtx
@@ -33,7 +33,7 @@
%<+package>\DeclareCurrentRelease{}{2020-10-01}
%<+package>
%<+package>\ProvidesPackage{array}
-%<+package> [2020/10/01 v2.5b Tabular extension package (FMi)]
+%<+package> [2020/10/01 v2.5c Tabular extension package (FMi)]
%
% \fi
%
@@ -552,14 +552,16 @@
% \item rules can be placed between columns or rows thereby enlarging
% the table.
% \end{enumerate}
-% \texttt{array.sty} implements the second possibility while the
-% default implementation in the \LaTeX{} kernel implements the first
-% concept. Both concepts have their merits but one has to be aware of
-% the individual implications.
+% For vertical rules \texttt{array.sty} implements the second
+% possibility while the default implementation in the \LaTeX{} kernel
+% implements the first concept.
+% Both concepts have their merits but
+% one has to be aware of the individual implications.
% \begin{itemize}
% \item
-% With standard \LaTeX{} adding rules to a table will not affect the
-% width or height of the table (unless double rules are used), e.g.,
+% With standard \LaTeX{} adding vertical rules to a table will
+% not affect the
+% width of the table (unless double rules are used), e.g.,
% changing a preamble from \verb=lll= to \verb=l|l|l= does not
% affect the document other than adding rules to the table. In
% contrast, with \texttt{array.sty} a table that just fit the
@@ -602,6 +604,12 @@
% \end{center}
% \end{itemize}
%
+% Horizontal rules produced with \cs{hline} add to the table height in
+% both implementations but they differ in handling double \cs{hline}s.
+% In contrast a \cs{cline} does not change the table
+% height.\footnote{All a bit inconsistent, but nothing that can be
+% changed after being 30+ years in existence.}
+%
% \subsection{Comparisons with older versions of \texttt{array.sty}}
%
% There are some differences in the way version 2.1 treats incorrect
@@ -731,7 +739,11 @@
\NeedsTeXFormat{LaTeX2e}[1995/12/01]
\documentclass{ltxdoc}
-\AtBeginDocument{\DeleteShortVerb{\|}} % undo the default is not used
+% undo the default is not used:
+
+\IfFormatAtLeastTF {2020/10/01}
+ {\AtBeginDocument[ltxdoc]{\DeleteShortVerb{\|}} }
+ {\AtBeginDocument{\DeleteShortVerb{\|}} }
\usepackage{array}
@@ -747,6 +759,7 @@
%\OnlyDescription % comment out for implementation details
%\OldMakeindex % use if your MakeIndex is pre-v2.9
+
\begin{document}
\DocInput{array.dtx}
\end{document}
@@ -2210,7 +2223,7 @@
% \cs{@yargarraycr} is the same as in the \LaTeX{} kernel
% (depending on the date of the kernel with one of the two
% definitions below). We therefore do not define it again.
-% \changes{v2.5b}{200/04/22}{Don't define \cs{@yargarraycr} unnecessarily}
+% \changes{v2.5b}{2020/04/22}{Don't define \cs{@yargarraycr} unnecessarily}
% \begin{macrocode}
%\def\@yargarraycr#1{\cr\noalign{\@vspace@calcify{#1}}} % 2020-10-01
%\def\@yargarraycr#1{\cr\noalign{\vskip #1}}
@@ -2922,10 +2935,13 @@
%
% We start by producing a single tabular row without any visible
% content that will produce the external reference point in case
-% "[t]" is used.
+% "[t]" is used. We need to suppress the \cs{tabcolsep} in the
+% \cs{multicolumn} in case there wasn't any in the real column.
+%
+% \changes{v2.5c}{2020/07/20}{Suppress all column space (gh/322)}
% \begin{macrocode}
\newcommand{\firsthline}{%
- \multicolumn1c{%
+ \multicolumn1{@{}c@{}}{%
% \end{macrocode}
% Within this row we calculate "\backup@length" to be the height
% plus depth of a standard line. In addition we have to add the
@@ -2942,6 +2958,10 @@
% \begin{macrocode}
\raise\extratabsurround\copy\@arstrutbox
% \end{macrocode}
+% And we should also cancel the guard otherwise we end up with two.
+% \begin{macrocode}
+ \kern-1sp%
+% \end{macrocode}
% Having done all this we end the line and back up by the value of
% "\backup@length" and then finally place our "\hline". This should
% place the line exactly at the right place but keep the reference
@@ -2963,9 +2983,12 @@
% depth of this last line increased by "\extratabsurround" without
% changing the placement "\hline".
%
-% We start by placing the rule followed by an invisible row.
+% We start by placing the rule followed by an invisible row. We
+% need to suppress the \cs{tabcolsep} in the multicol in case there
+% wasn't any in the real column.
+% \changes{v2.5c}{2020/07/20}{Suppress all column space (gh/322)}
% \begin{macrocode}
-\newcommand{\lasthline}{\hline\multicolumn1c{%
+\newcommand{\lasthline}{\hline\multicolumn1{@{}c@{}}{%
% \end{macrocode}
% We now calculate "\backup@length" to be the height and depth of
% two lines plus the width of the rule.
@@ -2983,8 +3006,9 @@
% reference for the whole tabular). Since this row is invisible we
% can enlarge its depth by the desired amount.
% \begin{macrocode}
- \multicolumn1c{%
+ \multicolumn1{@{}c@{}}{%
\lower\extratabsurround\copy\@arstrutbox
+ \kern-1sp%
}%
}
% \end{macrocode}
diff --git a/Master/texmf-dist/source/latex-dev/tools/varioref.dtx b/Master/texmf-dist/source/latex-dev/tools/varioref.dtx
index 077103eb97a..06af00bc282 100644
--- a/Master/texmf-dist/source/latex-dev/tools/varioref.dtx
+++ b/Master/texmf-dist/source/latex-dev/tools/varioref.dtx
@@ -40,7 +40,7 @@
%<package>\DeclareCurrentRelease{}{2019-10-01}
%<package>
%<package>\ProvidesPackage{varioref}
-%<package> [2020/01/23 v1.6c package for extended references (FMi)]
+%<package> [2020/07/20 v1.6d package for extended references (FMi)]
% \fi
%
%%
@@ -230,6 +230,11 @@
% The optional argument the command may take is the text to use in case
% both labels are placed on the current page.
%
+% In some languages (currently only for Japanese) the generated text
+% has to typeset the page range first and the reference range
+% afterwards. To accomodate for this \cs{vrefrangeformat} has been
+% added to allow to alter this on a per language basis.
+%
%
% \DescribeMacro\vpagerefrange This command is similar to |\vpageref|
% but takes two mandatory arguments which are two labels denoting a
@@ -708,6 +713,7 @@
\def\reftextfaraway#1{op bladsy~\pageref{#1}}%
\def\reftextpagerange#1#2{op bladsye~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} tot~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
%
@@ -723,6 +729,7 @@
\def\reftextfaraway#1{on page~\pageref{#1}}%
\def\reftextpagerange#1#2{on pages~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} to~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Arabic option text was contributed by Ihab Samir Mattar
@@ -743,6 +750,7 @@
\def\reftextfaraway#1{بالصفحة رقم~\pageref{#1}}%
\def\reftextpagerange#1#2{بالصفحات~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} حتى~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% \end{allowtofu}
@@ -759,6 +767,7 @@
\def\reftextfaraway#1{auf Seite~\pageref{#1}}%
\def\reftextpagerange#1#2{auf Seiten~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} bis~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% \changes{v1.2d}{2000/01/11}{Added naustrian defaults (identical to german)}
@@ -774,6 +783,7 @@
\def\reftextfaraway#1{auf Seite~\pageref{#1}}%
\def\reftextpagerange#1#2{auf Seiten~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} bis~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Text for basque defaults was contributed by
@@ -791,6 +801,7 @@
\def\reftextfaraway#1{~\pageref{#1}. orrialdean}%
\def\reftextpagerange#1#2{~\pageref{#1}--\pageref{#2} orrialdeetan}%
\def\reftextlabelrange#1#2{\ref{#1}.etik \ref{#2}.eraino}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Text for the Bahasa Malaysia defaults was contributed by
@@ -815,6 +826,7 @@
\def\reftextfaraway#1{pada muka surat~\pageref{#1}}%
\def\reftextpagerange#1#2{pada muka surat~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1}--\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Text for brazil defaults was contributed by
@@ -837,6 +849,7 @@
\def\reftextfaraway#1{na p\'agina~\pageref{#1}}%
\def\reftextpagerange#1#2{nas p\'aginas~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} a~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Text for Breton defaults was contributed by
@@ -858,6 +871,7 @@
on pages~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\vref@stringwarning\reflabelpagerange
\ref{#1} to~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Text for Bulgarian defaults was contributed by
@@ -892,6 +906,7 @@
\cyrs\cyrt\cyrr\cyra\cyrn\cyri\cyrc\cyri
~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} \cyrd\cyro~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Text for catalan defaults was contributed by Robert Fuster\\
@@ -910,6 +925,7 @@
\def\reftextpagerange#1#2{a les
p\`agines~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} a~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Text for croatian defaults was contributed by \v{S}ime Ungar
@@ -926,6 +942,7 @@
\def\reftextfaraway#1{na stranici~\pageref{#1}}%
\def\reftextpagerange#1#2{na stranicama~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} do~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Defaults for the Czech option provided by Milan Vancura
@@ -943,6 +960,7 @@
\def\reftextfaraway#1{na stran\v{e}~\pageref{#1}}%
\def\reftextpagerange#1#2{na stran\'ach~\pageref{#1}\--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} a\v{z}~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Defaults for Danish provided by Torsten Martinsen
@@ -965,6 +983,7 @@
\def\reftextfaraway#1{p\aa{} side~\pageref{#1}}%
\def\reftextpagerange#1#2{p\aa{} side~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} til~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Default string for dutch have been contributed by Frank Poppe
@@ -1004,6 +1023,7 @@
% \begin{macrocode}
\def\reftextpagerange#1#2{op pagina's~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1}--\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% \changes{v1.2a}{1998/08/22}{Added english defaults for
@@ -1021,6 +1041,7 @@
\def\reftextfaraway#1{on page~\pageref{#1}}%
\def\reftextpagerange#1#2{on pages~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} to~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
%
@@ -1041,6 +1062,7 @@
\def\reftextfaraway#1{en pa\^go~\pageref{#1}}%
\def\reftextpagerange#1#2{en pa\^goj~\pageref{#1} \^gis \pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} \^gis~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% The finnish strings were suggested by Matti Rintala
@@ -1064,6 +1086,7 @@
% Can't combine numbers with the necessary suffix well.
% \begin{macrocode}
\def\reftextlabelrange#1#2{\ref{#1}--\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% French defaults are provided by Daniel Flippo
@@ -1083,6 +1106,7 @@
\def\reftextfaraway#1{page~\pageref{#1}}%
\def\reftextpagerange#1#2{pages~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} \`a~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Galician defaults are provided by Matthias Moebius\\
@@ -1104,6 +1128,7 @@
\def\reftextpagerange#1#2{%
nas p\'axinas~\pageref{#1}-\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} a~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% There are no good variants for German (I think and still think but
@@ -1138,6 +1163,7 @@
\def\reftextfaraway#1{auf Seite~\pageref{#1}}%
\def\reftextpagerange#1#2{auf den Seiten~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} bis~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% \changes{v1.2d}{2000/01/11}{Added ngerman defaults (identical to german)}
@@ -1155,6 +1181,7 @@
\def\reftextfaraway#1{auf Seite~\pageref{#1}}%
\def\reftextpagerange#1#2{auf den Seiten~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} bis~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Defaults for greek suggested by Apostolos Syropoulos\\
@@ -1174,6 +1201,7 @@
\def\reftextpagerange#1#2{stis sel'ides\nobreakspace
\pageref{#1}---\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} ws\nobreakspace\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Icelandic defaults suggested by Thorhallur Sverrisson
@@ -1194,6 +1222,7 @@
\def\reftextfaraway#1{\'{a} s\'{i}{\dh}u~\pageref{#1}}%
\def\reftextpagerange#1#2{\'{a} s\'{i}{\dh}um~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} til~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Defaults for Italian suggested by Giovanni Pensa
@@ -1218,8 +1247,32 @@
\def\reftextfaraway#1{a pagina~\pageref{#1}}%
\def\reftextpagerange#1#2{nelle pagine~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{da~\ref{#1} a~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
+ }}
+% \end{macrocode}
+% Defaults for Japanese. It needs a special \cs{vrefrangeformat}
+% for gramatical reasons. As our standard documentation
+% workflow uses pdf\TeX{} the Japanese letters can't be displayed
+% easily, so you will see missing glyphs below. To see the real
+% letters you have to look at the source or package file.
+% \changes{v1.6d}{2020/07/20}{Option japanese added (gh/352)}
+% \begin{allowtofu}
+% \begin{macrocode}
+\DeclareOption{japanese}
+ {\vref@addto\extrasjapanese{%
+ \def\reftextfaceafter {\reftextvario{見開き}{次}頁}%
+ \def\reftextfacebefore{\reftextvario{見開き}{前}頁}%
+ \def\reftextafter {\reftextvario{直後の}{次}頁}%
+ \def\reftextbefore {\reftextvario{直前の}{前}頁}%
+ \def\reftextcurrent {\reftextvario{この}{現}頁}%
+ \def\reftextfaraway#1{\pageref{#1}頁}%
+ \def\reftextpagerange#1#2{\pageref{#1}頁から\pageref{#2}頁}%
+ \def\reftextlabelrange#1#2{\ref{#1}から\ref{#2}}%
+ \def\vrefrangeformat#1#2#3{\vpagerefrange[{#1}]{#2}{#3}の%
+ \reftextlabelrange{#2}{#3}}%
}}
% \end{macrocode}
+% \end{allowtofu}
% Defaults for Hungarian by Jeff Goldberg
% (\verb=jeffrey@goldmark.org=).
% There is a problem with the use of the definite article
@@ -1264,6 +1317,7 @@
on pages~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\vref@stringwarning\reflabelpagerange
\ref{#1} to~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}%
% \end{macrocode}
% The |\AtBeginDocument| needs to be executed when the option is
@@ -1304,6 +1358,7 @@
\def\reftextfaraway#1{p\aa{} side~\pageref{#1}}%
\def\reftextpagerange#1#2{p\aa{} side~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} til~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
\DeclareOption{nynorsk}
{\vref@addto\extrasnynorsk{%
@@ -1315,6 +1370,7 @@
\def\reftextfaraway#1{p\aa{} side~\pageref{#1}}%
\def\reftextpagerange#1#2{p\aa{} side~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} til~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% The polish translations have been provided by
@@ -1342,6 +1398,7 @@
\def\reftextfaraway#1{na stronie~\pageref{#1}}%
\def\reftextpagerange#1#2{na stronach~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{od~\ref{#1} do~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% The portuguese default text has been provided by
@@ -1362,6 +1419,7 @@
\def\reftextfaraway#1{na p\'agina~\pageref{#1}}%
\def\reftextpagerange#1#2{nas p\'aginas~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} a~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Updates to the default text for Romanian have been suggested by Florin Oprina
@@ -1381,6 +1439,7 @@
\def\reftextfaraway#1{pe pagina~\pageref{#1}}%
\def\reftextpagerange#1#2{pe paginile~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} la~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% The text for russian was taken from the book in Russian by
@@ -1414,6 +1473,7 @@
\def\reftextpagerange#1#2{\cyrn\cyra\ \cyrs\cyrt\cyrr\cyra\cyrn
\cyri\cyrc\cyra\cyrh~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\cyrs~\ref{#1}\ \cyrp\cyro~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% The text for slovak defaults was contributed by Miroslav Sedivy\\
@@ -1434,6 +1494,7 @@
\def\reftextfaraway#1{na strane~\pageref{#1}}%
\def\reftextpagerange#1#2{na stran\'ach~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} a\v z~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% The text for slovene defaults was contributed by Roman Maurer\\
@@ -1450,6 +1511,7 @@
\def\reftextfaraway#1{na strani~\pageref{#1}}%
\def\reftextpagerange#1#2{na straneh~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{od~\ref{#1} do~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% Text for spanish defaults was contributed by Julio Sanchez
@@ -1470,6 +1532,7 @@
\def\reftextpagerange#1#2{en las p\'aginas~\pageref{#1}%
-\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} a~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% The text for swedish was contributed by Mats Dahlgren
@@ -1492,6 +1555,7 @@
\def\reftextpagerange#1#2{p\aa\
sidorna~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} till~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
\DeclareOption{turkish}
{\vref@excuse{turkish}%
@@ -1505,6 +1569,7 @@
\def\reftextfaraway#1{on page~\pageref{#1}}%
\def\reftextpagerange#1#2{on pages~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\ref{#1} to~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% The text for Ukrainian defaults was contributed by Mykola Lyakhovych\\
@@ -1532,6 +1597,7 @@
\def\reftextpagerange#1#2{\cyrn\cyra\ \cyrs\cyrt\cyro\cyrr\cyrii
\cyrn\cyrk\cyra\cyrh~\pageref{#1}--\pageref{#2}}%
\def\reftextlabelrange#1#2{\cyrz~\ref{#1}\ \cyrd\cyro~\ref{#2}}%
+ \let\vrefrangeformat\vrefrangedefaultformat
}}
% \end{macrocode}
% We support francais as an alternative to french since people
@@ -2286,13 +2352,28 @@
% \changes{v1.2a}{1998/08/01}{Macro added}
% \changes{v1.4s}{2006/08/07}
% {Prevent loss of brackets}
+% \changes{v1.6d}{2020/07/20}{Changed for Japanese (gh/352)}
+% Argument two and three are implicitly picked up.
% \begin{macrocode}
-\newcommand\vrefrange[3][\reftextcurrent]
- {\reftextlabelrange{#2}{#3} \vpagerefrange[{#1}]{#2}{#3}}
+\newcommand\vrefrange[1][\reftextcurrent]{\vrefrangeformat{#1}}
% \end{macrocode}
+%
% \end{macro}
%
%
+% \begin{macro}{\vrefrangeformat,\vrefrangedefaultformat}
+% Japanese needs a different word order in \cs{vrefrange} so this
+% is separated out o that it can be changed on language level.
+% \changes{v1.6d}{2020/07/20}{Macro added (gh/352)}
+% \begin{macrocode}
+\def\vrefrangedefaultformat#1#2#3{%
+ \reftextlabelrange{#2}{#3} \vpagerefrange[{#1}]{#2}{#3}}
+% \end{macrocode}
+% Most languages need the above definition.
+% \begin{macrocode}
+\let\vrefrangeformat\vrefrangedefaultformat
+% \end{macrocode}
+% \end{macro}
%
% \begin{macro}{\Vref}
% \changes{v1.4a}{2002/02/24}{Macro added}
diff --git a/Master/texmf-dist/source/latex-dev/tools/verbatim.dtx b/Master/texmf-dist/source/latex-dev/tools/verbatim.dtx
index 121e2d4b39c..e62886e0033 100644
--- a/Master/texmf-dist/source/latex-dev/tools/verbatim.dtx
+++ b/Master/texmf-dist/source/latex-dev/tools/verbatim.dtx
@@ -69,6 +69,8 @@
%\fi
%
%
+% \changes{v1.5u}{2020-07-07}{Typo repair and added a missing comment
+% character}
% \changes{v1.5q}{2003/08/22}{Reintroduced \cs{@noligs}, by popular
% request.}
% \changes{v1.5i}{1996/06/04}{Move setting of verbatim font and
@@ -462,9 +464,12 @@
% the spacing.
% Then we open the file and set the category codes of all special
% characters:
+% \changes{v1.5t}{2020-07-05}{Added quotes around the filename in
+% order to allow a filename with spaces; also added a space and
+% comment-character to allow for thespace dlimited argument.}
% \begin{verbatim}
% \@bsphack
-% \immediate\openout \verbatim@out #1
+% \immediate\openout \verbatim@out "#1" %
% \let\do\@makeother\dospecials
% \catcode`\^^M\active
%\end{verbatim}
@@ -503,7 +508,7 @@
%<*package>
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{verbatim}
- [2019/11/10 v1.5r LaTeX2e package for verbatim enhancements]
+ [2020-07-07 v1.5u LaTeX2e package for verbatim enhancements]
\@ifundefined{verbatim@@@}{}{\endinput}
% \end{macrocode}
%
@@ -1567,19 +1572,31 @@
% existence of file.}
% |\verbatim@input| first checks whether the file exists, using
% the standard macro |\IfFileExists| which leaves the name of the
-% file found in |\@filef@und|.
-% Then everything is set up as in the |\verbatim| macro.
+% file found in |\@filef@und|.
+% Then everything is set up as in the |\verbatim| macro. But, as
+% |\@verbatim| contains a call to |\every@verbatim| which
+% \emph{might} contain an |\input| statement, which would overwrite
+% the contents of |\@filef@und|, we need to save it by expanding it
+% first. The use of |\@swaptwoargs| makes it so that the
+% \emph{expansion} of |\@filef@und| gets to be the second argument
+% of |\verbatim@readfile|.
+% \changes{v1.5t}{2020-07-06}{Expand \cs{@filef@und} before the call
+% of \cs{@verbatim} (gh/222)}m
% \begin{macrocode}
\def\verbatim@input#1#2{%
- \IfFileExists {#2}{\@verbatim #1\relax
+ \IfFileExists {#2}{%
+ \expandafter\@swaptwoargs\expandafter
+ {\expandafter{\@filef@und}}%
+ {\@verbatim #1\relax
% \end{macrocode}
% Then it reads in the file, finishes off the \texttt{trivlist}
% environment started by |\@verbatim| and closes the group.
% This restores everything to its normal settings.
% \begin{macrocode}
- \verbatim@readfile{\@filef@und}\endtrivlist\endgroup\@doendpe}%
+ \verbatim@readfile}%
+ \endtrivlist\endgroup\@doendpe}%
% \end{macrocode}
-% If the file is not found a more or less helpful message is
+% If the file is not found a more or less helpful message is
% printed. The final |\endgroup| is needed to close the group
% started in |\verbatiminput| above.
% \begin{macrocode}