diff options
Diffstat (limited to 'macros/latex/contrib/koma-script/source/scrlfile-hook.dtx')
-rw-r--r-- | macros/latex/contrib/koma-script/source/scrlfile-hook.dtx | 634 |
1 files changed, 634 insertions, 0 deletions
diff --git a/macros/latex/contrib/koma-script/source/scrlfile-hook.dtx b/macros/latex/contrib/koma-script/source/scrlfile-hook.dtx new file mode 100644 index 0000000000..1f944139be --- /dev/null +++ b/macros/latex/contrib/koma-script/source/scrlfile-hook.dtx @@ -0,0 +1,634 @@ +% \iffalse^^A meta-comment +% ====================================================================== +% scrlfile-hook.dtx +% Copyright (c) Markus Kohm, 2020 +% +% This file is part of the work `scrlfile' which is part of the LaTeX2e +% KOMA-Script bundle. +% +% This work may be distributed and/or modified under the conditions of +% the LaTeX Project Public License, version 1.3c of the license. +% 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 and of this work. +% +% This work has the LPPL maintenance status "author-maintained". +% +% The Current Maintainer and author of this work is Markus Kohm. +% +% This work consists of all files listed in manifest.txt. +% ---------------------------------------------------------------------- +% scrlfile-hook.dtx +% Copyright (c) Markus Kohm, 2020 +% +% Diese Datei ist Teil des Werks `scrlfile', das wiederum Teil des +% LaTeX2e KOMA-Script Pakets ist. +% +% Dieses Werk darf nach den Bedingungen der LaTeX Project Public Lizenz, +% Version 1.3c, verteilt und/oder veraendert werden. +% Die neuste Version dieser Lizenz ist +% http://www.latex-project.org/lppl.txt +% und Version 1.3c ist Teil aller Verteilungen von LaTeX +% Version 2005/12/01 oder spaeter und dieses Werks. +% +% Dieses Werk hat den LPPL-Verwaltungs-Status "author-maintained" +% (allein durch den Autor verwaltet). +% +% Der Aktuelle Verwalter und Autor dieses Werkes ist Markus Kohm. +% +% +% Dieses Werk besteht aus den in manifest.txt aufgeführten Dateien. +% ====================================================================== +% +%%% From File: $Id: scrlfile-hook.dtx$ +%<*dtx> +\ifx\ProvidesFile\undefined\def\ProvidesFile#1[#2]{}\fi +\begingroup + \def\filedate$#1: #2-#3-#4 #5${\gdef\filedate{#2/#3/#4}} + \filedate$Date: 2020-09-17 14:01:13 +0200 (Thu, 17 Sep 2020) $ + \def\filerevision$#1: #2 ${\gdef\filerevision{r#2}} + \filerevision$Revision: 3544 $ + \edef\reserved@a{% + \noexpand\endgroup + \noexpand\ProvidesFile{scrlfile-hook.dtx}% + [\filedate\space\filerevision\space + KOMA-Script package source + }% +\reserved@a +%</dtx> +%<package>\ProvidesPackage{scrlfile-hook}[% +%!KOMAScriptVersion +%<package> package + (using LaTeX hooks)] +%<*dtx> +\ifx\documentclass\undefined + \input scrdocstrip.tex + \@@input scrkernel-version.dtx + \@@input scrstrip.inc + \KOMAdefVariable{COPYRIGHTFROM}{2002} + \generate{\usepreamble\defaultpreamble + \file{scrlfile-hook.sty}{% + \from{scrlfile-hook.dtx}{package}% + }% + }% + \@@input scrstrop.inc +\else + \let\endbatchfile\relax +\fi +\endbatchfile +\documentclass{l3doc} +\usepackage[english]{babel} +\DeclareRobustCommand{\KOMAScript}{\textsf{K\kern.05em O\kern.05em% + M\kern.05em A\kern.1em-\kern.1em Script}} +\CodelineIndex +\GetFileInfo{scrlfile-hook.dtx} +\title{\KOMAScript{} \partname\ \texttt{\filename}% + \thanks{This file is revision \fileversion\ of file \texttt{\filename}.}} +\date{\filedate} +\author{Markus Kohm\thanks{mailto:komascript@gmx.info}} + +\begin{document} + \maketitle + \begin{abstract} + This package provides hooks before and after loading files, packages or + classes. It also provides a hook after the last \cs{clearpage} of the + document. It allowes to replace files, packages and classes by other + files, packages and classes. It is inteded to be used by package and class + authors but may also be used by \LaTeX{} users. + \end{abstract} + + \tableofcontents + + \DocInput{\filename} +\end{document} +%</dtx> +% \fi^^A meta-comment +% +% \changes{v3.32}{2020/08/25}{new (sub-)package} +%^^A TODO: We should use docstrip3 instead of of docstrip. This would enable +%^^A usability of @@-syntax in the source. But for this, additional +%^^A changes would be needed to setup the version string. Because of +%^^A this it should be done together with switch over to l3build. +% +% \section{The User Manual of \textsf{scrlfile-hook}} +% +% \textsf{scrlfile-hook} implements the \LaTeX-hook-based part of +% \textsf{scrlfile}. +% +% There isn't any user manual for the user level \LaTeXe{} commands in this +% file. Please see the manual of \textsf{scrlfile} for more information about +% \textsf{scrlfile-hook}. +% +% This section, however, contains the user manual of the \LaTeX3{} package +% author commands. +% +% \begin{function}[TF, added = 2020-08-26] +% {\scrlfile_if_class_loaded:n,\scrlfile_if_package_loaded:n} +% \begin{syntax} +% \cs{scrlfile_if_class_loaded:nTF} \Arg{class name} \Arg{true code} \Arg{false code} +% \cs{scrlfile_if_package_loaded:nTF} \Arg{package name} \Arg{true code} \Arg{false code} +% \end{syntax} +% Tests if the class \meta{class name} resp. the package \meta{package name} +% has been loaded completely. It runs the \Arg{true code} only, if the input +% of the class file with the name \meta{class +% name}\texttt{.}\cs{@clsextension} resp. the package file with the name +% \meta{package name}\texttt{.}\cs{@pkgextension} has already been +% finished. It runs the \Arg{false code}, if the class or package has not +% been loaded or the input of the class or package file is still in +% progress. +% \end{function} +% +% +% \StopEventually{\PrintIndex} +% +% \section{The Implementation of \textsf{scrlfile-hook}} +% +% \begin{macrocode} +%<@@=scrlfile> +% \end{macrocode} +% +% Test whether the uses \LaTeX{} provides all commands we need. +% \begin{macrocode} +\@ifundefined{AddToHook}{% + \PackageError{scrlfile-hook}{LaTeX too old for this package}{% + \string\AddToHook\space of LaTeX 2020-10-01 or newer is + needed.\MessageBreak + Please update LaTeX or use package scrlfile-patch instead of\MessageBreak + scrlfile-hook.\MessageBreak + If you would continue, I will try to load scrlfile-patch + }% + \RequirePackage{scrlfile-patch}% + \endinput +}{} +% \end{macrocode} +% +% +% \subsection{Before and After Commands} +% +% The hook implementation is based on a \LaTeX{} version that provides +% \LaTeX3. So it makes sense to use it. +% +% \begin{macrocode} +\ExplSyntaxOn +% \end{macrocode} +% +% \begin{macro}{\BeforeFile} +% The hook version of this command is just a wrapper to the corresponding +% \LaTeX{} file hooks. It supports a mandatory \meta{file} argument, an +% optional \meta{label} argument and a mandatory \meta{hook code} argument. +% \begin{macrocode} +\NewDocumentCommand \BeforeFile { m } + { + \AddToHook { file / before / #1 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\AfterFile} +% The hook version of this command is just a wrapper to the corresponding +% \LaTeX{} file hooks. It supports a mandatory \meta{file} argument, an +% optional \meta{label} argument and a mandatory \meta{hook code} argument. +% \begin{macrocode} +\NewDocumentCommand \AfterFile { m } + { + \AddToHook { file / after / #1 } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\BeforeClass,\BeforePackage} +% The hook version of these commands are also wrappers to the +% \texttt{file/before} hooks, because the \meta{code} should also be executed +% already in the class or package context. +% \begin{macrocode} +\NewDocumentCommand \BeforeClass { m } + { + \BeforeFile { #1.\@clsextension } + } +\NewDocumentCommand \BeforePackage { m } + { + \BeforeFile { #1.\@pkgextension } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\AfterAtEndOfClass,\AfterAtEndOfPackage} +% With version 3.32 the syntax of these commands have been changed. Now, there +% is also a star variant, that runs the \meta{code} immediately if the class +% or package has already been loaded completely. Otherwise and in the normal +% variant the \meta{code} is added to the \texttt{class/after} or +% \texttt{package/after} hook, because this hook is used outside the context +% of the class or package and after the \cs{AtEndOfClass} or +% \cs{AtEndOfPackage} code. +% \begin{macrocode} +\NewDocumentCommand \AfterAtEndOfClass { s m o +m } + { + \IfBooleanTF { #1 } + { + \scrlfile_if_class_loaded:nTF { #2 } + { #4 } + { \hook_gput_code:nnn { class / after / #2 } { #3 } { #4 } } + } + { \hook_gput_code:nnn { class / after / #2 } { #3 } { #4 } } + } +\NewDocumentCommand \AfterAtEndOfPackage { s m o +m } + { + \IfBooleanTF { #1 } + { + \scrlfile_if_package_loaded:nTF { #2 } + { #4 } + { \hook_gput_code:nnn { package / after / #2 } { #3 } { #4 } } + } + { \hook_gput_code:nnn { package / after / #2} { #3 } { #4 } } + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}[added = 2020-06-26]{\g__scrlfile_input_file_seq} +% \cs{g__scrlfile_input_file_seq} is a sequence of active file inputs (without +% path information). Two global hooks are used to setup the sequence. The new +% conditional tests if a file is in the sequence. +% \begin{macrocode} +\seq_new:N \g__scrlfile_input_file_seq +\hook_gput_code:nnn { file / before } { . } + { \seq_gpush:Nx \g__scrlfile_input_file_seq { \CurrentFile } } +\hook_gput_code:nnn { file / after } { . } + { + \seq_gpop:NNF \g__scrlfile_input_file_seq \l_tmpa_seq + { + \msg_new:nnn { scrlfile-hook } { to-much-pops } + { + More~file~names~popped~from~stack~than~put~to.~ + This~should~never~happen.~ + However,~it~could~happen~if~scrlfile-hook~is~loaded~by~another~ + package~or~class.~In~this~case~some~packages~or~classes~are~not~ + recognised~correctly. + } + \msg_warning:nn { scrlfile-hook } { to-much-pops } + } + } +% \end{macrocode} +% Unfortunately we need an ugly hack to initialise the stack using an internal +% kernel variable. This is a no go but I do not know a better solution for +% this, because loading of the package could be done late. +% TODO: Decide, if the second or fourth token is correct. If fourth, +% \cs{CurrentFile} has to be used always instead of +% \cs{CurrentFileUsed}. +% \begin{macrocode} +\cs_if_exist:NTF \g__filehook_input_file_seq + { + \seq_map_inline:Nn \g__filehook_input_file_seq + { + \seq_gput_right:Nx \g__scrlfile_input_file_seq + { \tl_item:nn { #1 } { 2 } } + } + } + { + \seq_gpush:Nx \g__scrlfile_input_file_seq { } + \cs_if_exist:NTF \CurrentFileUsed + { \seq_gpush:Nx \g__scrlfile_input_file_seq { \CurrentFileUsed } } + { \seq_gpush:Nx \g__scrlfile_input_file_seq { \CurrentFile } } + } +% \end{macrocode} +% \end{variable} +% \begin{function}[TF, added = 2020-06-26]{\@@_if_loading:n} +% Test if the file name is in the file name list. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \__scrlfile_if_loading:n #1 { T, F, TF } + { + \str_set:Nx \l_tmpa_str { #1 } + \seq_if_in:NxTF \g__scrlfile_input_file_seq { \str_use:N \l_tmpa_str } + { \prg_return_true: } + { \prg_return_false: } + } +% \end{macrocode} +% \end{function} +% +% \begin{function}[TF, added = 2020/08/22] +% {\scrlfile_if_class_loaded:n,\scrlfile_if_package_loaded:n} +% \cs{scrlfile_if_class_loaded:nTF} is similar to \cs{@ifclassloaded} and +% \cs{scrlfile_if_package_loaded:nTF} is similar to \cs{@ifpackageloaded} but in +% opposite to those they test, if the class or package has been loaded +% completely. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \scrlfile_if_class_loaded:n #1 { T, F, TF } + { + \@ifclassloaded { #1 } + { + \__scrlfile_if_loading:nTF { #1.\@clsextension } + { \prg_return_false: } + { \prg_return_true: } + } + { + \prg_return_false: + } + } +\prg_new_protected_conditional:Npnn \scrlfile_if_package_loaded:n #1 { T, F, TF } + { + \@ifpackageloaded { #1 } + { + \__scrlfile_if_loading:nTF { #1.\@pkgextension } + { \prg_return_false: } + { \prg_return_true: } + } + { + \prg_return_false: + } + } +% \end{macrocode} +% \end{function} +% +% \begin{macro}{\AfterClass,\AfterPackage} +% With version 3.32 these do not support plus or exclamation mark variants, +% but only the normal and the star variants. Instead of the plus or +% exclamation mark variants users should use the star variant of +% \cs{AfterAtEndOfClass} and \cs{AfterAtEndOfPackage}. The commands use the +% \texttt{file/after} hook, because the user manual declares, that \meta{code} +% is used before the code of \cs{AtEndOfClass} or \cs{AtEndOfPackage}. +% \begin{macrocode} +\NewDocumentCommand \scrlfile@AfterClass { s m o +m } + { + \IfBooleanTF { #1 } + { + \@ifclassloaded{ #2 } + { #4 } + { + \hook_gput_code:nnn + { file / after / #2.\@clsextension } + { #3 } + { #4 } + } + } + { + \hook_gput_code:nnn { file / after / #2.\@clsextension } { #3 } { #4 } + } + } +\NewDocumentCommand \AfterClass { } { \scrlfile@AfterClass } +\NewDocumentCommand \scrlfile@AfterPackage { s m o +m } + { + \IfBooleanTF { #1 } + { + \@ifpackageloaded{ #2 } + { #4 } + { + \hook_gput_code:nnn + { file / after / #2.\@pkgextension } + { #3 } + { #4 } + } + } + { + \hook_gput_code:nnn { file / after / #2.\@pkgextension } { #3 } { #4 } + } + } +\NewDocumentCommand \AfterPackage { } { \scrlfile@AfterPackage } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{File Substitution} +% +% With new file hooks the substitutions are so easy we even do not need +% \LaTeX3 syntax to implement them. +% +% \begin{macro}{\ReplaceInput} +% This is only the simplest wrapper to \cs{declare@file@substitution}. +% \begin{macrocode} +\NewDocumentCommand{\ReplaceInput}{}{\declare@file@substitution} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ReplaceClass} +% \begin{macro}{\ReplacePackage} +% These are also wrappers to \cs{declare@file@substitution}. But in this case +% we also have to add the extension. +% \begin{macrocode} +\NewDocumentCommand\ReplaceClass{mm}{% + \declare@file@substitution{#1.\@clsextension}{#2.\@clsextension}% +} +\NewDocumentCommand\ReplacePackage{mm}{% + \declare@file@substitution{#1.\@pkgextension}{#2.\@pkgextension}% +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\UnReplaceInput} +% This is the simplest wrapper to \cs{undeclare@file@substitution}. +% \begin{macrocode} +\NewDocumentCommand{\UnReplaceInput}{}{\undeclare@file@substitution} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\UnReplaceClass} +% \begin{macro}{\UnReplacePackage} +% Also very simple but again we have to add the extension. +% \begin{macrocode} +\NewDocumentCommand\UnReplaceClass{m}{% + \undeclare@file@substitution{#1.\@clsextension}% +} +\NewDocumentCommand\UnReplacePackage{mm}{% + \undeclare@file@substitution{#1.\@pkgextension}% +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Prevent Package from Loading} +% +% To store and reset the hole list of prevents we use a comma separated +% list. So we need again use \LaTeX3. +% +% \begin{variable}[added = 2020-09-02]{\g__scrlfile_prevents_clist} +% This local variable stores the list of files, that should be prevented from +% loading. It is needed to stay compatible with old \file{scrlfile}. Without +% this compatibility purpose we would be able to use simple wrappers to +% \cs{disable@package@load} and \cs{reenable@package@load}. +% \begin{macrocode} +\clist_new:N \g__scrlfile_prevent_clist +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\PreventPackageFromLoading} +% This is more than a wrapper to \cs{disable@package@load} because we have to +% manage an internal list and it is documented, that the re-enabling does not +% undefine the \meta{alternate-code} setting but only disables it. So we have +% to extra store it. Note: Local loading of packages does not make sense, so +% local changes of the prevent list also does not make sense. Therefore this +% is a global acting command! +% \begin{macrocode} +\NewDocumentCommand \PreventPackageFromLoading { s +o m } + { + \clist_set:Nx \l__scrlfile_package_clist { #3 } + \clist_map_inline:Nn \l__scrlfile_package_clist + { + \@ifpackageloaded { ##1 } + { + \IfBooleanTF { #1 } { \msg_info:nnn } { \msg_warning:nnn } + { scrlfile } { no-prevent-for-already-loaded } { ##1 } + } + { + \clist_if_in:NnF \g__scrlfile_prevent_clist { ##1 } + { \clist_gput_right:Nn \g__scrlfile_prevent_clist { ##1 } } + \tl_if_exist:cF { g__scrlfile_exclude_package_##1_tl } + { + \tl_new:c { g__scrlfile_exclude_package_##1_tl } + } + \IfValueT { #2 } + { + \tl_gput_right:cn { g__scrlfile_exclude_package_##1_tl } { #2 } + } + \disable@package@load { ##1 } + { \tl_use:c { g__scrlfile_exclude_package_##1_tl } } + } + } + \clist_clear:N \l__scrlfile_package_clist + } +% \end{macrocode} +% +% \begin{macro}{\l__scrlfile_package_clist} +% One local variable is used to process the \meta{package-list} argument of +% \cs{PreventPackageFromLoading}. +% \begin{macrocode} +\clist_new:N \l__scrlfile_package_clist +% \end{macrocode} +% \end{macro} +% +% And here comes the message, that could be used either as a warning or as an +% info. +% \begin{macrocode} +\msg_new:nnn { scrlfile } { no-prevent-for-already-loaded } + { + Cannot~prevent~package~`#1'~from~being~loaded,~ + because~it~has~been~loaded~already~before~line~\msg_line_number: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\StorePreventPackageFromLoading} +% This simply copies the internal \texttt{clist} to a macro. +% \begin{macrocode} +\NewDocumentCommand \StorePreventPackageFromLoading { m } + { \edef #1 { \clist_use:Nn \g__scrlfile_prevent_clist { , } } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ResetPreventPackageFromLoading} +% Map the internal list to a function that re-enables the package. At the end +% the internal list is cleared. +% \begin{macrocode} +\NewDocumentCommand \ResetPreventPackageFromLoading {} + { + \clist_map_function:NN \g__scrlfile_prevent_clist \reenable@package@load + \clist_gclear:N \g__scrlfile_prevent_clist + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\UnPreventPackageFromLoading} +% Here again the argument is a \meta{package-list} not only one +% \meta{package}. So we have to build a local \texttt{clist} and walk through +% it. +% \begin{macrocode} +\NewDocumentCommand \UnPreventPackageFromLoading { s m } + { + \clist_set:Nx \l__scrlfile_package_clist { #2 } + \clist_map_inline:Nn \l__scrlfile_package_clist + { + \clist_if_in:NnT \g__scrlfile_prevent_clist { ##1 } + { + \clist_gremove_all:Nn \g__scrlfile_prevent_clist { ##1 } + \reenable@package@load { ##1 } + \IfBooleanT { #1 } + { \cs_undefine:c { g__scrlfile_exclude_package_##1_tl } } + } + } + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Extra Document Hooks} +% +% \begin{macro}{\BeforeClosingMainAux} +% \changes{v3.32}{2020/09/10}{optional argument added} +% Here we cannot simply wrap this to the hook +% \texttt{enddocument/afterlastpage}, because it is documented, that inside +% the \meta{code} \cs{protected@write} is replaced by +% \cs{immediate@protected@write}. So we have to take extra care to it. +% \begin{macrocode} +\NewDocumentCommand \BeforeClosingMainAux { o m } + { + \hook_gput_code:nnn { enddocument / afterlastpage } { #1 } + { + \debug_suspend: + \RenewDocumentCommand \BeforeClosingMainAux { m } { ##1 } + \cs_set_eq:NN \__scrlfile_protected@write:Nnn \protected@write + \cs_set_eq:NN \protected@write \protected@immediate@write + #2 + \cs_set_eq:NN \protected@write \__scrlfile_protected@write:Nnn + \debug_resume: + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\AfterReadingMainAux} +% \changes{v3.32}{2020/09/10}{optional argument added} +% Here we the exact same problem as with \cs{BeforeClosingMainAux}. +% \begin{macrocode} +\NewDocumentCommand \AfterReadingMainAux { o m } + { + \hook_gput_code:nnn { enddocument / afteraux } { #1 } + { + \debug_suspend: + \RenewDocumentCommand \AfterReadingMainAux { m } { ##1 } + \cs_set_eq:NN \__scrlfile_protected@write:Nnn \protected@write + \cs_set_eq:NN \protected@write \protected@immediate@write + #2 + \cs_set_eq:NN \protected@write \__scrlfile_protected@write:Nnn + \debug_resume: + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\ExplSyntaxOff +% \end{macrocode} +% +% \subsection{Kernel Extensions not Using \LaTeX3} +% +% \begin{macro}{\protected@immediate@write} +% Like \LaTeX{} kernel's |\protected@write| but using |\immediate\write|. In +% this case it is even not a good idea to protect |\thepage|! +% \begin{macrocode} +\ProvideDocumentCommand\protected@immediate@write{m+m+m} + {% + \begingroup + #2% + \let\protect\@unexpandable@protect + \edef\reserved@a{\immediate\write#1{#3}}% + \reserved@a + \endgroup + \if@nobreak\ifvmode\nobreak\fi\fi + } +% \end{macrocode} +% \end{macro} +% +% \subsection{The \KOMAScript{} Logo} +% +% Last but not least this is a \KOMAScript{} package, so we also define the +% \KOMAScript{} logo: +% \begin{macrocode} +\RequirePackage{scrlogo} +% \end{macrocode} +% +% \Finale +% +% \endinput +% Local Variables: +% mode: doctex +% TeX-master: t +% End: |