Raw File
ltclass.dtx
% \iffalse meta-comment
%
% Copyright (C) 1993-2024
% The LaTeX Project and any individual authors listed elsewhere
% in this file.
%
% This file is part of the LaTeX base system.
% -------------------------------------------
%
% 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
%    https://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008 or later.
%
% This file has the LPPL maintenance status "maintained".
%
% The list of all files belonging to the LaTeX base distribution is
% given in the file `manifest.txt'. See also `legal.txt' for additional
% information.
%
% The list of derived (unpacked) files belonging to the distribution
% and covered by LPPL is defined by the unpacking scripts (with
% extension .ins) which are part of the distribution.
%
% \fi
%
% \iffalse
%%% From File: ltclass.dtx
%
%<*driver>
% \fi
\ProvidesFile{ltclass.dtx}
             [2023/04/14 v1.5h LaTeX Kernel (Class & Package Interface)]
% \iffalse
\documentclass{ltxdoc}
\GetFileInfo{ltclass.dtx}
\begin{document}
\title{The main structure of documents}
\author{Frank Mittelbach\and Chris Rowley\and Alan Jeffrey\and
        David Carlisle}
\date{\filedate}
 \MaintainedByLaTeXTeam{latex}
 \maketitle

 \providecommand\pkg[1]{\texttt{#1}}

 \DocInput{\filename}
\end{document}
%</driver>
% \fi
%
% \iffalse
% (C) Copyright Frank Mittelbach, Chris Rowley,
%               Alan Jeffrey and David Carlisle 1993-1998.
% All rights reserved.
% \fi
%
%
% \changes{v0.2f}{1993/11/22}
%         {\cs{@unknownversion} removed}
% \changes{v1.0j}{1994/10/18}
%         {Move \cs{listfiles} to ltfiles.dtx}
% \changes{v1.0f}{1994/05/22}{Use new warning and error commands}
% \changes{v1.0l}{1994/11/17}{\cs{@tempa} to \cs{reserved@a}}
% \changes{v1.0z}{1998/03/21}{Added to documentation of filecontents}
% \changes{v1.1c}{1998/08/17}{(RmS) Minor documentation fixes.}
% \changes{v1.3o}{2020/08/21}{Integration of new hook management interface}
% \changes{v1.4f}{2021/08/25}{Standardise generic hook names (gh/648)}
%
%
% \section{Introduction}
%
% This file implements the following declarations, which replace
% |\documentstyle| in  \LaTeXe\ documents.
%
% Note that old documents containing |\documentstyle| will be run using
% a compatibility option---thus keeping everyone happy, we hope!
%
% The overall idea is that there are two types of `style files':
% `class files' which define elements and provide a default formatting
% for them;  and `packages' which provide extra functionality.  One
% difference between \LaTeXe\ and \LaTeX2.09 is that \LaTeXe\ packages
% may have options. Note that options to classes packages may be
% implemented such that they input files, but these file names are not
% necessarily directly related to the option name.
%
% \section{User interface}
%
% |\documentclass[|\meta{main-option-list}|]{|^^A
%   \meta{class}|}[|\meta{version}|]|
%
% There must be exactly one such declaration, and it must come first.
% The \meta{main-option-list} is a list of options which can modify the
% formatting of elements which are defined in the \meta{class} file
% as well as in all following |\usepackage| declarations (see below).
% The \meta{version} is a version number, beginning with a date in the
% format |YYYY/MM/DD|.  If an older version of the class is found, a
% warning is issued.
%
% \bigskip
%
% |\documentstyle[|\meta{main-option-list}|]{|^^A
%   \meta{class}|}[|\meta{version}|]|
%
% The |\documentstyle| declaration is kept in order to maintain upward
% compatibility with \LaTeX2.09 documents.  It is similar to
% |\documentclass|, but it causes all options in
% \meta{main-option-list} that the \meta{class} does not use to be
% passed to |\RequirePackage| after the options have been processed.
% This maintains compatibility with the 2.09 behaviour. Also a flag is
% set to indicate that the document is to be processed in \LaTeX2.09
% compatibility mode.  As far as most packages are concerned, this
% only affects the warnings and errors \LaTeX\ generates. This flag
% does affect the definition of font commands, and |\sloppy|.
%
% \bigskip
%
% |\usepackage[|\meta{package-option-list}|]{|^^A
%    \meta{package-list}|}[|\meta{version}|]|
%
% There can be any number of these declarations. All packages in
% \meta{package-list} are called with the same options.
%
% Each \meta{package} file defines new elements (or modifies those
% defined in the \meta{class}), and thus extends the range of documents
% which can be processed.
% The \meta{package-option-list} is a list of options which can modify
% the formatting of elements defined in the \meta{package} file.
% The \meta{version} is a version number, beginning with a date in the
% format |YYYY/MM/DD|.  If an older version of the package is found, a
% warning is issued.
%
% Each package is loaded only once.  If the same package is requested
% more than once, nothing happens, unless the package has been requested
% with options that were not given the first time it was loaded, in
% which case an error is produced.
%
% As well as processing the options given in the
% \meta{package-option-list}, each package processes the
% \meta{main-option-list}.  This means that options that affect all
% of the packages can be given globally, rather than repeated for every
% package.
%
% Note that class files have the extension |.cls|, packages have the
% extension |.sty|.
%
% \DescribeEnv{filecontents}
% The environment |filecontents| is intended for passing the contents
% of packages, options, or other files along with a document in a
% single file.
% It has one argument, which is the name of the file to create. If that
% file already exists (maybe only in the current directory if the OS
% supports a notion of a `current directory' or `default directory')
% then nothing happens
% (except for an information message) and the body of the environment
% is bypassed. Otherwise, the body of the environment is written
% verbatim to the file name given as the first argument, together with
% some comments about how it was produced.
%
% The environment can also be called with an optional argument which is
% used to alter some of its behavior: option \texttt{force} or
% \texttt{overwrite} will allow for overwriting existing files,
% option \texttt{nosearch} will only check the current directory
% when looking if the file exists. This can be useful if you want to
% generate a local (modified) copy of some file that is already in the
% search tree of \TeX{}. Finally, you can use \texttt{noheader} to
% prevent it from writing the standard blurb at the top of the file
% (this is actually the same as using the star form of the environment).
%
% The environment is now allowed anywhere in the document, but to ensure
% that all packages or options necessary are available when the
% document is run, it is normally best to place it at the top of your
% file (before \cs{documentclass}).
% A possible use case for using it inside the document body is if you
% want to reuse some text several times in the document you could then
% write it and later use \cs{input} to retrieve it where needed.
%
%
% The begin and end tags should each be on a
% line by itself.
%
% \subsection{Option processing}
%
% When the options are processed, they are divided into two types: {\em
% local\/} and {\em global}:
% \begin{itemize}
%
% \item For a class, the options in the |\documentclass| command are
%    local.
%
% \item For a package, the options in the |\usepackage| command are
%    local, and the options in the |\documentclass| command are global.
%
% \end{itemize}
% The options for |\documentclass| and |\usepackage|
% are processed in the following way:
% \begin{enumerate}
%
% \item The local and global options that have been declared
%   (using |\DeclareOption| as  described below) are processed
%   first.
%
%  In the case of |\ProcessOptions|, they are processed in the order
%  that they were declared in the class or package.
%
%  In the case of |\ProcessOptions*|, they are processed in the order
%  that they appear in the option-lists. First the global options, and
%  then the local ones.
%
% \item Any remaining local options are dealt with using the default
%   option (declared using the |\DeclareOption*| declaration described
%   below).  For document classes, this usually does nothing, but
%   records the option on a list of unused options.
%   For packages, this usually produces an error.
%
% \end{enumerate}
% Finally, when |\begin{document}| is reached, if there are any global
% options which have not been used by either the class or any package,
% the system will produce a warning.
%
%
% \section{Class and Package interface}
%
% \subsection{Class name and version}
%
% \DescribeMacro\ProvidesClass
% A class can identify itself with the
% |\ProvidesClass{|\meta{name}|}[|\meta{version}|]| command.  The
% \meta{version} should begin with a date in the format |YYYY/MM/DD|.
%
% \subsection{Package name and version}
%
% \DescribeMacro\ProvidesPackage
% A package can identify itself with the
% |\ProvidesPackage|\marg{name}\oarg{version} command.  The
% \meta{version} should begin with a date in the format |YYYY/MM/DD|.
%
% \subsection{Requiring other packages}
%
% \DescribeMacro\RequirePackage
% Packages or classes can load other packages using\\
% |\RequirePackage|\oarg{options}\marg{name}\oarg{version}.\\
% If the package has already been loaded, then nothing happens unless
% the requested options are not a subset of the options with which it
% was loaded, in which case an error is called.
%
% \DescribeMacro\LoadClass
%  Similar to |\RequirePackage|, but for classes, may not be used in
%  package files.
%
% \DescribeMacro\PassOptionsToPackage
% Packages can pass options to other packages using:\\
% |\PassOptionsToPackage{|\meta{options}|}{|\meta{package}|}|.\\
% \DescribeMacro\PassOptionsToClass
% This adds the \meta{options} to the options list of any future
% |\RequirePackage| or |\usepackage| command.  For example:
% \begin{verbatim}
%    \PassOptionsToPackage{foo,bar}{fred}
%    \RequirePackage[baz]{fred}\end{verbatim}
% is the same as:
%\begin{verbatim}
%    \RequirePackage[foo,bar,baz]{fred}
%\end{verbatim}
%
% \DescribeMacro\LoadClassWithOptions
% |\LoadClassWithOptions|\marg{name}\oarg{version}:\\
% This is similar to
% |\LoadClass|, but it always calls class \meta{name} with
% exactly the same option list that is being used by the current class,
% rather than an option explicitly  supplied or passed on by
% |\PassOptionsToClass|.
% \DescribeMacro\RequirePackageWithOptions
% |\RequirePackageWithOptions| is the analogous command for packages.
%
% This is mainly intended to allow one class to simply build on another,
% for example:
%\begin{verbatim}
%   \LoadClassWithOptions{article}
%\end{verbatim}
%
% This should be contrasted with the slightly different construction
%\begin{verbatim}
%   \DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
%   \ProcessOptions
%   \LoadClass{article}
%\end{verbatim}
%
% As used here, the effects are more or less the same, but the
% version using |\LoadClassWithOptions| is slightly quicker
% (and less to type).
% If, however, the class declares options of its own then
% the two constructions are different; compare, for example:
%\begin{verbatim}
%   \DeclareOption{landscape}{...}
%   \ProcessOptions
%   \LoadClassWithOptions{article}
%\end{verbatim}
% with:
%\begin{verbatim}
%   \DeclareOption{landscape}{...}
%   \DeclareOption*{\PassOptionsToClass{\CurrentOption}{article}}
%   \ProcessOptions
%   \LoadClass{article}
%\end{verbatim}
% In the first case, the \textsf{article} class will be called with
% option |landscape| precisely when the current class is called with
% this option; but in the second example it will
% not as in that case \textsf{article} is only passed options by the
% default option handler, which is not used for |landscape| as that
% option is explicitly declared.
%
% \DescribeMacro\IfPackageLoadedTF
% \DescribeMacro\IfClassLoadedTF
% \DescribeMacro\@ifpackageloaded
% \DescribeMacro\@ifclassloaded
% To find out if a package has already been loaded, use
% \begin{quote}
% |\IfPackageLoadedTF{|\meta{package}|}{|\meta{true}|}{|\meta{false}|}|\\
% \end{quote}
% or the old name \cs{@ifpackageloaded}.
%
% \DescribeMacro\IfPackageAtLeastTF
% \DescribeMacro\IfClassAtLeastTF
% \DescribeMacro\IfFileAtLeastTF
% \DescribeMacro\@ifpackagelater
% \DescribeMacro\@ifclasslater
% \changes{v1.1i}{2013/07/07}{Correctly describe how the date in
%       \cs{@ifpackagelater} is used}
% To find out if a package has already been loaded with a version
% equal to or more
% recent than \meta{date}, use
% \begin{quote}
% |\IfPackageAtLeastTF{|\meta{package}|}{|\meta{date}|}{|^^A
% \meta{true}|}{|\meta{false}|}|
% \end{quote}
% or the old name \cs{@ifpackagelater}.

% \DescribeMacro\IfFormatAtLeastTF
% To test the format date use
% \begin{quote}
% |\IfFormatAtLeastTF{|\meta{date}|}{|^^A
% \meta{true}|}{|\meta{false}|}|
% \end{quote}
%
% \DescribeMacro\IfPackageLoadedWithOptionsTF
% \DescribeMacro\IfClassLoadedWithOptionsTF
% \DescribeMacro\@ifpackagewith
% \DescribeMacro\@ifclasswith
% To find out if a package has already been loaded with at least the
% options \meta{options}, use
% \begin{quote}
% |\IfPackageLoadedWithOptionsTF{|\meta{package}|}{|\meta{options}|}{|^^A
% \meta{true}|}{|\meta{false}|}|
% \end{quote}
% or the old name \cs{@ifpackagewith}.
%
% There exists one package that can't be tested with the above
% commands: the \texttt{fontenc} package pretends that it was never
% loaded to allow for repeated reloading with different options (see
% \texttt{ltoutenc.dtx} for details).
%
%
% \subsection{Declaring new options}
%
% Options for classes and packages are built using the same macros.
%
% \DescribeMacro\DeclareOption To define a builtin option, use
% |\DeclareOption{|\meta{name}|}{|\meta{code}|}|.
%
% \DescribeMacro{\DeclareOption*} To define the default action to
% perform for local options which have not been declared, use
% |\DeclareOption*{|\meta{code}|}|.
%
% {\em Note\/}: there should be no use of\\
%  |\RequirePackage|, |\DeclareOption|, |\DeclareOption*| or
%   |\ProcessOptions|\\
% inside |\DeclareOption| or |\DeclareOption*|.
%
% Possible uses for |\DeclareOption*| include:
%
% |\DeclareOption*{}|\\
%    Do nothing. Silently accept unknown options. (This suppresses the
%    usual warnings.)
%
% |\DeclareOption*{\@unkownoptionerror}|\\
%     Complain about unknown local options. (The initial setting for
%       package files.)
%
% |\DeclareOption*{\PassOptionsToPackage{\CurrentOption}|^^A
%                                     |{|\meta{pkg-name}|}|\\
% Handle the current option by passing it on to the package
% \meta{pkg-name}, which will presumably be loaded via
% |\RequirePackage| later in the file. This is useful for building
% `extension' packages, that perhaps handle a couple of new options,
% but then pass everything else on to an existing package.
%
% |\DeclareOption*{\InputIfFileExists{xx-\CurrentOption.yyy}%|\\
% |               {}%|\\
% |               {\OptionNotUsed}}|\\
%  Handle the option foo by loading the file |xx-foo.yyy| if it
%  exists, otherwise do nothing, but declare that the option was not
%  used.
%  Actually the |\OptionNotUsed| declaration is only needed if this is
%  being used in class files, but does no harm in package files.
%
%
% \subsection{Safe Input Macros}
% \DescribeMacro{\InputIfFileExists}
%  |\InputIfFileExists{|\meta{file}|}{|\meta{then}|}{|\meta{else}|}|\\
% Inputs \meta{file} if it exists. Immediately before the input,
% \meta{then} is executed. Otherwise \meta{else} is executed.
%
% \DescribeMacro{\IfFileExists}
% As above, but does not input the file.
%
% One thing you might like to put in the \meta{else} clause is
%
% \DescribeMacro{\@missingfileerror}
% This starts an interactive request for a filename, supplying default
% extensions. Just hitting return causes the whole input to be skipped
% and entering |x| quits the current run,
%
% \DescribeMacro{\input}
% This has been redefined from the \LaTeX2.09 definition, in terms of
% the new commands |\InputIfFileExists| and |\@missingfileerror|.
%
%
% \DescribeMacro{\listfiles} Giving this declaration in the preamble
% causes a list of all files input via the `safe input' commands to be
% listed at the end. Any strings specified in the optional argument to
% |\ProvidesPackage| are listed alongside the file name. So files in
% standard (and other non-standard) distributions can put informative
% strings in this argument.
%
% \MaybeStop{}
%
% \section{Implementation}
%
%    \begin{macrocode}
%<*2ekernel>
%    \end{macrocode}
%
%
% \changes{v0.2g}{1993/11/23}
%         {Various macros now moved to latex.tex.}
% \changes{v0.2g}{1993/11/23}
%         {Warnings and errors now directly coded.}
% \changes{v0.2h}{1993/11/28}
%         {Primitive filenames now terminated by space not \cs{relax}.}
% \changes{v0.2h}{1993/11/28}
%         {Directory syntax checking moved to dircheck.dtx}
% \changes{v0.2h}{1993/11/28}
%         {Assorted commands now in the kernel removed.}
% \changes{v0.2i}{1993/12/03}
%         {\cs{@onlypreamble}: Many commands declared.}
% \changes{v0.2i}{1993/12/03}
%         {Removed obsolete \cs{@documentclass}}
% \changes{v0.2o}{1993/12/13}
%         {Removed setting \cs{errorcontextlines}\ (now in latex.tex)}
% \changes{v0.2p}{1993/12/15}
%         {Removed extra `.'s from \cs{@@warning}s}
% \changes{v0.2s}{1994/01/17}
%         {Added many more \cs{@onlypreamble} commands}
% \changes{v0.2s}{1994/01/17}
%         {Wrapped long lines to column 72}
% \changes{v0.3a}{1994/03/02}
%         {Remove need for driver file}
% \changes{v0.3b}{1994/03/08}
%         {Modify driver code into `new style'}
% \changes{v0.3c}{1994/03/12}
%         {Change name from docclass to ltclass}
% \changes{v0.3h}{1994/04/25}
%         {Removed spurious extra `.'s at the end of error messages}
% \changes{v1.0a}{1994/04/29}
%         {Change version number to 1 (no other change)}
% \changes{v1.0k}{1994/11/03}
%         {Move \cs{@missingfileerror} to ltfiles}
%
% \begin{macro}{\if@compatibility}
%    The flag for compatibility mode.
%    \begin{macrocode}
\newif\if@compatibility
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@documentclasshook}
%    This legacy hook is called after the first |\documentclass| command.
%    It is \emph{not} integrated with the new 2020 hook management system!
%    By
%    default this checks to see if |\@normalsize| is undefined, and if
%    so, sets it to |\normalsize|.
% \changes{v0.2q}{1993/12/17}
%         {Macro added}
% \changes{v0.2z}{1994/02/10}
%         {Changed the name from \cs{@compatibility} to
%          \cs{@documentclasshook}, and added the check for whether
%          \cs{@normalsize} has been defined.  ASAJ.}
%    \begin{macrocode}
\def\@documentclasshook{%
   \ifx\@normalsize\@undefined
      \let\@normalsize\normalsize
   \fi
}
%    \end{macrocode}
% \end{macro}
%
%  \begin{macro}{\@declaredoptions}
%    This list is automatically built by |\DeclareOption|.
%    It is the list of options (separated by commas) declared in
%    the class or package file and it defines the order in which
%    the corresponding |\ds@|\meta{option} commands are executed.
%    All local \meta{option}s which are not declared will be processed
%    in the order defined by the optional argument of |\documentclass|
%    or |\usepackage|.
%    \begin{macrocode}
\let\@declaredoptions\@empty
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@classoptionslist}
%    List of options of the main class.
% \changes{v1.0u}{1996/07/26}{made only preamble}
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
\let\@classoptionslist\relax
%\@onlypreamble\@classoptionslist
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@raw@classoptionslist}
%    List of options of the main class (unprocessed).
% \changes{v1.4b}{2021/05/18}{Initialise to \cs{relax} to match \cs{@classoptionslist}}
%    \begin{macrocode}
\let\@raw@classoptionslist\relax
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@unusedoptionlist}
% \changes{v1.0u}{1996/07/26}{made only preamble}
%    List of options of the main class that haven't been declared or
%    loaded as class option files.
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
\let\@unusedoptionlist\@empty
%\@onlypreamble\@unusedoptionlist
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\CurrentOption}
%    Name of current package or option.
% \changes{v0.2c}{1993/11/17}
%         {Name changed from \cs{@curroption}}
%    \begin{macrocode}
\let\CurrentOption\@empty
%    \end{macrocode}
%  \end{macro}
%
% \begin{macro}{\@currpath}
%   Path to the current file if explicitly given.
%   \changes{v1.3u}{2020/11/20}{Macro added}
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}{\@currpath}%
%<latexrelease>  {Add \@currpath}%
\let\@currpath\@empty
%<latexrelease>\EndIncludeInRelease
%
%<latexrelease>\IncludeInRelease{0000/00/00}{\@currpath}%
%<latexrelease>  {Add \@currpath}%
%<latexrelease>\let\@currpath\@undefined
%<latexrelease>\EndIncludeInRelease
%</2ekernel|latexrelease>
%<*2ekernel>
%    \end{macrocode}
% \end{macro}
%
%  \begin{macro}{\@currname}
%    Name of current package or option.
%    \begin{macrocode}
\let\@currname\@empty
%    \end{macrocode}
%  \end{macro}
%
% \begin{macro}{\@currext}
%    The current file extension.
% \changes{v0.2a}{1993/11/14}{Name changed from \cs{@currextension}}
%    \begin{macrocode}
\global\let\@currext=\@empty
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@clsextension}
% \begin{macro}{\@pkgextension}
%    The two possible values of |\@currext|.
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
\def\@clsextension{cls}
\def\@pkgextension{sty}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@pushfilename}
% \begin{macro}{\@popfilename}
% \begin{macro}{\@currnamestack}
% Commands to push and pop the file name and extension. \\
% |#1| current name.      \\
% |#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@@}}
% \changes{v1.3s}{2020/10/08}{Added missing 2020/02/02 \cs{IncludeInRelease}}
% \changes{v1.3v}{2020/12/14}{Removed \cs{@expl@@@hook@curr@name@push@@n}}
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}{\@pushfilename}%
%<latexrelease>  {Add \@expl@push@filename@@ and \@expl@push@filename@aux@@}%
\def\@pushfilename{%
%    \end{macrocode}
%   The push and pop macros are injected in \cs{@pushfilename} and
%   \cs{@popfilename} so that they correctly keep track of the hook
%   labels.
%
%   This needs cleanup with the \pkg{expl3} interfaces also playing
%   here, e.g., \cs{@expl@push@filename@@} needs cleanup and (and
%   should probably not have this name either).
%    \begin{macrocode}
  \@expl@push@filename@@
  \xdef\@currnamestack{%
    {\@currname}%
    {\@currext}%
    {\the\catcode`\@}%
    \@currnamestack}%
%    \end{macrocode}
%   Temporarily add a stack for \cs{@currpath} here.  This should be
%   integrated in the main file stack eventually, but other packages
%   rely on \cs{@currnamestack} having three elements per file, so that
%   isn't a trivial change.  The prefix \cs{@kernel@...} hopefully
%   discourages people from using it.
%    \begin{macrocode}
  \xdef\@kernel@currpathstack{%
    {\@currpath}%
    \@kernel@currpathstack}%
  \@expl@push@filename@aux@@}
%<latexrelease>\EndIncludeInRelease
%    \end{macrocode}
%
%   The following version of \cs{@pushfilename} didn't formally exist in
%   this file, but in the 2020/02/02 release, \pkg{expl3} was preloaded
%   and it patched \cs{@pushfilename} (and \cs{@popfilename}) by adding
%   some hooks in there.  But rolling back to 2020/02/02, \pkg{expl3}
%   doesn't patch these macros again, so rolling back has to take those
%   hooks into account.  Same goes for \cs{@popfilename}.
%    \begin{macrocode}
%<latexrelease>
%<latexrelease>\IncludeInRelease{2020/02/02}{\@pushfilename}%
%<latexrelease>  {Add \@expl@push@filename@@}%
%<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>\EndIncludeInRelease
%<latexrelease>
%    \end{macrocode}
%
% When we roll back from a release that has \pkg{expl3} preloaded, the
% definitions of \cs{@pushfilename} and \cs{@popfilename} can't be
% completely rolled back otherwise \pkg{expl3}-based packages won't
% have the automatic \cs{ExplSyntaxOff} at the end.  Here and below for
% \cs{@popfilename}, we don't roll back all the way through if coming
% from \LaTeX${}>2020-02-02$.
% \changes{v1.4a}{2021/03/27}
%         {Do not completely roll back if \pkg{expl3} is loaded.}
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}{\@pushfilename}%
%<latexrelease>  {Add \@expl@push@filename@@ and \@expl@push@filename@aux@@}%
%<latexrelease>\ifnum\sourceLaTeXdate<20200202\relax
%<latexrelease>  \GenericInfo{}{Defining 00-00-00\string\@pushfilename.}
%<latexrelease>\def\@pushfilename{%
%<latexrelease>  \xdef\@currnamestack{%
%<latexrelease>    {\@currname}%
%<latexrelease>    {\@currext}%
%<latexrelease>    {\the\catcode`\@}%
%<latexrelease>    \@currnamestack}}
%<latexrelease>\else
%<latexrelease>  \GenericInfo{}{Defining 2020-02-02\string\@pushfilename.}
%<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>\fi
%<latexrelease>\EndIncludeInRelease
\@onlypreamble\@pushfilename
%    \end{macrocode}
%
%
%
%
%
% \changes{v1.3l}{2020/06/05}{Added \cs{@expl@pop@filename@@}}
%    \begin{macrocode}
%<latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}{\@popfilename}%
%<latexrelease>  {Add \@expl@pop@filename@@}%
\def\@popfilename{\@expl@@@hook@curr@name@pop@@
  \expandafter\@p@pfilename\@currnamestack\@nil
%    \end{macrocode}
%   Same for popping:
%    \begin{macrocode}
  \expandafter\@p@pfilepath\@kernel@currpathstack\@nil
  \@expl@pop@filename@@}
%<latexrelease>\EndIncludeInRelease
%<latexrelease>
%<latexrelease>\IncludeInRelease{2020/02/02}{\@popfilename}%
%<latexrelease>  {Add \@expl@push@filename@@}%
%<latexrelease>\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil
%<latexrelease>  \@expl@pop@filename@@}
%<latexrelease>\EndIncludeInRelease
%<latexrelease>
%    \end{macrocode}
%
% \changes{v1.4a}{2021/03/27}
%         {Do not completely roll back if \pkg{expl3} is loaded.}
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}{\@popfilename}%
%<latexrelease>  {Add \@expl@push@filename@@ and \@expl@push@filename@aux@@}%
%<latexrelease>\ifnum\sourceLaTeXdate<20200202\relax
%<latexrelease>  \GenericInfo{}{Defining 00-00-00\string\@popfilename.}
%<latexrelease>\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil}
%<latexrelease>\else
%<latexrelease>  \GenericInfo{}{Defining 2020-02-02\string\@popfilename.}
%<latexrelease>\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil
%<latexrelease>  \@expl@pop@filename@@}
%<latexrelease>\fi
%<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}%
  \catcode`\@#3\relax
  \gdef\@currnamestack{#4}}
\@onlypreamble\@p@pfilename
%    \end{macrocode}
%
%    \begin{macrocode}
\gdef\@currnamestack{}
\@onlypreamble\@currnamestack
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\@kernel@currpathstack}
%   Path to the current file if explicitly given.  The auxiliary is
%   needed here to insert a \cs{@empty} to prevent the loss of braces.
%   \changes{v1.3u}{2020/11/20}{Macro added}
%   \changes{v1.3w}{2021/01/21}{Add empty entry for latexrelease}
%   \changes{v1.4c}{2021/06/03}%
%           {Take care of \cs{@kernel@currpathstack} when rolling
%            back/forward.}
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}{\@kernel@currpathstack}%
%<latexrelease>  {Add \@kernel@currpathstack}%
%    \end{macrocode}
%   If rolling backwards to this release, \cs{@kernel@currpathstack}
%   will be defined, so the \cs{gdef} line should not be executed, thus
%   the \cs{@gobblethree} will take it out, so the satck isn't touched.
%    \begin{macrocode}
%<latexrelease>\@ifundefined{@kernel@currpathstack}{}{\@gobblethree}
\gdef\@kernel@currpathstack{}%
%    \end{macrocode}
%   If rolling forward to this release, then the \cs{gdef} line above
%   will define the path stack to be empty (which it can't be, inside a
%   file), so the code below will traverse the \cs{@currnamestack}, and
%   add as many empty items to \cs{@kernel@currpathstack} as there are
%   items in \cs{@currnamestack}, so both are back in sync.  Most of the
%   time \pkg{latexrelease} is loaded on top-level, so only one item is
%   needed, but \pkg{platexrelease} loads it internally, so the more
%   complicated loop is needed.
%    \begin{macrocode}
%<latexrelease>\ifx\@kernel@currpathstack\@empty
%<latexrelease>  \def\reserved@a#1#2#3{%
%<latexrelease>    \ifx\relax#3\else
%<latexrelease>      \g@addto@macro\@kernel@currpathstack{{}}%
%<latexrelease>      \expandafter\reserved@a
%<latexrelease>    \fi}%
%<latexrelease>  \expandafter\reserved@a\@currnamestack{}{}{\relax}%
%<latexrelease>\fi
\def\@p@pfilepath#1{%
  \gdef\@currpath{#1}\@p@pfilepath@aux\@empty}
\def\@p@pfilepath@aux#1\@nil{%
  \xdef\@kernel@currpathstack{#1}}
%<latexrelease>\EndIncludeInRelease
%
%<latexrelease>\IncludeInRelease{0000/00/00}{\@kernel@currpathstack}%
%<latexrelease>  {Add \@kernel@currpathstack}%
%<latexrelease>\let\@kernel@currpathstack\@undefined
%<latexrelease>\let\@p@pfilepath\@undefined
%<latexrelease>\let\@p@pfilepath@aux\@undefined
%<latexrelease>\EndIncludeInRelease
%</2ekernel|latexrelease>
%<*2ekernel>
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@ptionlist}
%    Returns the option list of the file.
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
\def\@ptionlist#1{%
  \@ifundefined{opt@#1}\@empty{\csname opt@#1\endcsname}}
%\@onlypreamble\@ptionlist
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@ifpackageloaded}
% \begin{macro}{\@ifclassloaded}
%   |\@ifpackageloaded{|\meta{name}|}|
%  Checks to see whether a file has been loaded.
% \changes{v0.2t}{1994/01/18}
%         {Fix typo \cs{@pkgetension}}
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
\def\@ifpackageloaded{\@ifl@aded\@pkgextension}
\def\@ifclassloaded{\@ifl@aded\@clsextension}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\@ifl@aded#1#2{%
  \expandafter\ifx\csname ver@#2.#1\endcsname\relax
    \expandafter\@secondoftwo
  \else
    \expandafter\@firstoftwo
  \fi}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
%
% \begin{macro}{\@ifpackagelater}
% \begin{macro}{\@ifclasslater}
% |\@ifpackagelater{|\meta{name}|}{YYYY/MM/DD}{|\meta{true
%    code}|}{|\meta{false code}|}|
%     Checks that the package loaded is more recent or equal to the
%    given date.
%    A better name for it  would therefore been
%    |\@ifpackagelaterorequal| but it is in use for more than 30
%    years, so \ldots
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
\def\@ifpackagelater{\@ifl@ter\@pkgextension}
\def\@ifclasslater{\@ifl@ter\@clsextension}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
%
%
%  \begin{macro}{\IfPackageAtLeastTF}
%  \begin{macro}{\IfClassAtLeastTF}
%  \begin{macro}{\IfFileAtLeastTF}
%  \begin{macro}{\IfFormatAtLeastTF}
% |\IfFormatAtLeastTF{YYYY/MM/DD}{|\meta{true
%    code}|}{|\meta{false code}|}|
%    Test if the format is later or equal to the given date.
% \changes{v1.3k}{2020/04/07}{Macro added; also in rollback (gh/168)}
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
% \changes{v1.5g}{2023/03/28}{Added \cs{IfFileAtLeastTF} (gh/1015)}
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>                 {\IfFormatAtLeastTF}{Test format date}%
\def\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
\let\IfPackageAtLeastTF\@ifpackagelater
\let\IfClassAtLeastTF\@ifclasslater
\def\IfFileAtLeastTF#1{\expandafter\@ifl@t@r\csname ver@#1\endcsname}
%    \end{macrocode}
%    For rollback pretend it was available since the beginning of dawn.
%    \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\IfFormatAtLeastTF}{Test format date}%
%<latexrelease>\def\IfFormatAtLeastTF{\@ifl@t@r\fmtversion}
%<latexrelease>\let\IfPackageAtLeastTF\@ifpackagelater
%<latexrelease>\let\IfClassAtLeastTF\@ifclasslater
%<latexrelease>\def\IfFileAtLeastTF#1{\expandafter\@ifl@t@r\csname ver@#1\endcsname}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%  \end{macro}
%  \end{macro}
%
% \begin{macro}{\@ifl@ter}
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
\def\@ifl@ter#1#2{%
  \expandafter\@ifl@t@r
    \csname ver@#2.#1\endcsname}
%</2ekernel>
%    \end{macrocode}
%
% This internal macro is also used in |\NeedsTeXFormat|.
% \changes{v0.2f}{1993/11/22}
%         {Added //00 so parsing never produces a runaway argument.}
% \changes{v1.2d}{2018/02/18}
%         {Added 0 up front to make bad data come out as 0.}
% \changes{v1.2g}{2018/04/08}
%         {Strip leading spaces from dates.}
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{2018/04/01}%
%<latexrelease>                 {\@ifl@t@r}{Guard against bad input}%
%<*2ekernel|latexrelease>
\def\@ifl@t@r#1#2{%
  \ifnum\expandafter\@parse@version@#1//00\@nil<%
        \expandafter\@parse@version@#2//00\@nil
    \expandafter\@secondoftwo
  \else
    \expandafter\@firstoftwo
  \fi}
\def\@parse@version@#1{\@parse@version0#1}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\@ifl@t@r}{Guard against bad input}%
%<latexrelease>\def\@ifl@t@r#1#2{%
%<latexrelease>  \ifnum\expandafter\@parse@version#1//00\@nil<%
%<latexrelease>        \expandafter\@parse@version#2//00\@nil
%<latexrelease>    \expandafter\@secondoftwo
%<latexrelease>  \else
%<latexrelease>    \expandafter\@firstoftwo
%<latexrelease>  \fi}
%<latexrelease>\let\@parse@version@\@undefined
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
% \end{macro}
%
% \changes{v1.1j}{2016/06/20}
%         {don't declare as \cs{@onlypreamble}}
% \changes{v1.2c}{2017/03/08}
%         {add \cs{@parse@version@dash} to support yyyy-mm-dd as well as yyyy/mm/dd }
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexreleasefirst>
\def\@parse@version#1/#2/#3#4#5\@nil{%
\@parse@version@dash#1-#2-#3#4\@nil
}
%    \end{macrocode}
%
% The |\if| test here ensures that an argument with no |/|  or |-| produces 0 (actually 00).
%    \begin{macrocode}
\def\@parse@version@dash#1-#2-#3#4#5\@nil{%
  \if\relax#2\relax\else#1\fi#2#3#4 }
%</2ekernel|latexreleasefirst>
%<*2ekernel>
%    \end{macrocode}
%
%
%
% \begin{macro}{\@ifpackagewith}
% \begin{macro}{\@ifclasswith}
% |\@ifpackagewith{|\meta{name}|}{|\meta{option-list}|}|
% Checks that \meta{option-list} is a subset of the options
% \textbf{with} which \meta{name} was loaded.
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
\def\@ifpackagewith{\@if@ptions\@pkgextension}
\def\@ifclasswith{\@if@ptions\@clsextension}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\@if@ptions#1#2{%
  \@expandtwoargs\@if@pti@ns{\@ptionlist{#2.#1}}}
%    \end{macrocode}
%
% Probably shouldn't use |\CurrentOption| here\ldots (changed to
% |\reserved@b|.)
% \changes{v0.2y}{1994/02/07}
%         {Add extra ,s so `two' is not matched with `twocolumn'}
% \changes{v1.1i}{2011/08/19}
%         {Re-jig definition after more stringent \cs{in@} test.}
% \changes{v1.4e}{2021/07/19}{Drop \cs{@onlypreamble}}
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2017/01/01}%
%<latexrelease>                 {\@if@pti@ns}{Spaces in option clash check}%
%<*2ekernel|latexrelease>
\def\@if@pti@ns#1#2{%
 \let\reserved@a\@firstoftwo
%    \end{macrocode}
% \changes{v1.2a}{2016/10/02}
%         {Ignore spaces while checking for option clash}
%    \begin{macrocode}
 \edef\reserved@b{\zap@space#2 \@empty}%
 \@for\reserved@b:=\reserved@b\do{%
   \ifx\reserved@b\@empty
   \else
     \expandafter\in@\expandafter{\expandafter,\reserved@b,}{,#1,}%
     \ifin@
     \else
       \let\reserved@a\@secondoftwo
     \fi
   \fi
 }%
 \reserved@a}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\@if@pti@ns}{Spaces in option clash check}%
%<latexrelease>\def\@if@pti@ns#1#2{%
%<latexrelease> \let\reserved@a\@firstoftwo
%<latexrelease> \@for\reserved@b:=#2\do{%
%<latexrelease>  \ifx\reserved@b\@empty
%<latexrelease>   \else
%<latexrelease>   \expandafter\in@\expandafter
%<latexrelease>                   {\expandafter,\reserved@b,}{,#1,}%
%<latexrelease>    \ifin@
%<latexrelease>    \else
%<latexrelease>     \let\reserved@a\@secondoftwo
%<latexrelease>    \fi
%<latexrelease>  \fi
%<latexrelease> }%
%<latexrelease> \reserved@a}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
% \end{macro}
% \end{macro}
%
%
%
%
%  \begin{macro}{\IfPackageLoadedTF,\IfPackageLoadedWithOptionsTF,
%                \IfClassLoadedTF,\IfClassLoadedWithOptionsTF}
%    More public names for the commands already available for a long time.
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2021/11/15}%
%<latexrelease>                 {\IfPackageLoadedtTF}{Test package loading}%
\let \IfPackageLoadedTF            \@ifpackageloaded
\let \IfClassLoadedTF              \@ifclassloaded
\let \IfPackageLoadedWithOptionsTF \@ifpackagewith
\let \IfClassLoadedWithOptionsTF   \@ifclasswith
%    \end{macrocode}
%    For rollback pretend it was available since the beginning of dawn.
%    \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\IfPackageLoadedtTF}{Test package loading}%
%<latexrelease>
%<latexrelease>\let \IfPackageLoadedTF            \@ifpackageloaded
%<latexrelease>\let \IfClassLoadedTF              \@ifclassloaded
%<latexrelease>\let \IfPackageLoadedWithOptionsTF \@ifpackagewith
%<latexrelease>\let \IfClassLoadedWithOptionsTF   \@ifclasswith
%<latexrelease>
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%  \end{macro}
%
%
%
%
% \begin{macro}{\ProvidesPackage}
%    Checks that the current filename is correct, and defines
%    |\ver@filename|.
% \changes{v0.3c}{1994/03/12}
%         {Add \cs{wlog}}
% \changes{v0.3c}{1994/03/12}
%         {use \cs{@gtempa}}
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>  {\ProvidesPackage}{Check name with \strcmp}%
%<*2ekernel|latexrelease>
\def\ProvidesPackage#1{%
  \xdef\@gtempa{#1}%
%    \end{macrocode}
% \changes{v1.3u}{2020/11/20}
%         {Use string comparison instead of \cs{ifx}}
%   Here \cs{@currpath} is explicitly added to the file name to report
%   when a package or class is loaded using an explicit path.  Loading
%   using a path in the argument is supported but not encouraged.
%    \begin{macrocode}
  \@expandtwoargs\@expl@str@if@eq@@nnTF
      {\@gtempa}{\@currpath\@currname}{}{%
    \@latex@warning@no@line{You have requested
      \@cls@pkg\space`\@currpath\@currname',\MessageBreak
       but the \@cls@pkg\space provides `#1'}%
    }%
  \@ifnextchar[\@pr@videpackage{\@pr@videpackage[]}}%]
\@onlypreamble\ProvidesPackage
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>  {\ProvidesPackage}{Undo: check name with \strcmp}%
%<latexrelease>\def\ProvidesPackage#1{%
%<latexrelease>  \xdef\@gtempa{#1}%
%<latexrelease>  \ifx\@gtempa\@currname\else
%<latexrelease>    \@latex@warning@no@line{You have requested
%<latexrelease>      \@cls@pkg\space`\@currname',\MessageBreak
%<latexrelease>       but the \@cls@pkg\space provides `#1'}%
%<latexrelease>  \fi
%<latexrelease>  \@ifnextchar[\@pr@videpackage{\@pr@videpackage[]}}%]
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\@pr@videpackage}
%    This is the helper command for \cs{ProvidesPackage}. It tries to
%    be cautious when handling the identification string in case it
%    contains UTF-8 characters.
% \changes{v1.3e}{2019/11/29}{Protect package info text (gh/52)}
% \changes{v1.3r}{2020/10/01}{Allow for package substitution}
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>                 {\@pr@videpackage}{Allow for package substitution}%
\def\@pr@videpackage[#1]{%
  \expandafter\protected@xdef                %     <-- protected...
     \csname ver@\@currname.\@currext\endcsname{#1}% Loaded package
  \expandafter\let
    \csname ver@\@currpkg@reqd\expandafter\endcsname % Requested package
    \csname ver@\@currname.\@currext\endcsname
  \ifx\@currext\@clsextension
    \typeout{Document Class: \@gtempa\space#1}%
  \else
    \protected@wlog{Package: \@gtempa\space#1}%   <--- protected
  \fi}
%    \end{macrocode}
% \end{macro}
%
%
%
%  \begin{macro}{\protected@wlog}
%    This is like plain \TeX's \cs{wlog} but gracefully handles
%    protected commands.
%    \begin{macrocode}
\long\def\protected@wlog#1{\begingroup
  \set@display@protect
  \immediate \write \m@ne {#1}\endgroup }
%    \end{macrocode}
%  \end{macro}
%
%
%    \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2020/02/02}%
%<latexrelease>                 {\@pr@videpackage}{Protection for package info}%
%<latexrelease>
%<latexrelease>\def\@pr@videpackage[#1]{%
%<latexrelease>  \expandafter\protected@xdef                %     <-- protected...
%<latexrelease>     \csname ver@\@currname.\@currext\endcsname{#1}%
%<latexrelease>\ifx\@currext\@clsextension
%<latexrelease>    \typeout{Document Class: \@gtempa\space#1}%
%<latexrelease>  \else
%<latexrelease>    \protected@wlog{Package: \@gtempa\space#1}%   <--- protected
%<latexrelease>  \fi}
%<latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\@pr@videpackage}{Protection for package info}%
%<latexrelease>
%<latexrelease>\def\@pr@videpackage[#1]{%
%<latexrelease>  \expandafter\xdef\csname ver@\@currname.\@currext\endcsname{#1}%
%<latexrelease>  \ifx\@currext\@clsextension
%<latexrelease>    \typeout{Document Class: \@gtempa\space#1}%
%<latexrelease>  \else
%<latexrelease>    \wlog{Package: \@gtempa\space#1}%
%<latexrelease>  \fi}
%<latexrelease>\let\protected@wlog\@undefined
%<latexrelease>
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\@pr@videpackage
%    \end{macrocode}
%
%
%
% \begin{macro}{\ProvidesClass}
%    Like |\ProvidesPackage|, but for classes.
%    This needs a dummy \pkg{latexrelease} block to copy the definition
%    of \cs{ProvidesPackage} as it changes across releases.
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>  {\ProvidesClass}{Track \ProvidesPackage}%
%<*2ekernel|latexrelease>
\let\ProvidesClass\ProvidesPackage
\@onlypreamble\ProvidesClass
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ProvidesFile}
%    Like |\ProvidesPackage|, but for arbitrary files. Do not apply
%    |\@onlypreamble| to these, as we may want to label files input
%    during the document.
% \changes{v0.2l}{1993/12/07}
%         {Macro added}
% \changes{v0.3c}{1994/03/12}
%         {Add \cs{wlog}}
% \changes{v0.3g}{1994/04/11}
%         {Protect against weird catcodes.}
% \begin{macro}{\@providesfile}
% \changes{v1.0r}{1995/10/17}
%         {Delay definition of \cs{ProvidesFile} till ltfinal}
% \changes{v1.1a}{1998/03/21}
%         {Allow \&. Internal/2702}
% \changes{v1.1d}{2001/05/25}{Explicitly set catcode of
%                              \cs{endlinechar} to 10 (pr/3334)}
% \changes{v1.1e}{2001/06/04}{But only if it is a char (pr/3334)}
% \changes{v1.1f}{2001/08/26}{Readded setting of space char (pr/3353)}
%    \begin{macrocode}
\def\ProvidesFile#1{%
  \begingroup
    \catcode`\ 10 %
    \ifnum \endlinechar<256 %
      \ifnum \endlinechar>\m@ne
        \catcode\endlinechar 10 %
      \fi
    \fi
    \@makeother\/%
    \@makeother\&%
%    \end{macrocode}
% \changes{v1.1g}{2004/01/28}{Use kernel version of
%                             \cs{@ifnextchar} (pr/3501)}
%    \begin{macrocode}
    \kernel@ifnextchar[{\@providesfile{#1}}{\@providesfile{#1}[]}}
%    \end{macrocode}
%
% During initex a special version of |\@providesfile| is used.
% The real definition is installed right at the end, in |ltfinal.dtx|.
%\begin{verbatim}
%\def\@providesfile#1[#2]{%
%    \wlog{File: #1 #2}%
%    \expandafter\xdef\csname ver@#1\endcsname{#2}%
%  \endgroup}
%\end{verbatim}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\PassOptionsToPackage}
% \begin{macro}{\PassOptionsToClass}
%   If the package has been loaded, we check that it was first loaded with
%   the options.  Otherwise we add the option list to that of the package.
% \changes{v1.3t}{2020/10/18}{Drop path from \cs{input@path} (gh/414).}
% \changes{v1.3x}{2021/02/18}{save raw option lists (gh/85)}
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2021/06/01}%
%<latexrelease>                 {\@pass@ptions}{Raw option lists}%
%<*2ekernel|latexrelease>
\def\@pass@ptions#1#2#3{%
  \@expl@@@filehook@set@curr@file@@nNN
    {\@expl@@@filehook@resolve@file@subst@@w #3.#1\@nil}%
      \reserved@a\reserved@b
  \@expl@@@filehook@clear@replacement@flag@@
%    \end{macrocode}
% \changes{v1.5d}{2022/10/10}{Use \cs{protected@xdef}.}
%    \begin{macrocode}
  \expandafter\protected@xdef\csname opt@\reserved@a\endcsname{%
    \@ifundefined{opt@\reserved@a}\@empty
      {\csname opt@\reserved@a\endcsname,}%
    \zap@space#2 \@empty}%
%    \end{macrocode}
% \changes{v1.3u}{2020/11/20}
%         {Copy option list to the requested package.}
%    \begin{macrocode}
  \expandafter\let
    \csname opt@#3.#1\expandafter\endcsname
    \csname opt@\reserved@a\endcsname
%    \end{macrocode}
% Extend raw option list
% \changes{v1.4c}{2021/06/06}
%         {apply \cs{expandafter} to raw options for gh/580}
%    \begin{macrocode}
    \@ifundefined{@raw@opt@#3.#1}%
      {\expandafter\gdef\csname @raw@opt@#3.#1\expandafter\endcsname
                \expandafter{#2}}%
      {\expandafter\g@addto@macro\csname @raw@opt@#3.#1\expandafter\endcsname
                \expandafter{\expandafter,#2}}%
}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{2020/10/01}{\@pass@ptions}
%<latexrelease>  {Add file replacement in \@pass@ptions}%
%<latexrelease>
%<latexrelease>\def\@pass@ptions#1#2#3{%
%<latexrelease>  \@expl@@@filehook@set@curr@file@@nNN
%<latexrelease>    {\@expl@@@filehook@resolve@file@subst@@w #3.#1\@nil}%
%<latexrelease>      \reserved@a\reserved@b
%<latexrelease>  \@expl@@@filehook@clear@replacement@flag@@
%<latexrelease>  \expandafter\xdef\csname opt@\reserved@a\endcsname{%
%<latexrelease>    \@ifundefined{opt@\reserved@a}\@empty
%<latexrelease>      {\csname opt@\reserved@a\endcsname,}%
%<latexrelease>    \zap@space#2 \@empty}%
%<latexrelease>  \expandafter\let
%<latexrelease>    \csname opt@#3.#1\expandafter\endcsname
%<latexrelease>    \csname opt@\reserved@a\endcsname}
%<latexrelease>\EndIncludeInRelease
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}{\@pass@ptions}
%<latexrelease>  {\@pass@ptions}%
%<latexrelease>
%<latexrelease>\def\@pass@ptions#1#2#3{%
%<latexrelease>  \expandafter\xdef\csname opt@#3.#1\endcsname{%
%<latexrelease>    \@ifundefined{opt@#3.#1}\@empty
%<latexrelease>      {\csname opt@#3.#1\endcsname,}%
%<latexrelease>    \zap@space#2 \@empty}}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\@pass@ptions
%    \end{macrocode}
%
%    \begin{macrocode}
\def\PassOptionsToPackage{\@pass@ptions\@pkgextension}
\def\PassOptionsToClass{\@pass@ptions\@clsextension}
\@onlypreamble\PassOptionsToPackage
\@onlypreamble\PassOptionsToClass
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\DeclareOption}
% \begin{macro}{\DeclareOption*}
%    Adds an option as a |\ds@| command, or the default |\default@ds|
%    command.
% \changes{v0.2c}{1993/11/17}
%         {Error checking added}
% \changes{v1.0m}{1995/04/21}
%         {Made long /1498}
% \changes{v1.0n}{1995/05/12}
%         {Use \cs{toks@} to remove need to double hash /1557}
%    \begin{macrocode}
\def\DeclareOption{%
  \let\@fileswith@pti@ns\@badrequireerror
  \@ifstar\@defdefault@ds\@declareoption}
\long\def\@declareoption#1#2{%
   \xdef\@declaredoptions{\@declaredoptions,#1}%
   \toks@{#2}%
   \expandafter\edef\csname ds@#1\endcsname{\the\toks@}}
\long\def\@defdefault@ds#1{%
  \toks@{#1}%
  \edef\default@ds{\the\toks@}}
\@onlypreamble\DeclareOption
\@onlypreamble\@declareoption
\@onlypreamble\@defdefault@ds
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\OptionNotUsed}
% \changes{v1.3x}{2021/02/18}{filter out =value from unused option list (gh/85)}
% \begin{macro}{\@remove@eq@value}
% \changes{v1.3x}{2021/02/18}{macro added (gh/85)}
% If we are in a class file, add |\CurrentOption| to the list of
% unused options. Otherwise, in a package file do nothing.
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2021/06/01}%
%<latexrelease>                 {\OptionNotUsed}{filter unused option list}%
%<*2ekernel|latexrelease>
\def\@remove@eq@value#1=#2\@nil{#1}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\OptionNotUsed{%
  \ifx\@currext\@clsextension
    \xdef\@unusedoptionlist{%
      \ifx\@unusedoptionlist\@empty\else\@unusedoptionlist,\fi
      \expandafter\@remove@eq@value\CurrentOption=\@nil}%
  \fi}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\OptionNotUsed}{filter unused option list}%
%<latexrelease>\let\@remove@eq@value\@undefined
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\def\OptionNotUsed{%
%<latexrelease>  \ifx\@currext\@clsextension
%<latexrelease>    \xdef\@unusedoptionlist{%
%<latexrelease>      \ifx\@unusedoptionlist\@empty\else\@unusedoptionlist,\fi
%<latexrelease>      \CurrentOption}%
%<latexrelease>  \fi}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\OptionNotUsed
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\default@ds}
% The default option code.
% Set by |\@onefilewithoptions| to either |\OptionNotUsed| for
% classes, or |\@unknownoptionerror| for packages. This may be reset
% in either case with |\DeclareOption*|.
%    \begin{macrocode}
% \let\default@ds\OptionNotUsed
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ProcessOptions}
% \begin{macro}{\ProcessOptions*}
% |\ProcessOptions| calls |\ds@option| for each known package option,
% then calls |\default@ds| for each option on the local options list.
% Finally resets all the declared options to |\relax|. The empty option
% does nothing, this has to be reset on the off chance it's set to
% |\relax| if an empty element gets into the |\@declaredoptions| list.
%
% The star form is similar but executes options given in the order
% specified in the document, not the order they are declared in the
% file. In the case of packages, global options are executed before
% local ones.
% \changes{v0.2a}{1993/11/14}
%         {Stop adding the global option list inside class files.}
% \changes{v0.2a}{1993/11/14}
%         {Optimize `empty option' code.}
% \changes{v0.2b}{1993/11/15}
%         {Star form added.}
% \changes{v0.2c}{1993/11/17}
%         {restoring \cs{@fileswith@pti@ns} added.}
% \changes{v1.5d}{2022/10/10}
%         {Use \cs{protected@edef}.}
%    \begin{macrocode}
\def\ProcessOptions{%
  \let\ds@\@empty
  \protected@edef\@curroptions{\@ptionlist{\@currname.\@currext}}%
  \@ifstar\@xprocess@ptions\@process@ptions}
\@onlypreamble\ProcessOptions
%    \end{macrocode}
%
% \changes{v0.2y}{1994/02/07}
%         {Add extra ,s so `two' is not matched with `twocolumn'}
%    \begin{macrocode}
\def\@process@ptions{%
  \@for\CurrentOption:=\@declaredoptions\do{%
    \ifx\CurrentOption\@empty\else
      \@expandtwoargs\in@{,\CurrentOption,}{%
         ,\ifx\@currext\@clsextension\else\@classoptionslist,\fi
         \@curroptions,}%
      \ifin@
        \@use@ption
        \expandafter\let\csname ds@\CurrentOption\endcsname\@empty
      \fi
    \fi}%
  \@process@pti@ns}
\@onlypreamble\@process@ptions
%    \end{macrocode}
%
% \changes{v0.2y}{1994/02/07}
%         {Add extra ,s so `two' is not matched with `twocolumn'}
% \changes{v1.3z}{2021/03/05}{modify so braces to not give errors (gh/513)}
% \changes{v1.5e}{2022/10/22}{Use \cs{detokenize}}
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2021/06/01}%
%<latexrelease>                 {\@xprocess@ptions}{safer @xprocess@ptions}%
%<*2ekernel|latexrelease>
\def\@xprocess@ptions{%
  \ifx\@currext\@clsextension\else
   \ifx\@classoptionslist\relax\else
    \@for\CurrentOption:=\@classoptionslist\do{%
      \ifx\CurrentOption\@empty\else
        \@ifundefined{ds@\detokenize\expandafter{\CurrentOption}}{}{%
          \@use@ption
          \expandafter\let\csname ds@\CurrentOption\endcsname\@empty
        }%
      \fi}%
    \fi
  \fi
  \@process@pti@ns}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\@xprocess@ptions}{safer @xprocess@ptions}%
%<latexrelease>\let\@remove@eq@value\@undefined
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\def\@xprocess@ptions{%
%<latexrelease>  \ifx\@currext\@clsextension\else
%<latexrelease>    \@for\CurrentOption:=\@classoptionslist\do{%
%<latexrelease>      \ifx\CurrentOption\@empty\else
%<latexrelease>        \@expandtwoargs\in@{,\CurrentOption,}{,\@declaredoptions,}%
%<latexrelease>        \ifin@
%<latexrelease>          \@use@ption
%<latexrelease>          \expandafter\let\csname ds@\CurrentOption\endcsname\@empty
%<latexrelease>        \fi
%<latexrelease>      \fi}%
%<latexrelease>  \fi
%<latexrelease>  \@process@pti@ns}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\@xprocess@ptions
%    \end{macrocode}
%
% The common part of |\ProcessOptions| and |\ProcessOptions*|.
% \changes{v1.5e}{2022/10/22}{Use \cs{detokenize}}
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>                 {\@process@pti@ns}{Unused options issue}%
\def\@process@pti@ns{%
  \@for\CurrentOption:=\@curroptions\do{%
    \@ifundefined{ds@\detokenize\expandafter{\CurrentOption}}%
      {\@use@ption
       \default@ds}%
%    \end{macrocode}
% There should not be any non-empty definition of |\CurrentOption| at
% this point, as all the declared options were executed earlier. This is
% for compatibility with 2.09 styles which use |\def\ds@|\ldots\
% directly, and so have options which do not appear in
% |\@declaredoptions|.
%    \begin{macrocode}
      \@use@ption}%
%    \end{macrocode}
% Clear all the definitions for option code. First set all the declared
% options to |\relax|, then reset the `default' and `empty' options. and
% the lst of declared options.
%    \begin{macrocode}
  \@for\CurrentOption:=\@declaredoptions\do{%
    \expandafter\let\csname ds@\CurrentOption\endcsname\relax}%
%    \end{macrocode}
% \changes{v1.0r}{1995/10/17}
%         {Reset \cs{CurrentOption} for graphics/1873}
% \changes{v1.3k}{2020/04/07}{Use different method to ignore
%    unprocessed options (gh/22)}
%    \begin{macrocode}
  \let\CurrentOption\@empty
  \let\@fileswith@pti@ns\@@fileswith@pti@ns
  \AtEndOfPackage{\expandafter\let
                     \csname unprocessedoptions-\@currname.\@currext\endcsname
                     \relax}}
\@onlypreamble\@process@pti@ns
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\@process@pti@ns}{Unused options issue}%
%<latexrelease>
%<latexrelease>\def\@process@pti@ns{%
%<latexrelease>  \@for\CurrentOption:=\@curroptions\do{%
%<latexrelease>    \@ifundefined{ds@\CurrentOption}%
%<latexrelease>      {\@use@ption
%<latexrelease>       \default@ds}%
%<latexrelease>      \@use@ption}%
%<latexrelease>  \@for\CurrentOption:=\@declaredoptions\do{%
%<latexrelease>    \expandafter\let\csname ds@\CurrentOption\endcsname\relax}%
%<latexrelease>  \let\CurrentOption\@empty
%<latexrelease>  \let\@fileswith@pti@ns\@@fileswith@pti@ns
%<latexrelease>  \AtEndOfPackage{\let\@unprocessedoptions\relax}}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@options}
% |\@options| is a synonym for |\ProcessOptions*| for upward
% compatibility with \LaTeX2.09 style files.
%    \begin{macrocode}
\def\@options{\ProcessOptions*}
\@onlypreamble\@options
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@use@ption}
% Execute the code for the current option.
% \changes{v0.2g}{1993/11/23}
%         {Name changed from \cs{@executeoption}}
% \changes{v1.0e}{1994/05/17}
%         {Execute option after removing from list, not before}
% \changes{v1.3x}{2021/02/18}{filter out =value from unused option list (gh/85)}
% \changes{v1.5e}{2022/10/22}{Use \cs{detokenize}}
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2021/06/01}%
%<latexrelease>                 {\@use@ption}{filter unused option list}%
%<*2ekernel|latexrelease>
\def\@use@ption{%
  \@expandtwoargs\@removeelement
     {\expandafter\@remove@eq@value\CurrentOption=\@nil}%
  \@unusedoptionlist\@unusedoptionlist
  \csname ds@\detokenize\expandafter{\CurrentOption}\endcsname}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\@use@ption}{filter unused option list}%
%<latexrelease>\def\@use@ption{%
%<latexrelease>  \@expandtwoargs\@removeelement\CurrentOption
%<latexrelease>  \@unusedoptionlist\@unusedoptionlist
%<latexrelease>  \csname ds@\CurrentOption\endcsname}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\@use@ption
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ExecuteOptions}
% |\ExecuteOptions{|\meta{option-list}|}| executes the code declared
% for each option.
% \changes{v0.2d}{1993/11/18}
%         {Use \cs{CurrentOption} not \cs{reserved@a}}
% \changes{v0.2k}{1993/12/06}
%         {Preserve \cs{CurrentOption}.}
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2017/01/01}%
%<latexrelease>                 {\ExecuteOptions}{Spaces in \ExecuteOptions}%
%<*2ekernel|latexrelease>
\def\ExecuteOptions#1{%
%    \end{macrocode}
% \changes{v1.2a}{2016/10/02}
%         {Ignore spaces in argument}
% Use |\@fortmp| here as it is anyway cleared during |\@for| loop
% so does not change any existing names.
%    \begin{macrocode}
  \edef\@fortmp{\zap@space#1 \@empty}%
  \def\reserved@a##1\@nil{%
    \@for\CurrentOption:=\@fortmp\do
             {\csname ds@\CurrentOption\endcsname}%
    \edef\CurrentOption{##1}}%
  \expandafter\reserved@a\CurrentOption\@nil}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\ExecuteOptions}{Spaces in \ExecuteOptions}%
%<latexrelease>\def\ExecuteOptions#1{%
%<latexrelease>  \def\reserved@a##1\@nil{%
%<latexrelease>    \@for\CurrentOption:=#1\do
%<latexrelease>             {\csname ds@\CurrentOption\endcsname}%
%<latexrelease>    \edef\CurrentOption{##1}}%
%<latexrelease>  \expandafter\reserved@a\CurrentOption\@nil}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\ExecuteOptions
%    \end{macrocode}
% \end{macro}
%
% The top-level commands, which just set some parameters then call
% the internal command, |\@fileswithoptions|.
% \begin{macro}{\documentclass}
% \changes{v1.0q}{1995/06/19}
%         {Don't redefine \cs{usepackage} in compat mode for /1634}
% The main new-style class declaration.
%    \begin{macrocode}
\def\documentclass{%
  \let\documentclass\@twoclasseserror
  \if@compatibility\else\let\usepackage\RequirePackage\fi
  \@fileswithoptions\@clsextension}
\@onlypreamble\documentclass
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\documentstyle}
% 2.09 style class `style' declaration.
% \changes{v0.2a}{1993/11/14}
%         {Added \cs{RequirePackage} \cs{@unusedoptionlist} stuff.}
% \changes{v0.2b}{1993/11/15}
%         {Modified to match \cs{ProcessOption*}}
% \changes{v0.2d}{1993/11/18}
%         {Modified \cs{RequirePackage} stuff.}
% \changes{v0.2n}{1993/12/09}
%         {input 209 compatibility file.}
% \changes{v0.2o}{1993/12/13}
%         {compatibility file now latex209.sty.}
% \changes{v0.2q}{1993/12/17}
%         {Match Alan's new code.}
% \changes{v0.2u}{1994/01/21}
%         {compatibility file now latex209.def.}
%    \begin{macrocode}
\def\documentstyle{%
  \makeatletter\input{latex209.def}\makeatother
  \documentclass}
\@onlypreamble\documentstyle
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\RequirePackage}
% Load package if not already loaded.
%    \begin{macrocode}
\def\RequirePackage{%
  \@fileswithoptions\@pkgextension}
\@onlypreamble\RequirePackage
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\LoadClass}
% Load class.
%    \begin{macrocode}
\def\LoadClass{%
  \ifx\@currext\@pkgextension
     \@latex@error
      {\noexpand\LoadClass in package file}%
      {You may only use \noexpand\LoadClass in a class file.}%
  \fi
  \@fileswithoptions\@clsextension}
\@onlypreamble\LoadClass
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@loadwithoptions}
% \changes{v1.0t}{1995/11/14}{macro added}
% \changes{v1.4c}{2021/06/06}
%         {handle raw options for gh/580}
% Pass the current option list on to a class or package.
% |#1| is |\@|\emph{cls-or-pkg}|extension|,
% |#2| is |\RequirePackage| or |\LoadClass|,
% |#3| is the class or package to be loaded.
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2021/06/01}%
%<latexrelease>                 {\@loadwithoptions}{Raw option lists load with options}%
%<*2ekernel|latexrelease>
\def\@loadwithoptions#1#2#3{%
  \expandafter\let\csname opt@#3.#1\expandafter\endcsname
       \csname opt@\@currname.\@currext\endcsname
  \expandafter\let\csname @raw@opt@#3.#1\expandafter\endcsname
       \csname @raw@opt@\@currname.\@currext\endcsname
   #2{#3}}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}
%<latexrelease>                 {\@loadwithoptions}{Raw option lists load with options}%
%<latexrelease>\def\@loadwithoptions#1#2#3{%
%<latexrelease>  \expandafter\let\csname opt@#3.#1\expandafter\endcsname
%<latexrelease>       \csname opt@\@currname.\@currext\endcsname
%<latexrelease>   #2{#3}}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\@loadwithoptions
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\LoadClassWithOptions}
% \changes{v1.0t}{1995/11/14}{macro added}
% Load class `|#1|' with the current option list.
%    \begin{macrocode}
\def\LoadClassWithOptions{%
  \@loadwithoptions\@clsextension\LoadClass}
\@onlypreamble\LoadClassWithOptions
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\RequirePackageWithOptions}
% \changes{v1.0t}{1995/11/14}{macro added}
% \changes{v1.0v}{1996/10/04}{Reset \cs{@unprocessedoptions} for /2269}
% Load package `|#1|' with the current option list.
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>                 {\RequirePackageWithOptions}{Unused options issue}%
\def\RequirePackageWithOptions{%
%    \end{macrocode}
%    The resetting of the unprocessed options is now done on a par package basis.
% \changes{v1.3k}{2020/04/07}{Use different method to ignore
%    unprocessed options (gh/22)}
%    \begin{macrocode}
  \AtEndOfPackage{\expandafter\let
                    \csname unprocessedoptions-\@currname.\@currext\endcsname
                    \relax}%
  \@loadwithoptions\@pkgextension\RequirePackage}
\@onlypreamble\RequirePackageWithOptions
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\RequirePackageWithOptions}{Unused options issue}%
%<latexrelease>
%<latexrelease>\def\RequirePackageWithOptions{%
%<latexrelease>  \AtEndOfPackage{\let\@unprocessedoptions\relax}%
%<latexrelease>  \@loadwithoptions\@pkgextension\RequirePackage}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
% \end{macro}
%
%






%
% \begin{macro}{\usepackage}
%    To begin with, |\usepackage| produces an error.  This is reset by
%    |\documentclass|.
% \changes{v0.2o}{1993/12/13}
%         {Fixed error handling}
% \changes{v1.0h}{1994/05/23}{Remove argument if possible}
%    \begin{macrocode}
\def\usepackage#1#{%
  \@latex@error
    {\noexpand \usepackage before \string\documentclass}%
    {\noexpand \usepackage may only appear in the document
      preamble, i.e.,\MessageBreak
      between \noexpand\documentclass and
      \string\begin{document}.}%
  \@gobble}
\@onlypreamble\usepackage
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\NeedsTeXFormat}
% Check that the document is running on the correct system.
% \changes{v0.2a}{1993/11/14}
%         {made more robust for alternative syntax for other formats.}
% \changes{v0.2c}{1993/11/17}
%         {Name changed from \cs{NeedsFormat}}
% \changes{v0.2d}{1993/11/18}
%         {\cs{fmtname} \cs{fmtversion} not \cs{@}\ldots}
%    \begin{macrocode}
\def\NeedsTeXFormat#1{%
  \def\reserved@a{#1}%
  \ifx\reserved@a\fmtname
    \expandafter\@needsformat
  \else
     \@latex@error{This file needs format `\reserved@a'%
       \MessageBreak but this is `\fmtname'}{%
       The current input file will not be processed
       further,\MessageBreak
       because it was written for some other flavor of
       TeX.\MessageBreak\@ehd}%
%    \end{macrocode}
%    If the file is not meant to be processed by \LaTeXe{} we stop
%    inputting it, but we do not end the run. We just end inputting
%    the current file.
% \changes{v1.0h}{1994/05/23}
%     {Don't stop completely when format is wrong}
%    \begin{macrocode}
     \endinput \fi}
\@onlypreamble\NeedsTeXFormat
%    \end{macrocode}
%
%    \begin{macrocode}
\def\@needsformat{%
  \@ifnextchar[%]
    \@needsf@rmat
    {}}
\@onlypreamble\@needsformat
%    \end{macrocode}
%
% \changes{v1.0b}{1994/05/04}
%         {Changed wording of the warning}
%    \begin{macrocode}
\def\@needsf@rmat[#1]{%
    \@ifl@t@r\fmtversion{#1}{}%
    {\@latex@warning@no@line
        {You have requested release `#1' of LaTeX,\MessageBreak
         but only release `\fmtversion' is available}}}
\@onlypreamble\@needsf@rmat
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\zap@space}
% |\zap@space foo|\meta{space}|\@empty| removes all spaces from |foo|
% that are not protected by |{ }| groups.
%    \begin{macrocode}
\def\zap@space#1 #2{%
  #1%
  \ifx#2\@empty\else\expandafter\zap@space\fi
  #2}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@fileswithoptions}
% The common part of |\documentclass| and |\usepackage|.
%    \begin{macrocode}
\def\@fileswithoptions#1{%
  \@ifnextchar[%]
    {\@fileswith@ptions#1}%
    {\@fileswith@ptions#1[]}}
\@onlypreamble\@fileswithoptions
%    \end{macrocode}
%
% \changes{v0.2f}{1993/11/22}
%         {Made the default [] not [\cs{@unknownversion}]}
% \changes{v1.1h}{2007/08/05}
%         {Prevent loss of brackets PR/3965}
%    \begin{macrocode}
\def\@fileswith@ptions#1[#2]#3{%
  \@ifnextchar[%]
  {\@fileswith@pti@ns#1[{#2}]#3}%
  {\@fileswith@pti@ns#1[{#2}]#3[]}}
\@onlypreamble\@fileswith@ptions
%    \end{macrocode}
% Then we do some work.
%
% First of all, we define the global variables.
% Then we look to see if the file has already been loaded.
% If it has, we check that it was first loaded with at least the current
% options.
% If it has not, we add the current options to the package options,
% set the default version to be |0000/00/00|, and load the file if we
% can find it.
% Then we check the version number.
%
% Finally, we restore the old file name, reset the default option,
% and we set the catcode of |@|.
%
% For classes, we can immediately process the file. For other types,
% |#2| could be a comma separated list, so loop through, processing
% each one separately.
% \changes{v0.2q}{1993/12/17}
%         {Add \cs{@compatibility} hook}
% \changes{v0.2s}{1994/01/17}
%         {Modify to reduce parameter stack usage}
% \changes{v0.2y}{1994/02/07}
%         {Run \cs{@compatibility} on the first class to start
%          (not the first to finish) }
% \changes{v0.2z}{1994/02/10}
%         {Renamed \cs{@compatibility} to \cs{@documentclasshook}.
%          ASAJ.}
% \changes{v1.1h}{2007/08/05}
%         {Prevent loss of brackets PR/3965}
% \changes{v2.1b}{2016/11/09}
%         {Improve \cs{ifx} tests PR/4497}
% \changes{v1.3x}{2021/02/18}{save raw class option list (gh/85)}
% \changes{v1.5e}{2022/10/22}{Use \cs{protected@xdef}.}
%    \begin{macrocode}
%</2ekernel>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>        {\@fileswith@pti@ns}{ifx tests in \@fileswith@pti@ns}%
%<*2ekernel|latexrelease>
\def\@fileswith@pti@ns#1[#2]#3[#4]{%
  \ifx#1\@clsextension
    \ifx\@classoptionslist\relax
      \protected@xdef\@classoptionslist{\zap@space#2 \@empty}%
%    \end{macrocode}
% Save raw class list.
%    \begin{macrocode}
      \gdef\@raw@classoptionslist{#2}%
%    \end{macrocode}
%
%    \begin{macrocode}
      \def\reserved@a{%
        \@onefilewithoptions#3[{#2}][{#4}]#1%
        \@documentclasshook}%
    \else
      \def\reserved@a{%
        \@onefilewithoptions#3[{#2}][{#4}]#1}%
    \fi
  \else
%    \end{macrocode}
% build up a list of calls to |\@onefilewithoptions|
% (one for each package) without thrashing the parameter stack.
%    \begin{macrocode}
    \def\reserved@b##1,{%
%    \end{macrocode}
% If |#1| is |\@nnil| we have reached the end of the list
% (older version used |\@nil| here but |\@nil| is undefined so |\ifx|
% equal to all undefined commands)
%    \begin{macrocode}
      \ifx\@nnil##1\relax\else
%    \end{macrocode}
%  If |\ifx\@nnil##1\@nnil| is true then |#1| is (presumably) empty
% (Older code used |\relax| which is slightly easier to get into |#1|
% by mistake, which would spoil this test.)
%    \begin{macrocode}
        \ifx\@nnil##1\@nnil\else
%    \end{macrocode}
%
% \changes{v1.4d}{2021/07/12}{add \cs{unexpanded}}
%    \begin{macrocode}
         \noexpand\@onefilewithoptions##1[{\unexpanded{#2}}][{#4}]%
         \noexpand\@pkgextension
        \fi
        \expandafter\reserved@b
      \fi}%
      \edef\reserved@a{\zap@space#3 \@empty}%
      \edef\reserved@a{\expandafter\reserved@b\reserved@a,\@nnil,}%
  \fi
  \reserved@a}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2017/01/01}%
%<latexrelease>        {\@fileswith@pti@ns}{ifx tests in \@fileswith@pti@ns}%
%<latexrelease>\def\@fileswith@pti@ns#1[#2]#3[#4]{%
%<latexrelease>  \ifx#1\@clsextension
%<latexrelease>    \ifx\@classoptionslist\relax
%<latexrelease>      \xdef\@classoptionslist{\zap@space#2 \@empty}%
%<latexrelease>      \def\reserved@a{%
%<latexrelease>        \@onefilewithoptions#3[{#2}][{#4}]#1%
%<latexrelease>        \@documentclasshook}%
%<latexrelease>    \else
%<latexrelease>      \def\reserved@a{%
%<latexrelease>        \@onefilewithoptions#3[{#2}][{#4}]#1}%
%<latexrelease>    \fi
%<latexrelease>  \else
%<latexrelease>    \def\reserved@b##1,{%
%<latexrelease>      \ifx\@nnil##1\relax\else
%<latexrelease>        \ifx\@nnil##1\@nnil\else
%<latexrelease>         \noexpand\@onefilewithoptions##1[{#2}][{#4}]%
%<latexrelease>         \noexpand\@pkgextension
%<latexrelease>        \fi
%<latexrelease>        \expandafter\reserved@b
%<latexrelease>      \fi}%
%<latexrelease>      \edef\reserved@a{\zap@space#3 \@empty}%
%<latexrelease>      \edef\reserved@a{\expandafter\reserved@b\reserved@a,\@nnil,}%
%<latexrelease>  \fi
%<latexrelease>  \reserved@a}
%    \end{macrocode}
%
%    \begin{macrocode}
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>        {\@fileswith@pti@ns}{ifx tests in \@fileswith@pti@ns}%
%<latexrelease>\def\@fileswith@pti@ns#1[#2]#3[#4]{%
%<latexrelease>  \ifx#1\@clsextension
%<latexrelease>    \ifx\@classoptionslist\relax
%<latexrelease>      \xdef\@classoptionslist{\zap@space#2 \@empty}%
%<latexrelease>      \def\reserved@a{%
%<latexrelease>        \@onefilewithoptions#3[{#2}][{#4}]#1%
%<latexrelease>        \@documentclasshook}%
%<latexrelease>    \else
%<latexrelease>      \def\reserved@a{%
%<latexrelease>        \@onefilewithoptions#3[{#2}][{#4}]#1}%
%<latexrelease>    \fi
%<latexrelease>  \else
%<latexrelease>    \def\reserved@b##1,{%
%<latexrelease>      \ifx\@nil##1\relax\else
%<latexrelease>        \ifx\relax##1\relax\else
%<latexrelease>         \noexpand\@onefilewithoptions##1[{#2}][{#4}]%
%<latexrelease>         \noexpand\@pkgextension
%<latexrelease>        \fi
%<latexrelease>        \expandafter\reserved@b
%<latexrelease>      \fi}%
%<latexrelease>      \edef\reserved@a{\zap@space#3 \@empty}%
%<latexrelease>      \edef\reserved@a{%
%<latexrelease>        \expandafter\reserved@b\reserved@a,\@nil,}%
%<latexrelease>  \fi
%<latexrelease>  \reserved@a}
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\@fileswith@pti@ns
%    \end{macrocode}
%
% \begin{macro}{\load@onefilewithoptions}
%   This macro is used when loading packages or classes.
%
% Have the main argument as |#1|, so we only need one |\expandafter|
% above.
% \changes{v0.2a}{1993/11/14}
%         {Moved resetting of \cs{default@ds}, \cs{ds@} and
%         \cs{@declaredoptions} here, from the end of
%         \cs{ProcessOptions}.}
% \changes{v0.2f}{1993/11/22}
%         {Made the initial version [] not [\cs{@unknownversion}]}
% \changes{v0.2m}{1993/12/07}
%         {Reset \cs{CurrentOption}}
% \changes{v1.3d}{2019/10/18}{Initialize \cs{...-h@@k} only when loading
%                             the package or class (gh/198)}
% \changes{v1.5h}{2023/04/14}{Define \cs{load@onefilewithoptions} when
%                             in \pkg{latexrelease} (gh/992)}
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>      {\@onefilewithoptions}{Hooks and unused options issue}%
%    \end{macrocode}
%
%   Here this macro is called \cs{@onefilewithoptions}, but further
%   ahead in this file it is renamed to \cs{load@onefilewithoptions},
%   and \cs{@onefilewithoptions} becomes a wrapper around this, used for
%   bookkeeping when rolling back.  Therefore, when in
%   \pkg{latexrelease}, we need to define \cs{load@onefilewithoptions}
%   instead, thus the extra guarded \cs{def} line below:
%    \begin{macrocode}
%<*2ekernel>
\def\@onefilewithoptions#1[#2][#3]#4{%
%</2ekernel>
%<latexrelease>\def\load@onefilewithoptions#1[#2][#3]#4{%
%    \end{macrocode}
%
%    We have to sanitise file names, so that something like
% \begin{verbatim}
%   \usepackage{some/local/path/array}
%   \usepackage{array}
% \end{verbatim}
%    won't load |array.sty| twice.  It is remotely possible that
%    those are two different files, but as a matter of principles, we
%    will consider that the base file name uniquely identifies a
%    package, regardless of where it lives.  This assumption already
%    holds for file hooks, for example, which address the hook to a file
%    by its base name only.
%
%    We'll use \cs{@expl@@@filehook@set@curr@file@@nNN} to parse the
%    file name and return the \meta{path} and \meta{base+ext} in
%    separate token lists.  Further ahead, most operations use
%    \cs{@currname} which doesn't have a path attached to it;  only few
%    actions prepend \cs{@currpath} to \cs{@currname} (namely loading,
%    as we have to respect the given path).
%
%    A file substitution isn't followed just yet because at this point
%    we are parsing user input, so the file is still what the user
%    asked for, and not the file actually loaded.
%    \begin{macrocode}
  \@expl@@@filehook@set@curr@file@@nNN{#1.#4}\reserved@a\reserved@b
  \edef\reserved@c{\def\noexpand\reserved@c####1%
    \detokenize\expandafter{\expanded{.#4}}%
    \noexpand\@nil{\def\noexpand\reserved@a{####1}}}\reserved@c
  \expandafter\reserved@c\reserved@a\@nil
  \@pushfilename
  \xdef\@currname{\string@makeletter\reserved@a}%
  \xdef\@currpath{\ifx\reserved@b\@empty\else\reserved@b/\fi}%
  \global\let\@currext#4%
%    \end{macrocode}
%    The command \cs{ver@\meta{file}.\meta{ext}} is used to signal that
%    a package is already loaded, either because it is in fact loaded, or
%    because it's loading was suppressed.  In minimal installations, said
%    package may not exist but still have its loading suppressed with
%    \cs{ver@\meta{file}.\meta{ext}}, so before checking if the file
%    exists we have to check that we do need to load it with
%    \cs{@ifl@aded}.  If we don't, then there's no point in checking for
%    a typo or load-disabling.
%    \begin{macrocode}
  \@ifl@aded\@currext\@currname
%    \end{macrocode}
% \changes{v1.5b}{2022/03/18}{Switch to \cs{ProcessKeyOptions}}
% \changes{v1.5c}{2022/06/20}{Pass raw options to \cs{ProcessKeyOptions}}
% \changes{v1.5e}{2022/10/20}
%         {Define key option handler in \pkg{ltkeys}}
%    In the current preferred approach, a key family name will exist for
%    processing using \pkg{ltkeys}. In that case, we replace the previous
%    package options with the new ones, then call the key handler.
%    Otherwise, we use the more classical clash handler.
%    \begin{macrocode}
    {%
      \@ifundefined{opt@handler@\@currname.\@currext}
        {\@onefilewithoptions@clashchk{#2}}
        {%
%    \end{macrocode}
% \changes{v1.5d}{2022/10/10}{Use \cs{protected@edef}.}
%    \begin{macrocode}
          \expandafter\protected@edef\csname opt@\@currname.\@currext\endcsname
            {\zap@space#2 \@empty}%
          \@namedef{@raw@opt@\@currname.\@currext}{#2}%
          \@nameuse{opt@handler@\@currname.\@currext}%
        }%
    }%
    {\makeatletter
%    \end{macrocode}
%    The next line seems to be necessary for 2.09 compatibility (the
%    way the code is written there) This seems questionable and should be
%    look at as in 2e it is definitely unnecessary at this point!
%    \begin{macrocode}
     \@reset@ptions
%    \end{macrocode}
%    First we take the \meta{name} and \meta{ext} given in the argument
%    and check if the file exists, and issue an error otherwise asking
%    for a correction with \cs{@missingfileerror}.  For checking if the
%    file exists we use \cs{@currpath} (usually empty) before
%    \cs{@currname}.
%    \begin{macrocode}
     \IfFileExists{\@currpath\@currname.\@currext}{}%
       {\@missing@onefilewithoptions{#2}}%
%    \end{macrocode}
%    If \cs{@currname} is empty (the user replied to the ``Enter file
%    name'' prompt with \meta{RETURN}), so stop here
%    (do \cs{@popfilename} to pop the item just added above).
%
%    This \cs{@gobble} omits the date check at the end.
%    \begin{macrocode}
     \ifx\@currname\@empty
       \expandafter\@gobble
     \else
%    \end{macrocode}
%    If the file exists, check if it was load-prevented, and otherwise
%    do the bookkeeping with \cs{@filehook@file@push}
%    then call \cs{set@curr@file} to set \cs{@curr@file} (and do any
%    required substitution), then actually load the class/package with
%    \cs{load@onefile@withoptions}.  \cs{set@curr@file} also needs the
%    file path.
%    \begin{macrocode}
       \@disable@packageload@do{\@currname.\@currext}%
         {\@expl@@@filehook@file@push@@
          \set@curr@file{\@currpath\@currname.\@currext}%
          \@filehook@set@CurrentFile
%    \end{macrocode}
%    \changes{v1.3q}{2020/09/06}
%         {Save \cs{@currpkg@reqd} so that we don't lose track of
%          package substitutions.}
%    The \cs{set@curr@file} line above might have replaced the file, so
%    \cs{@currname} and \cs{@currext} may no longer hold the actual
%    package being loaded, so in that case we need to update these two
%    token lists (\cs{@curr@file} holds the file name after replacement,
%    so we parse that).
%
%    The requested file is saved in \cs{@currpkg@reqd} to be used in
%    \cs{InputIfFileExists} later:  if the updated \cs{@currname} and
%    \cs{@currext} are used we lose track of the substitution, so
%    \cs{CurrentFile} and \cs{CurrentFileUsed} will be (incorrectly)
%    the same.
%
%    \changes{v1.3t}{2020-10-11}{Restore \cs{@currpkg@reqd} after
%      finished loading a package file (gh/408).}
%    \begin{macrocode}
          \expandafter\@swaptwoargs\expandafter
            {\expandafter{\@currpkg@reqd}}%
            {% <
%    \end{macrocode}
%    \cs{@currpkg@reqd} doesn't take a path because it is used later to
%    assign \cs[no-index]{opt@...} and \cs[no-index]{ver@...}.
%    \begin{macrocode}
          \edef\@currpkg@reqd{\@currname.\@currext}%
          \ifx\CurrentFile\CurrentFileUsed
          \else
            \filename@parse\@curr@file
            \edef\@currpath{\string@makeletter\filename@area}%
            \edef\@currname{\string@makeletter\filename@base}%
            \edef\@currext{\string@makeletter\filename@ext}%
          \fi
          \load@onefile@withoptions{#2}%
          \def\@currpkg@reqd%{\@currpkg@reqd}
            }% >
%    \end{macrocode}
%    Now just clean up and exit.
%    \begin{macrocode}
          \@expl@@@filehook@file@pop@@}%
       \expandafter\@firstofone
     \fi}%
%    \end{macrocode}
%   Except in the case where \cs{@currname} is empty, the date is
%   checked against the date marked in the package file:
%    \begin{macrocode}
    {\@ifl@ter\@currext{\@currname}{#3}{}%
      {\@latex@warning@no@line
        {You have requested,\on@line,
         version\MessageBreak
           `#3' of \@cls@pkg\space \@currname,\MessageBreak
         but only version\MessageBreak
          `\csname ver@\@currname.\@currext\endcsname'\MessageBreak
         is available}}%
%    \end{macrocode}
% \changes{v0.2c}{1993/11/17}
%         {Added trap for two \cs{LoadClass} commands.}
%    \begin{macrocode}
     \ifx\@currext\@clsextension\let\LoadClass\@twoloadclasserror\fi}%
    \@popfilename
    \@reset@ptions}
%    \end{macrocode}
%
% \begin{macro}{\@onefilewithoptions@clashchk}
%    If the package is already loaded, check that there were no option
%    clashes.
% \changes{v1.1b}{1998/05/07}
%         {Modify help message for latex/2805}
% \changes{v1.5a}{2021/11/30}
%         {Separated out from \cs{@onefilewithoptions}}
%    \begin{macrocode}
\def\@onefilewithoptions@clashchk#1{%
  \@if@ptions\@currext{\@currname}{#1}{}%
      {\@latex@error
        {Option clash for \@cls@pkg\space \@currname}%
        {The package \@currname\space has already been loaded
         with options:\MessageBreak
         \space\space[\@ptionlist{\@currname.\@currext}]\MessageBreak
         There has now been an attempt to load it
          with options\MessageBreak
         \space\space[#1]\MessageBreak
         Adding the global options:\MessageBreak
         \space\space
              \@ptionlist{\@currname.\@currext},#1\MessageBreak
         to your \noexpand\documentclass declaration may fix this.%
         \MessageBreak
         Try typing \space <return> \space to proceed.}}%
     \@firstofone}
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\let\@currpkg@reqd\@empty
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\@onefilewithoptions
%    \end{macrocode}
%
%    The kernel no longer uses \cs{@unprocessedoptions}
%    \begin{macrocode}
\let\@unprocessedoptions\@undefined
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@missing@onefilewithoptions}
%    Now the action taken when a file is not found.  Path must be
%    included here as it eventually leads to a file lookup.
%    \begin{macrocode}
\def\@missing@onefilewithoptions#1{%
  \@missingfileerror{\@currpath\@currname}\@currext
  \global\let\@currpath\@missingfile@area
  \global\let\@currname\@missingfile@base
  \global\let\@currext\@missingfile@ext}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\load@onefile@withoptions}
%    Now the code that actually does the file loading:
%    \begin{macrocode}
\def\load@onefile@withoptions#1{%
  \let\CurrentOption\@empty
  \@reset@ptions
%    \end{macrocode}
% Grab everything in a macro, so the parameter stack is popped before
% any processing begins.
% \changes{v0.2s}{1994/01/17}
%         {Modify to reduce parameter stack usage}
%    \begin{macrocode}
  \def\reserved@a{%
    \@pass@ptions\@currext{#1}{\@currname}%
%    \end{macrocode}
% \changes{v1.3u}{2020/11/20}
%         {Copy option list to the requested package.}
% \changes{v1.4c}{2021/06/06}
%         {Copy raw options for gh/580}
%    \begin{macrocode}
    \expandafter\let
      \csname opt@\@currpkg@reqd\expandafter\endcsname
      \csname opt@\@currname.\@currext\endcsname
    \expandafter\let
      \csname @raw@opt@\@currpkg@reqd\expandafter\endcsname
      \csname @raw@opt@\@currname.\@currext\endcsname
    \global\expandafter
    \let\csname ver@\@currname.\@currext\endcsname\@empty
%    \end{macrocode}
%    We initialize \cs{...-h@@k} here and only if we load the file so that it
%    remains undefined otherwise.
%    \begin{macrocode}
    \expandafter\let\csname\@currname.\@currext-h@@k\endcsname\@empty
%    \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.
% \changes{v1.4e}{2021/07/23}{Make class/name/before a one-time hook}
% \changes{v1.4e}{2021/07/23}{Make package/name/before a one-time hook}
%    \begin{macrocode}
%-----------------------------------------
    \ifx\@currext\@pkgextension
      \UseHook{package/before}%
      \UseOneTimeHook{package/\@currname/before}%
    \else
      \ifx\@currext\@clsextension
        \UseHook{class/before}%
        \UseOneTimeHook{class/\@currname/before}%
      \fi
    \fi
%    \end{macrocode}
%    Now actually load the file (at this point we are certain it exists,
%    but use \cs{InputIfFileExists} so that file hooks are executed).
%    \cs{@currpath} is needed here too.
%    \begin{macrocode}
    \InputIfFileExists{\@currpath\@currpkg@reqd}{}%
      {\@latex@error
        {The \@cls@pkg\space\@currpkg@reqd\space failed to load}\@ehd}%
%-----------------------------------------
%    \end{macrocode}
%    In older versions of the code |\@unprocessedoptions| would
%    generate an error for each specified
%    option in a package unless a |\ProcessOptions| has appeared in the
%    package file.
% \changes{v0.2v}{1994/01/29}
%         {All options raise error if no \cs{ProcessOptions} appears}
% \changes{v0.2x}{1994/02/02}
%         {Only run the hook and options check if the file was
%    loaded.}
%
%    This has changed in 2020. We now use a separate macro per package
%    to avoid interference in case of nested packages.  The whole
%    code for handling this issue (GitHub 22) was provided by Hironobu
%    Yamashita, thanks for that.
% \changes{v1.3k}{2020/04/07}{Use different method to ignore
%    unprocessed options (gh/22)}
%    \begin{macrocode}
    \expandafter\let\csname unprocessedoptions-\@currname.\@currext\endcsname
                    \@@unprocessedoptions
    \csname\@currname.\@currext-h@@k\endcsname
    \expandafter\let\csname\@currname.\@currext-h@@k\endcsname
              \@undefined
%    \end{macrocode}
%    Catch the case where the packages has handled the options and
%    redefined \cs{@unprocessedoptions} to \cs{relax} (old interface).
%    In that case no error should be produced.
% \changes{v1.3k}{2020/04/07}{Use different method to ignore
%    unprocessed options (gh/22)}
%    \begin{macrocode}
    \ifx\@unprocessedoptions\relax
      \let\@unprocessedoptions\@undefined
%    \end{macrocode}
%    Otherwise run the per package set of unused options.
%    \begin{macrocode}
    \else
      \csname unprocessedoptions-\@currname.\@currext\endcsname
    \fi
%    \end{macrocode}
%    In either case we drop the macro afterwards as it is no longer needed.
%    \begin{macrocode}
    \expandafter\let
        \csname unprocessedoptions-\@currname.\@currext\endcsname
       \@undefined
%    \end{macrocode}
%    And same procedure, James, when we are finished loading, except
%    that the hook order is now reversed.
% \changes{v1.4e}{2021/07/23}{Make class/name/after a one-time hook}
% \changes{v1.4e}{2021/07/23}{Make package/name/after a one-time hook}
%    \begin{macrocode}
%-----------------------------------------
    \ifx\@currext\@pkgextension
      \UseOneTimeHook{package/\@currname/after}%
      \UseHook{package/after}%
    \else
      \ifx\@currext\@clsextension
        \UseOneTimeHook{class/\@currname/after}%
        \UseHook{class/after}%
      \fi
    \fi}%
%-----------------------------------------
  \@ifl@aded\@currext\@currname{}{\reserved@a}}
%    \end{macrocode}
%
% \changes{v1.4f}{2021/08/25}{Declare non-generic package and class hooks}
%   Now declare the non-generic package and class hooks used above:
%    \begin{macrocode}
\NewHook{package/before}
\NewHook{class/before}
\NewReversedHook{package/after}
\NewReversedHook{class/after}
%    \end{macrocode}
%  \end{macro}
%
%    \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>      {\@onefilewithoptions}{Hooks and unused options issue}%
%<latexrelease>
%    \end{macrocode}
%    Because of the way \cs{@onfilewithoptions} is changed for
%    rollback handling below we have to define
%    \cs{load@onefilewithoptions} when rolling back!
%    \begin{macrocode}
%<latexrelease>\def\load@onefilewithoptions#1[#2][#3]#4{%
%<latexrelease>  \@pushfilename
%<latexrelease>  \xdef\@currname{#1}%
%<latexrelease>  \global\let\@currext#4%
%<latexrelease>  \let\CurrentOption\@empty
%<latexrelease>  \@reset@ptions
%<latexrelease>  \makeatletter
%<latexrelease>  \def\reserved@a{%
%<latexrelease>    \@ifl@aded\@currext{#1}%
%<latexrelease>      {\@if@ptions\@currext{#1}{#2}{}%
%<latexrelease>        {\@latex@error
%<latexrelease>            {Option clash for \@cls@pkg\space #1}%
%<latexrelease>            {The package #1 has already been loaded
%<latexrelease>             with options:\MessageBreak
%<latexrelease>             \space\space[\@ptionlist{#1.\@currext}]\MessageBreak
%<latexrelease>             There has now been an attempt to load it
%<latexrelease>              with options\MessageBreak
%<latexrelease>             \space\space[#2]\MessageBreak
%<latexrelease>             Adding the global options:\MessageBreak
%<latexrelease>             \space\space
%<latexrelease>                  \@ptionlist{#1.\@currext},#2\MessageBreak
%<latexrelease>             to your \noexpand\documentclass declaration may fix this.%
%<latexrelease>             \MessageBreak
%<latexrelease>             Try typing \space <return> \space to proceed.}}}%
%<latexrelease>      {\@pass@ptions\@currext{#2}{#1}%
%<latexrelease>       \global\expandafter
%<latexrelease>       \let\csname ver@\@currname.\@currext\endcsname\@empty
%<latexrelease>       \expandafter\let\csname\@currname.\@currext-h@@k\endcsname\@empty
%<latexrelease>       \InputIfFileExists
%<latexrelease>         {\@currname.\@currext}%
%<latexrelease>         {}%
%<latexrelease>         {\@missingfileerror\@currname\@currext}%
%<latexrelease>    \let\@unprocessedoptions\@@unprocessedoptions
%<latexrelease>    \csname\@currname.\@currext-h@@k\endcsname
%<latexrelease>    \expandafter\let\csname\@currname.\@currext-h@@k\endcsname
%<latexrelease>              \@undefined
%<latexrelease>    \@unprocessedoptions}%
%<latexrelease>    \@ifl@ter\@currext{#1}{#3}{}%
%<latexrelease>      {\@latex@warning@no@line
%<latexrelease>         {You have requested,\on@line,
%<latexrelease>          version\MessageBreak
%<latexrelease>            `#3' of \@cls@pkg\space #1,\MessageBreak
%<latexrelease>          but only version\MessageBreak
%<latexrelease>           `\csname ver@#1.\@currext\endcsname'\MessageBreak
%<latexrelease>          is available}}%
%<latexrelease>    \ifx\@currext\@clsextension\let\LoadClass\@twoloadclasserror\fi
%<latexrelease>    \@popfilename
%<latexrelease>    \@reset@ptions}%
%<latexrelease>  \reserved@a}
%<latexrelease>
%<latexrelease>\let \load@onefile@withoptions    \@undefined
%<latexrelease>\let \@missing@onefilewithoptions \@undefined
%<latexrelease>
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
% \end{macro}
%
%
%
%
%
%
% \begin{macro}{\@@fileswith@pti@ns}
% Save the definition (for error checking).
% \changes{v0.2c}{1993/11/17}
%         {Macro added}
%    \begin{macrocode}
\let\@@fileswith@pti@ns\@fileswith@pti@ns
\@onlypreamble\@@fileswith@pti@ns
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@reset@ptions}
% Reset the default option, and clear lists of declared options.
% \changes{v0.2a}{1993/11/14}{macro added}
%    \begin{macrocode}
\def\@reset@ptions{%
  \global\ifx\@currext\@clsextension
    \let\default@ds\OptionNotUsed
   \else
    \let\default@ds\@unknownoptionerror
  \fi
  \global\let\ds@\@empty
  \global\let\@declaredoptions\@empty}
\@onlypreamble\@reset@ptions
%    \end{macrocode}
% \end{macro}
%
%
%
%
% \subsection{Hooks}
%
% Allow code to be saved to be executed at specific later times.
%
% Save things in macros, I considered using toks registers, (and
% |\addto@hook| from the NFSS code, that would require stacking the
% contents in the case of required packages, so just generate a new
% macro for each package.
% \begin{macro}{\@begindocumenthook}
% \changes{v1.0s}{1995/10/20}
%         {Make setting conditional, for autoload version}
% \begin{macro}{\@enddocumenthook}
% Stuff to appear at the beginning or end of the document.
%    \begin{macrocode}
\ifx\@begindocumenthook\@undefined
  \let\@begindocumenthook\@empty
\fi
\let\@enddocumenthook\@empty
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\AtEndOfPackage}
% \begin{macro}{\AtEndOfClass}
% \begin{macro}{\AtBeginDocument}
% \begin{macro}{\AtEndDocument}
% The access functions.
% \changes{v0.2a}{1993/11/14}
%         {Included extension in the generated macro name for package
%         and class hooks.}
%    \begin{macrocode}
\def\AtEndOfPackage{%
  \expandafter\g@addto@macro\csname\@currname.\@currext-h@@k\endcsname}
\let\AtEndOfClass\AtEndOfPackage
\@onlypreamble\AtEndOfPackage
\@onlypreamble\AtEndOfClass
%    \end{macrocode}
%
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>                 {\AtBeginDocument}{Use hook system}%
\DeclareRobustCommand\AtBeginDocument{\AddToHook{begindocument}}
\DeclareRobustCommand\AtEndDocument  {\AddToHook{enddocument}}
%\DeclareRobustCommand\AtEndDocument {\AddToHook{env/document/end}} % alternative impl
%    \end{macrocode}
%
%    \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>                 {\AtBeginDocument}{Use hook system}%
%<latexrelease>
%<latexrelease>\DeclareRobustCommand\AtBeginDocument{\g@addto@macro\@begindocumenthook}
%<latexrelease>\DeclareRobustCommand\AtEndDocument{\g@addto@macro\@enddocumenthook}
%<latexrelease>
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%    \begin{macrocode}
\@onlypreamble\AtBeginDocument
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
% \begin{macro}{\@cls@pkg}
%    The current file type.
% \changes{v0.2i}{1993/12/03}
%         {Name changed to avoid clash with output routine.}
%    \begin{macrocode}
\def\@cls@pkg{%
  \ifx\@currext\@clsextension
    document class%
  \else
    package%
  \fi}
\@onlypreamble\@cls@pkg
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@unknownoptionerror}
% Bad option.
%    \begin{macrocode}
\def\@unknownoptionerror{%
  \@latex@error
    {Unknown option `\CurrentOption' for \@cls@pkg\space`\@currname'}%
    {The option `\CurrentOption' was not declared in
     \@cls@pkg\space`\@currname', perhaps you\MessageBreak
      misspelled its name.
     Try typing \space <return>
     \space to proceed.}}
\@onlypreamble\@unknownoptionerror
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@unprocessedoptions}
% Declare an error for each option, unless a |\ProcessOptions| occurred.
% \changes{v0.2v}{1994/01/29}
%         {Macro added.}
% \changes{v1.0t}{1995/11/14}{Allow empty option}
% \changes{v1.5d}{2022/10/10}{Use \cs{protected@edef}.}
%    \begin{macrocode}
\def\@@unprocessedoptions{%
  \ifx\@currext\@pkgextension
    \protected@edef\@curroptions{\@ptionlist{\@currname.\@currext}}%
    \@for\CurrentOption:=\@curroptions\do{%
        \ifx\CurrentOption\@empty\else\@unknownoptionerror\fi}%
  \fi}
\@onlypreamble\@unprocessedoptions
\@onlypreamble\@@unprocessedoptions
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@badrequireerror}
% |\RequirePackage| or |\LoadClass| occurs in the options section.
% \changes{v0.2c}{1993/11/17}
%         {Macro added}
%    \begin{macrocode}
\def\@badrequireerror#1[#2]#3[#4]{%
  \@latex@error
    {\noexpand\RequirePackage or \noexpand\LoadClass
         in Options Section}%
    {The \@cls@pkg\space `\@currname' is defective.\MessageBreak
     It attempts to load `#3' in the options section, i.e.,\MessageBreak
     between \noexpand\DeclareOption and \string\ProcessOptions.}}
\@onlypreamble\@badrequireerror
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@twoloadclasserror}
% Two |\LoadClass| in a class.
% \changes{v0.2c}{1993/11/17}
%         {Macro added}
%    \begin{macrocode}
\def\@twoloadclasserror{%
  \@latex@error
    {Two \noexpand\LoadClass commands}%
    {You may only use one \noexpand\LoadClass in a class file}}
\@onlypreamble\@twoloadclasserror
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@twoclasseserror}
% Two |\documentclass| or |\documentstyle|.
% \changes{v0.2h}{1993/11/28}
%         {Macro added}
%    \begin{macrocode}
\def\@twoclasseserror#1#{%
  \@latex@error
    {Two \noexpand\documentclass or \noexpand\documentstyle commands}%
    {The document may only declare one class.}\@gobble}
\@onlypreamble\@twoclasseserror
%    \end{macrocode}
% \end{macro}
%
% \subsection{Providing shipment}
%
% \begin{macro}{\two@digits}
% Prefix a number less than 10 with `0'.
%    \begin{macrocode}
\def\two@digits#1{\ifnum#1<10 0\fi\number#1}
%    \end{macrocode}
% \end{macro}
%
%  \begin{environment}{filecontents}
%  \begin{macro}{\filecontents}
%  \begin{macro}{\endfilecontents}
%    This environment implements inline files.
%    The star-form does not write extra comments into the file.
%
% \changes{v0.2h}{1993/11/28}
%         {Don't globally allocate a write stream (always use 15)}
% \changes{v0.2r}{1993/12/19}{Different message when ignoring a file}
% \changes{v0.3g}{1994/04/11}
%         {Add star form,
%          don't write \cs{endinput} at the end of the file.}
% \changes{v1.0c}{1994/05/11}
%         {Add checks for form feed and tab}
% \changes{v1.0m}{1995/04/21}
%         {Close input check stream: latex/1487}
% \changes{v1.0p}{1995/05/25}{Delete \cs{filec@ntents} after preamble}
% \changes{v1.3a}{2019/07/01}{Support UTF8 and spaces in
%                             filecontents environment file name}
% \changes{v1.3b}{2019/08/27}{Make various commands robust}
% \changes{v1.3c}{2019/09/11}{Support optional argument for filecontents}
% \changes{v1.3f}{2020/01/05}{Support more write streams in LuaTeX gh/238}
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease>                 {\filec@ntents}{Define \q@curr@file directly (gh/220)}%
%
%    \end{macrocode}
%    We use |@tempswa| to mean no preamble writing and reuse |@filesw|
%    to indicate no overwriting:
%    \begin{macrocode}
\def\filecontents{\@tempswatrue\@fileswtrue
  \@ifnextchar[\filec@ntents@opt\filec@ntents
}
\@namedef{filecontents*}{\@tempswafalse\@fileswtrue
  \@ifnextchar[\filec@ntents@opt\filec@ntents
}
%    \end{macrocode}
%    To handle the optional argument we execute for each option the
%    command \cs{filec@ntents@OPTION} if it exist or complain about
%    unknown option.
% \changes{v1.3h}{2020/01/28}{Allow spaces in option string and display
%     only unknown options not the whole option list (gh/256)}
% \changes{v1.5f}{2022/11/16}{Introduce key 'nowarn' on filecontents (gh/958)}
%    \begin{macrocode}
\def\filec@ntents@opt[#1]{%
  \edef\@fortmp{\zap@space#1 \@empty}%
  \@for\reserved@a:=\@fortmp\do{%
    \ifcsname filec@ntents@\reserved@a\endcsname
      \csname filec@ntents@\reserved@a\endcsname
    \else
    \@latex@error{Unknown filecontents option \reserved@a}%
       {Valid options are force (or overwrite), nosearch, noheader, nowarn}%
    \fi}%
  \filec@ntents
}
%    \end{macrocode}
%    Option \texttt{force} (or \texttt{overwrite}) changes the
%    overwriting switch
%    \begin{macrocode}
\let\filec@ntents@force\@fileswfalse
\let\filec@ntents@overwrite\@fileswfalse  % alternative name
%    \end{macrocode}
%    and option \texttt{noheader} the preamble switch (which is
%    equivalent to using the star form of the environment).
%    \begin{macrocode}
\let\filec@ntents@noheader\@tempswafalse
%    \end{macrocode}
%    Option \texttt{nosearch} only checks the current directory not
%    the whole \TeX{} tree for the existence of the file to write.
%    \begin{macrocode}
\def\filec@ntents@nosearch{%
  \let\filec@ntents@checkdir\@currdir
  \def\filec@ntents@where{in current directory}}
%    \end{macrocode}
%    By default we search the whole tree:
%    \begin{macrocode}
\let\filec@ntents@checkdir\@empty
\def\filec@ntents@where{exists on the system}
%    \end{macrocode}
%    Option \texttt{nowarn} does not show any warning on the terminal
%    but still writes it to the \texttt{.log}.
% \changes{v1.5f}{2022/11/16}{Introduce key 'nowarn' on filecontents (gh/958)}
%    \begin{macrocode}
\def\filec@ntents@nowarn{%
  \let\filec@ntents@warning\@latex@note@no@line
}
%    \end{macrocode}
%    By default we show terminal warnings.
%    \begin{macrocode}
\let\filec@ntents@warning\@latex@warning@no@line
%    \end{macrocode}
%
%    \begin{macrocode}
\begingroup%
\@tempcnta=1
\loop
  \catcode\@tempcnta=12  %
  \advance\@tempcnta\@ne %
\ifnum\@tempcnta<32      %
\repeat                  %
\catcode`\*=11 %
\catcode`\^^M\active%
\catcode`\^^L\active\let^^L\relax%
\catcode`\^^I\active%
%    \end{macrocode}
%
% \changes{v1.3m}{2020-08-08}{define \cs{q@curr@file} directly as the
%    quotes have already been removed (gh/220)}
%    \begin{macrocode}
\gdef\filec@ntents#1{%
  \set@curr@file{\filec@ntents@checkdir#1}%
  \edef\q@curr@file{"\@curr@file"}%
%    \end{macrocode}
%
% Lua\TeX\ has more writes (and 18 is safe here).
% \changes{v1.4b}{2021/06/09}{Use \cs{@latex@note@no@line} to display the information}
%    \begin{macrocode}
  \chardef\reserved@c\ifx\directlua\@undefined 15 \else 127 \fi%
  \openin\@inputcheck\q@curr@file \space %
  \ifeof\@inputcheck%
    \@latex@note@no@line%
        {Writing file `\@currdir\@curr@file'}%
%    \end{macrocode}
%
% \changes{v1.0y}{1997/10/10}
%         {\cs{reserved@c} not \cs{verbatim@out} to save a csname}
%    \begin{macrocode}
    \ch@ck7\reserved@c\write\relax%
    \immediate\openout\reserved@c\q@curr@file\relax%
  \else%
%    \end{macrocode}
%
% \changes{v1.0y}{1997/10/10}
%         {Use \cs{@gobbletwo}}
% \changes{v1.4b}{2021/06/09}{Use \cs{@latex@note@no@line} to display the information}
%    \begin{macrocode}
    \if@filesw%
      \@latex@note@no@line%
          {File `\@curr@file' already \filec@ntents@where.\MessageBreak%
             Not generating it from this source}%
      \let\write\@gobbletwo%
      \let\closeout\@gobble%
    \else%
%    \end{macrocode}
%    If we are overwriting, we try to make sure that the user is not
%    by mistake overwriting the input file (\cs{jobname}). Of course,
%    this only works for input files ending in \texttt{.tex}. If a
%    different extension is used there is no way to see that we are
%    overwriting ourselves!
% \changes{v1.3y}{2021/03/03}
%         {Fix overwrite check for files with UTF-8 (gh/415)}
%    \begin{macrocode}
      \edef\reserved@b{\detokenize\expandafter{\jobname}}%
      \ifx\@curr@file\reserved@b%
        \@fileswtrue%
      \else%
        \edef\reserved@b{\reserved@b\detokenize{.tex}}%
        \ifx\@curr@file\reserved@b
          \@fileswtrue%
        \fi%
      \fi%
%    \end{macrocode}
%    We allocate a write channel but we open it only if it is
%    (hopefully) safe. If not opened that means we are going to write
%    on the terminal.
% \changes{v1.3g}{2020/01/27}{Fix typo in error message}
% \changes{v1.3j}{2020/02/20}{Fix missing quotes around file name (gh/284)}
% \changes{v1.5f}{2022/11/16}{Introduce key 'nowarn' on filecontents (gh/958)}
% \changes{v1.5f}{2022/11/16}{Do not show "current dir" in message (gh/917)}
%    \begin{macrocode}
      \ch@ck7\reserved@c\write\relax%
      \if@filesw%  % Foul ... trying to overwrite \jobname!
      \@latex@error{Trying to overwrite `\jobname.tex'}{You can't %
        write to the file you are reading from!\MessageBreak%
        Data is written to screen instead.}%
      \else%
        \filec@ntents@warning%
           {Writing or overwriting file `\@curr@file'}%
        \immediate\openout\reserved@c\q@curr@file\relax%
      \fi%
    \fi%
  \fi%
%    \end{macrocode}
%    Closing the \cs{@inputcheck} is done here to avoid having to do
%    this in each branch.
%    \begin{macrocode}
  \closein\@inputcheck%
  \if@tempswa%
%    \end{macrocode}
%
% \changes{v1.0y}{1997/10/10}
%         {\cs{@currenvir} in banner}
%    \begin{macrocode}
    \immediate\write\reserved@c{%
      \@percentchar\@percentchar\space%
          \expandafter\@gobble\string\LaTeX2e file `\@curr@file'^^J%
      \@percentchar\@percentchar\space  generated by the %
        `\@currenvir' \expandafter\@gobblefour\string\newenvironment^^J%
      \@percentchar\@percentchar\space from source `\jobname' on %
         \number\year/\two@digits\month/\two@digits\day.^^J%
      \@percentchar\@percentchar}%
  \fi%
  \let\do\@makeother\dospecials%
%    \end{macrocode}
%    If there are active characters in the upper half (e.g., from
%    \texttt{inputenc} there would be confusion so we render everything
%    harmless.
% \changes{v1.2f}{2018/03/27}
%         {Use full file name for old release}
%    \begin{macrocode}
  \count@ 128\relax%
  \loop%
    \catcode\count@ 11\relax%
    \advance\count@ \@ne%
    \ifnum\count@<\@cclvi%
  \repeat%
%    \end{macrocode}
%
% \changes{v1.0y}{1997/10/10}
%     {Check for text before or after \cs{end} environment. latex/2636}
%    \begin{macrocode}
  \edef\E{\@backslashchar end\string{\@currenvir\string}}%
  \edef\reserved@b{%
    \def\noexpand\reserved@b%
         ####1\E####2\E####3\relax}%
  \reserved@b{%
    \ifx\relax##3\relax%
%    \end{macrocode}
% There was no |\end{filecontents}|
%    \begin{macrocode}
      \immediate\write\reserved@c{##1}%
    \else%
%    \end{macrocode}
% There was a |\end{filecontents}|, so stop this time.
%    \begin{macrocode}
      \edef^^M{\noexpand\end{\@currenvir}}%
      \ifx\relax##1\relax%
      \else%
%    \end{macrocode}
% Text before the |\end|, write it with a warning.
%    \begin{macrocode}
          \@latex@warning{Writing text `##1' before %
            \string\end{\@currenvir}\MessageBreak
            as last line of \@curr@file}%
        \immediate\write\reserved@c{##1}%
      \fi%
      \ifx\relax##2\relax%
      \else%
%    \end{macrocode}
% Text after the |\end|, ignore it with a warning.
%    \begin{macrocode}
         \@latex@warning{%
           Ignoring text `##2' after \string\end{\@currenvir}}%
      \fi%
    \fi%
    ^^M}%
%    \end{macrocode}
%
%
% \changes{v1.2j}{2018/05/29}{use \cs{csname} not \cs{@undefined}}
%    \begin{macrocode}
  \catcode`\^^L\active%
  \let\L\@undefined%
  \def^^L{\expandafter\ifx\csname L\endcsname\relax\fi ^^J^^J}%
  \catcode`\^^I\active%
  \let\I\@undefined%
  \def^^I{\expandafter\ifx\csname I\endcsname\relax\fi\space}%
  \catcode`\^^M\active%
  \edef^^M##1^^M{%
    \noexpand\reserved@b##1\E\E\relax}}%
\endgroup%
%    \end{macrocode}
%
%
%    \begin{macrocode}
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{2019/10/01}%
%<latexrelease>    {\filec@ntents}{Spaces in file names + optional arg}%
%<latexrelease>
%<latexrelease>\def\filecontents{\@tempswatrue\@fileswtrue
%<latexrelease>  \@ifnextchar[\filec@ntents@opt\filec@ntents
%<latexrelease>}
%<latexrelease>\@namedef{filecontents*}{\@tempswafalse\@fileswtrue
%<latexrelease>  \@ifnextchar[\filec@ntents@opt\filec@ntents
%<latexrelease>}
%<latexrelease>\def\filec@ntents@opt[#1]{%
%<latexrelease>  \edef\@fortmp{\zap@space#1 \@empty}%
%<latexrelease>  \@for\reserved@a:=\@fortmp\do{%
%<latexrelease>    \ifcsname filec@ntents@\reserved@a\endcsname
%<latexrelease>      \csname filec@ntents@\reserved@a\endcsname
%<latexrelease>    \else
%<latexrelease>    \@latex@error{Unknown filecontents option \reserved@a}%
%<latexrelease>       {Valid options are force (or overwrite), nosearch, noheader}%
%<latexrelease>    \fi}%
%<latexrelease>  \filec@ntents
%<latexrelease>}
%<latexrelease>\let\filec@ntents@force\@fileswfalse
%<latexrelease>\let\filec@ntents@overwrite\@fileswfalse  % alternative name
%<latexrelease>\let\filec@ntents@noheader\@tempswafalse
%<latexrelease>\def\filec@ntents@nosearch{%
%<latexrelease>  \let\filec@ntents@checkdir\@currdir
%<latexrelease>  \def\filec@ntents@where{in current directory}}
%<latexrelease>\let\filec@ntents@checkdir\@empty
%<latexrelease>\def\filec@ntents@where{exists on the system}
%<latexrelease>\begingroup%
%<latexrelease>\@tempcnta=1
%<latexrelease>\loop
%<latexrelease>  \catcode\@tempcnta=12  %
%<latexrelease>  \advance\@tempcnta\@ne %
%<latexrelease>\ifnum\@tempcnta<32      %
%<latexrelease>\repeat                  %
%<latexrelease>\catcode`\*=11 %
%<latexrelease>\catcode`\^^M\active%
%<latexrelease>\catcode`\^^L\active\let^^L\relax%
%<latexrelease>\catcode`\^^I\active%
%<latexrelease>\gdef\filec@ntents#1{%
%<latexrelease>  \set@curr@file{\filec@ntents@checkdir#1}%
%<latexrelease>  \edef\q@curr@file{\expandafter\quote@name\expandafter{\@curr@file}}%
%<latexrelease>  \chardef\reserved@c\ifx\directlua\@undefined 15 \else 127 \fi%
%<latexrelease>  \openin\@inputcheck\q@curr@file \space %
%<latexrelease>  \ifeof\@inputcheck%
%<latexrelease>    \@latex@warning@no@line%
%<latexrelease>        {Writing file `\@currdir\@curr@file'}%
%<latexrelease>    \ch@ck7\reserved@c\write\relax%
%<latexrelease>    \immediate\openout\reserved@c\q@curr@file\relax%
%<latexrelease>  \else%
%<latexrelease>    \if@filesw%
%<latexrelease>      \@latex@warning@no@line%
%<latexrelease>          {File `\@curr@file' already \filec@ntents@where.\MessageBreak%
%<latexrelease>             Not generating it from this source}%
%<latexrelease>      \let\write\@gobbletwo%
%<latexrelease>      \let\closeout\@gobble%
%<latexrelease>    \else%
%<latexrelease>      \edef\reserved@a{#1}%
%<latexrelease>      \edef\reserved@a{\detokenize\expandafter{\reserved@a}}%
%<latexrelease>      \edef\reserved@b{\detokenize\expandafter{\jobname}}%
%<latexrelease>      \ifx\reserved@a\reserved@b%
%<latexrelease>        \@fileswtrue%
%<latexrelease>      \else%
%<latexrelease>        \edef\reserved@b{\reserved@b\detokenize{.tex}}%
%<latexrelease>        \ifx\reserved@a\reserved@b
%<latexrelease>          \@fileswtrue%
%<latexrelease>        \fi%
%<latexrelease>      \fi%
%<latexrelease>      \ch@ck7\reserved@c\write\relax%
%<latexrelease>      \if@filesw%  % Foul ... trying to overwrite \jobname!
%<latexrelease>      \@latex@error{Trying to overwrite `\jobname.tex'}{You can't %
%<latexrelease>        write to the file you are reading from!\MessageBreak%
%<latexrelease>        Data is written to screen instead.}%
%<latexrelease>      \else%
%<latexrelease>        \@latex@warning@no@line%
%<latexrelease>           {Writing or overwriting file `\@currdir\@curr@file'}%
%<latexrelease>        \immediate\openout\reserved@c\q@curr@file\relax%
%<latexrelease>      \fi%
%<latexrelease>    \fi%
%<latexrelease>  \fi%
%<latexrelease>  \closein\@inputcheck%
%<latexrelease>  \if@tempswa%
%<latexrelease>    \immediate\write\reserved@c{%
%<latexrelease>      \@percentchar\@percentchar\space%
%<latexrelease>          \expandafter\@gobble\string\LaTeX2e file `\@curr@file'^^J%
%<latexrelease>      \@percentchar\@percentchar\space  generated by the %
%<latexrelease>        `\@currenvir' \expandafter\@gobblefour\string\newenvironment^^J%
%<latexrelease>      \@percentchar\@percentchar\space from source `\jobname' on %
%<latexrelease>         \number\year/\two@digits\month/\two@digits\day.^^J%
%<latexrelease>      \@percentchar\@percentchar}%
%<latexrelease>  \fi%
%<latexrelease>  \let\do\@makeother\dospecials%
%<latexrelease>  \count@ 128\relax%
%<latexrelease>  \loop%
%<latexrelease>    \catcode\count@ 11\relax%
%<latexrelease>    \advance\count@ \@ne%
%<latexrelease>    \ifnum\count@<\@cclvi%
%<latexrelease>  \repeat%
%<latexrelease>  \edef\E{\@backslashchar end\string{\@currenvir\string}}%
%<latexrelease>  \edef\reserved@b{%
%<latexrelease>    \def\noexpand\reserved@b%
%<latexrelease>         ####1\E####2\E####3\relax}%
%<latexrelease>  \reserved@b{%
%<latexrelease>    \ifx\relax##3\relax%
%<latexrelease>      \immediate\write\reserved@c{##1}%
%<latexrelease>    \else%
%<latexrelease>      \edef^^M{\noexpand\end{\@currenvir}}%
%<latexrelease>      \ifx\relax##1\relax%
%<latexrelease>      \else%
%<latexrelease>          \@latex@warning{Writing text `##1' before %
%<latexrelease>             \string\end{\@currenvir}\MessageBreak as last line of \@curr@file}%
%<latexrelease>        \immediate\write\reserved@c{##1}%
%<latexrelease>      \fi%
%<latexrelease>      \ifx\relax##2\relax%
%<latexrelease>      \else%
%<latexrelease>         \@latex@warning{%
%<latexrelease>           Ignoring text `##2' after \string\end{\@currenvir}}%
%<latexrelease>      \fi%
%<latexrelease>    \fi%
%<latexrelease>    ^^M}%
%<latexrelease>  \catcode`\^^L\active%
%<latexrelease>  \let\L\@undefined%
%<latexrelease>  \def^^L{\expandafter\ifx\csname L\endcsname\relax\fi ^^J^^J}%
%<latexrelease>  \catcode`\^^I\active%
%<latexrelease>  \let\I\@undefined%
%<latexrelease>  \def^^I{\expandafter\ifx\csname I\endcsname\relax\fi\space}%
%<latexrelease>  \catcode`\^^M\active%
%<latexrelease>  \edef^^M##1^^M{%
%<latexrelease>    \noexpand\reserved@b##1\E\E\relax}}%
%<latexrelease>\endgroup%
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease>    {\filec@ntents}{Spaces in file names + optional arg}%
%<latexrelease>
%<latexrelease>\let\filec@ntents@opt        \@undefined
%<latexrelease>\let\filec@ntents@force      \@undefined
%<latexrelease>\let\filec@ntents@overwrite  \@undefined
%<latexrelease>\let\filec@ntents@noheader   \@undefined
%<latexrelease>\let\filec@ntents@nosearch   \@undefined
%<latexrelease>\let\filec@ntents@checkdir   \@undefined
%<latexrelease>\let\filec@ntents@where      \@undefined
%<latexrelease>
%<latexrelease>\begingroup%
%<latexrelease>\@tempcnta=1
%<latexrelease>\loop
%<latexrelease>  \catcode\@tempcnta=12  %
%<latexrelease>  \advance\@tempcnta\@ne %
%<latexrelease>\ifnum\@tempcnta<32      %
%<latexrelease>\repeat                  %
%<latexrelease>\catcode`\*=11 %
%<latexrelease>\catcode`\^^M\active%
%<latexrelease>\catcode`\^^L\active\let^^L\relax%
%<latexrelease>\catcode`\^^I\active%
%<latexrelease>
%<latexrelease>\gdef\filec@ntents#1{%
%<latexrelease>  \openin\@inputcheck#1 %
%<latexrelease>  \ifeof\@inputcheck%
%<latexrelease>    \@latex@warning@no@line%
%<latexrelease>        {Writing file `\@currdir#1'}%
%<latexrelease>    \chardef\reserved@c15 %
%<latexrelease>    \ch@ck7\reserved@c\write%
%<latexrelease>    \immediate\openout\reserved@c#1\relax%
%<latexrelease>  \else%
%<latexrelease>    \closein\@inputcheck%
%<latexrelease>    \@latex@warning@no@line%
%<latexrelease>            {File `#1' already exists on the system.\MessageBreak%
%<latexrelease>             Not generating it from this source}%
%<latexrelease>    \let\write\@gobbletwo%
%<latexrelease>    \let\closeout\@gobble%
%<latexrelease>  \fi%
%<latexrelease>  \if@tempswa%
%<latexrelease>    \immediate\write\reserved@c{%
%<latexrelease>      \@percentchar\@percentchar\space%
%<latexrelease>          \expandafter\@gobble\string\LaTeX2e file `#1'^^J%
%<latexrelease>      \@percentchar\@percentchar\space  generated by the %
%<latexrelease>        `\@currenvir' \expandafter\@gobblefour\string\newenvironment^^J%
%<latexrelease>      \@percentchar\@percentchar\space from source `\jobname' on %
%<latexrelease>         \number\year/\two@digits\month/\two@digits\day.^^J%
%<latexrelease>      \@percentchar\@percentchar}%
%<latexrelease>  \fi%
%<latexrelease>  \let\do\@makeother\dospecials%
%<latexrelease>  \count@ 128\relax%
%<latexrelease>  \loop%
%<latexrelease>    \catcode\count@ 11\relax%
%<latexrelease>    \advance\count@ \@ne%
%<latexrelease>    \ifnum\count@<\@cclvi%
%<latexrelease>  \repeat%
%<latexrelease>  \edef\E{\@backslashchar end\string{\@currenvir\string}}%
%<latexrelease>  \edef\reserved@b{%
%<latexrelease>    \def\noexpand\reserved@b%
%<latexrelease>         ####1\E####2\E####3\relax}%
%<latexrelease>  \reserved@b{%
%<latexrelease>    \ifx\relax##3\relax%
%<latexrelease>      \immediate\write\reserved@c{##1}%
%<latexrelease>    \else%
%<latexrelease>      \edef^^M{\noexpand\end{\@currenvir}}%
%<latexrelease>      \ifx\relax##1\relax%
%<latexrelease>      \else%
%<latexrelease>          \@latex@warning{Writing text `##1' before %
%<latexrelease>             \string\end{\@currenvir}\MessageBreak as last line of #1}%
%<latexrelease>        \immediate\write\reserved@c{##1}%
%<latexrelease>      \fi%
%<latexrelease>      \ifx\relax##2\relax%
%<latexrelease>      \else%
%<latexrelease>         \@latex@warning{%
%<latexrelease>           Ignoring text `##2' after \string\end{\@currenvir}}%
%<latexrelease>      \fi%
%<latexrelease>    \fi%
%<latexrelease>    ^^M}%
%<latexrelease>
%<latexrelease>  \catcode`\^^L\active%
%<latexrelease>  \let\L\@undefined%
%<latexrelease>  \def^^L{\expandafter\ifx\csname L\endcsname\relax\fi ^^J^^J}%
%<latexrelease>  \catcode`\^^I\active%
%<latexrelease>  \let\I\@undefined%
%<latexrelease>  \def^^I{\expandafter\ifx\csname I\endcsname\relax\fi\space}%
%<latexrelease>  \catcode`\^^M\active%
%<latexrelease>  \edef^^M##1^^M{%
%<latexrelease>    \noexpand\reserved@b##1\E\E\relax}}%
%<latexrelease>\endgroup%
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
%    \end{macrocode}
%
%
%    \begin{macrocode}
\begingroup
\catcode`|=\catcode`\%
\catcode`\%=12
\catcode`\*=11
\gdef\@percentchar{%}
\gdef\endfilecontents{|
  \immediate\closeout\reserved@c
  \def\T##1##2##3{|
  \ifx##1\@undefined\else
    \@latex@warning@no@line{##2 has been converted to Blank ##3e}|
  \fi}|
  \T\L{Form Feed}{Lin}|
  \T\I{Tab}{Spac}|
  \immediate\write\@unused{}}
\global\let\endfilecontents*\endfilecontents
%    \end{macrocode}
%    We no longer prevent the code to be used after begin document (no
%    rollback needed for this change).
%    \begin{macrocode}
%\@onlypreamble\filecontents
%\@onlypreamble\endfilecontents
%\@onlypreamble\filecontents*
%\@onlypreamble\endfilecontents*
\endgroup
%\@onlypreamble\filec@ntents
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{environment}
%
%
%
%
%
% \section{Package/class rollback mechanism}
%
%
%
%    \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexreleasefirst>
%    \end{macrocode}
%
% \changes{v1.2d}{2018/02/18}{Introduce rollback concept}
%
%  \begin{macro}{\pkgcls@debug}
%    For testing we have a few extra lines of code that by default do
%    nothing but one can set |\pkgcls@debug| to  |\typeout| to get
%    extra info. Sometime in the future this will be dropped.
%    \begin{macrocode}
%<*tracerollback>
%\let\pkgcls@debug\typeout
\let\pkgcls@debug\@gobble
%</tracerollback>
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\requestedLaTeXdate}
%    The macro (!) |\requestedLaTeXdate| holds the globally requested
%    rollback date (via \texttt{latexrelease}) or zero if no such
%    request was made.
%    \begin{macrocode}
\def\requestedLaTeXdate{0}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\pkgcls@targetdate}
%  \begin{macro}{\pkgcls@targetlabel}
%  \begin{macro}{\pkgcls@innerdate}
%
%    If a rollback for a package or class is requested then
%    |\pkgcls@targetdate| holds the requested date as a number
%    YYYYMMDD (if there was one, otherwise the value of
%    |\requestedLaTeXdate|) and |\pkgcls@targetlabel| will be
%    empty. If there was a request for a named version then
%    |\pkgcls@targetlabel| holds the version name and
%    |\pkgcls@targetdate| is set to \texttt{1}.
%
%    |\pkgcls@targetdate=0| is used to indicate that there was no
%    rollback request.
%    While loading an old release |\pkgcls@targetdate| is also reset to
%    zero so that |\DeclareRelease| declarations are bypassed.
%
%    In contrast |\pkgcls@innerdate| will always hold the requested
%    date (in a macro not a counter) if there was one, otherwise,
%    e.g., if there was no request or a request to a version name it
%    will contain \TeX{} largest legal number. While loading a file
%    this can be used to provide conditionals that select code based
%    on the request.
%
%
%    \begin{macrocode}
\ifx\pkgcls@targetdate\@undefined
  \newcount\pkgcls@targetdate
\fi
\let\pkgcls@targetlabel\@empty
\def\pkgcls@innerdate{\maxdimen}
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%  \end{macro}
%
%  \begin{macro}{\pkgcls@candidate}
%  \begin{macro}{\pkgcls@releasedate}
%    When looping through the |\DeclareRelease| declarations we
%    record if the release is the best candidate we have seen so far.
%    This is recorded in |\pkgcls@candidate| and we update it whenever
%    we see a better one.
%
%    In |\pkgcls@releasedate| we keep track of the release date of
%    that candidate.
%    \begin{macrocode}
\let\pkgcls@candidate\@empty
\let\pkgcls@releasedate\@empty
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
%  \begin{macro}{\load@onefilewithoptions}
%  \begin{macro}{\@onefilewithoptions}
%    the best place to add the rollback code is at the point where
%    |\@onefilewithoptions| is called to load a single class or
%    package.
%
%    To make things easy we save the old definition as
%    |\load@onefilewithoptions| and then provide a new interface.
%
%    Important: as this code is also unconditionally placed into
%    latexrelease we can only do this name change once otherwise both
%    macros will contain the same code.
%    \begin{macrocode}
\ifx\load@onefilewithoptions\@undefined
 \let\load@onefilewithoptions\@onefilewithoptions
%    \end{macrocode}
%
%    \begin{macrocode}
 \def\@onefilewithoptions#1[#2][#3]#4{%
%    \end{macrocode}
%    First a bit of tracing normally disabled.
%    \begin{macrocode}
%<*tracerollback>
  \pkgcls@debug{--- File loaded request (\noexpand\usepackage or ...)}%
  \pkgcls@debug{\@spaces 1: #1}%
  \pkgcls@debug{\@spaces 2: #2}%
  \pkgcls@debug{\@spaces 3: #3}%
  \pkgcls@debug{\@spaces 4: #4}%
%</tracerollback>
%    \end{macrocode}
%    Two of the arguments are needed later on in error/warning
%    messages so we save them.
%    \begin{macrocode}
  \def\pkgcls@name{#1}%                  % for info message
  \def\pkgcls@arg {#3}%                  % for info message
%    \end{macrocode}
%    then we parse the final optional argument to determine if there
%    is a specific rollback request for the current file. This will
%    set |\pkgcls@targetdate|, |\pkgcls@targetlabel| and
%    |\pkgcls@mindate|.
%    \begin{macrocode}
  \pkgcls@parse@date@arg{#3}%
%    \end{macrocode}
%    When determining the correct release to load we keep track of
%    candidates in |\pkgcls@candidate| and initially we don't have any:
%    \begin{macrocode}
  \let\pkgcls@candidate\@empty
%    \end{macrocode}
%    If we had a rollback request then |#3| may contain data but not
%    necessarily a ``minimal date'' so instead of passing it on we
%    pass on the content of |\pkgcls@mindate|. We need to pass the
%    value not the command, otherwise nested packages may pick up the
%    wrong information.
%   \changes{v1.2h}{2018-04-08}{Pass expanded date}
%    \begin{macrocode}
  \begingroup
  \edef\reserved@a{%
    \endgroup
    \unexpanded{\load@onefilewithoptions#1[#2]}%
    [\pkgcls@mindate]%
    \unexpanded{#4}}%
   \reserved@a
 }
\fi
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
%
%  \begin{macro}{\pkgcls@parse@date@arg}
%    The |\pkgcls@parse@date@arg| command parses the second optional
%   argument of |\usepackage|, |\RequirePackage| or |\documentclass|
%   for a rollback request setting the values of |\pkgcls@targetdate|
%   and |\pkgcls@targetlabel|.
%
%   This optional argument has a dual purpose: If it just contains a
%   date string then this means that the package should have at least
%   that date (to ensure that a certain feature is actually available,
%   or a certain bug has been fixed). When the package gets loaded the
%   information in |\Provides...| will then be checked against this
%   request.
%
%   But if it starts with an equal sign followed by a date string or
%   followed by a version name then this means that we should roll
%   back to the state of the package at that date or to the version
%   with the requested name.
%
%   If there was no optional argument or the optional argument
%   does not start with ``\texttt{=}'' then the |\pkgcls@targetdate|
%   is set to the date of the overall rollback request (via
%   \texttt{latexrelease}) or if that was not given it is set to
%   \texttt{0}.
%   In either case |\pkgcls@targetlabel| will be made empty.
%
%   If the argument doesn't start with  ``\texttt{=}'' then it is
%    supposed to be a ``minimal date'' and we therefore save the value
%    in |\pkgcls@mindate|, otherwise this macro is made empty.
%
%   So in summary we have:
%   \begin{flushleft}
%     \hspace*{-1in}\begin{tabular}{ccccc@{}}
%   Input        &  & \cs{pkgcls@targetdate}
%                   & \cs{pkgcls@targetlabel}
%                   & \cs{pkgcls@mindate}\\[3pt]
% \meta{empty}   & $\to$ & \meta{global-rollbackdate-as-number}
%                        & \meta{empty} & \meta{empty}
% \\
% \meta{date}    & $\to$ & \meta{global-rollbackdate-as-number}
%                        & \meta{empty} & \meta{date}
% \\
% \texttt{=}\meta{date} & $\to$ & \meta{date-as-number}
%                        & \meta{empty} & \meta{empty}
% \\
% \texttt{=}\meta{version}& $\to$ & \texttt{1}
%                                 & \meta{version}  & \meta{empty}
% \\
% \meta{other}   & $\to$ & \meta{global-rollbackdate-as-number}
%                        & \meta{empty} & \meta{other}
% \\
%     \end{tabular}
%   \end{flushleft}
%    where \meta{global-rollbackdate-as-number} is a date request given
%    via \texttt{latexrelease} or if there wasn't one \texttt{0}.
%
%    \begin{macrocode}
\def\pkgcls@parse@date@arg #1{%
%    \end{macrocode}
%    If the argument is empty we use the rollback date from
%    \texttt{latexrelease} which has the value of zero if there was no
%    rollback request. The label and the minimal date is made empty in that case.
%    \begin{macrocode}
   \ifx\@nil#1\@nil
     \pkgcls@targetdate\requestedLaTeXdate\relax
     \let\pkgcls@targetlabel\@empty
     \let\pkgcls@mindate\@empty
%    \end{macrocode}
%    Otherwise we parse the argument further, checking for a \texttt{=}
%    as the first character. We append a \texttt{=} at the end so that
%    there is at least one such character in the argument.
%    \begin{macrocode}
   \else
     \pkgcls@parse@date@arg@#1=\@nil\relax
   \fi
 }
%    \end{macrocode}
%    The actual parsing work then happens in |\pkgcls@parse@date@arg@|:
%    \begin{macrocode}
\def\pkgcls@parse@date@arg@#1=#2\@nil{%
%    \end{macrocode}
%    We set |\pkgcls@targetdate| depending on the parsing result; the
%    code is expandable so we can do the parsing as part of the assignment.
%    \begin{macrocode}
  \pkgcls@targetdate
%    \end{macrocode}
%    If a \texttt{=} was in first position then |#1| will be empty. In
%    that case |#2| will be the original argument with a \texttt{=}
%    appended.
%
%    This can be parsed with |\@parse@version|, the trailing character
%    is simply ignored. This macro returns the parsed date as a number
%    (or zero if it wasn't a date) and accepts both YYYY/MM/DD and YYYY-MM-DD
%    formats.
%    \begin{macrocode}
    \ifx\@nil#1\@nil
      \@parse@version0#2//00\@nil\relax
%    \end{macrocode}
%     Whatever is returned is thus assigned to |\pkgcls@targetdate|
%    and therefore we can now test its value. If the value is zero we
%    assume that the remaining argument string represents a version
%    and change |\pkgcls@targetdate| and set |\pkgcls@targetlabel| to
%    the version name (after stripping off the trailing \texttt{=}.
%    \begin{macrocode}
      \ifnum \pkgcls@targetdate=\z@
        \pkgcls@targetdate\@ne
        \def\pkgcls@innerdate{\maxdimen}%
        \pkgcls@parse@date@arg@version#2%
      \else
        \edef\pkgcls@innerdate{\the\pkgcls@targetdate}%
      \fi
      \let\pkgcls@mindate\@empty
    \else
%    \end{macrocode}
%    If |#1| was not empty then there wasn't a \texttt{=} character in
%    first position so we are dealing either with a ``minimum
%    date'' or with some incorrect data. We assume the former and make
%    the following assignments (the first one finishing the assignment
%    of |\pkgcls@targetdate|):
%    \begin{macrocode}
      \requestedLaTeXdate\relax
      \let\pkgcls@targetlabel\@empty
      \def\pkgcls@innerdate{\maxdimen}%
      \def\pkgcls@mindate{#1}%
%    \end{macrocode}
%    If the min-date is after the requested rollback date (if there is
%    any, i.e., if it is not zero) then we have a conflict and
%    therefore issue a warning.
% \changes{v1.2i}{2018/05/08}
%         {Make suspicious rollback a warning not error: github issue 43}
%    \begin{macrocode}
      \ifnum \pkgcls@targetdate > \z@
        \ifnum \@parse@version0#1//00\@nil > \pkgcls@targetdate
          \@latex@warning@no@line{Suspicious rollback/min-date date given\MessageBreak
            A minimal date of #1 has been specified for
             \@cls@pkg\MessageBreak '\pkgcls@name'.\MessageBreak
             But this is in conflict
             with a rollback request to \requestedpatchdate}
        \fi
      \fi
    \fi
}
%    \end{macrocode}
%    Strip off the trailing \texttt{=} and assign the version name to
%    |\pkgcls@targetlabel|.
%    \begin{macrocode}
\def\pkgcls@parse@date@arg@version#1={%
  \def\pkgcls@targetlabel{#1}}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\DeclareRelease}
%    First argument is the ``name'' of the release and it can be left empty
%    if one doesn't like to give a name to the release.
%    The second argument is that from which on this release was
%    available (or should be used in case of minor updates).
%    The final argument is the external file name of this release, by
%    convention this should be
%    \meta{pkg/cls-name}\texttt{-}\meta{date}\texttt{.}\meta{extension}
%    but this is not enforced and through this argument one can
%    overwrite it.
%    \begin{macrocode}
\def\DeclareRelease#1#2#3{%
  \ifnum\pkgcls@targetdate>\z@  % some sort of rollback request
%<*tracerollback>
    \pkgcls@debug{---\string\DeclareRelease:}%
    \pkgcls@debug{\@spaces 1: #1}%
    \pkgcls@debug{\@spaces 2: #2}%
    \pkgcls@debug{\@spaces 3: #3}%
%</tracerollback>
%    \end{macrocode}
%    If the date argument |#2| is empty we are dealing with a special
%    release that should be only accessible via its name; a typical
%    use case would be a ``beta'' release. So if we are
%    currently processing a date request we ignore it and otherwise we
%    check if we can match the name and if  so load the corresponding
%    release file.
%    \begin{macrocode}
    \ifx\@nil#2\@nil
      \ifnum\pkgcls@targetdate=\@ne  % named request
        \def\reserved@a{#1}%
        \ifx\pkgcls@targetlabel\reserved@a
          \pkgcls@use@this@release{#3}{}%
%<*tracerollback>
        \else
          \pkgcls@debug{Label doesn't match}%
%</tracerollback>
        \fi
%<*tracerollback>
      \else
        \pkgcls@debug{Date request: ignored}%
%</tracerollback>
      \fi
    \else
%    \end{macrocode}
%    If the value of |\pkgcls@targetdate| is greater than 1 (or in
%    reality greater than something like 19930101) we are dealing with a
%    rollback request to a specific date.
%    \begin{macrocode}
      \ifnum\pkgcls@targetdate>\@ne  % a real request
%    \end{macrocode}
%    So we parse the date of this release to check if it is before or
%    after the request date.
%    \begin{macrocode}
        \ifnum\@parse@version#2//00\@nil
             >\pkgcls@targetdate
%    \end{macrocode}
%    If it is after we have to distinguish between two cases: If there
%    was an earlier candidate we use that one because the other is too
%    late, but if there wasn't one (i.e., if current release is the
%    oldest that exists) we use it as the best choice. However in
%    that case something is wrong (as there shouldn't be a rollback to
%    a date where a package used doesn't yet exists. So we make a
%    complained to the user.
%    \begin{macrocode}
          \ifx\pkgcls@candidate\@empty
            \pkgcls@rollbackdate@error{#2}%
            \pkgcls@use@this@release{#3}{#2}%
          \else
            \pkgcls@use@this@release\pkgcls@candidate
                                    \pkgcls@releasedate
          \fi
        \else
%    \end{macrocode}
%    Otherwise, if the release date of this version is before the
%    target rollback and we record it as a candidate. But we don't use
%    it yet as there may be another release which is still before the
%    target rollback.
%    \begin{macrocode}
          \def\pkgcls@candidate{#3}%
          \def\pkgcls@releasedate{#2}%
%<*tracerollback>
          \pkgcls@debug{New candidate: #3}%
%</tracerollback>
        \fi
      \else
%    \end{macrocode}
%    If we end up in this branch we have a named version request. So
%    we check if |\pkgcls@targetlabel| matches the current name and if
%    yes we use this release immediately, otherwise we do nothing as a
%    later declaration may match it.
%    \begin{macrocode}
        \def\reserved@a{#1}%
        \ifx\pkgcls@targetlabel\reserved@a
          \pkgcls@use@this@release{#3}{#2}%
%<*tracerollback>
        \else
          \pkgcls@debug{Label doesn't match}%
%</tracerollback>
        \fi
      \fi
    \fi
  \fi
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\pkgcls@use@this@release}
%    If a certain release has been selected (stored in the external
%    file given in \verb=#1=) we need to input it and afterwards stop
%    reading the current file.
%    \begin{macrocode}
\def\pkgcls@use@this@release#1#2{%
%    \end{macrocode}
%    Before that we record the selection made inside the transcript.
%    \begin{macrocode}
   \pkgcls@show@selection{#1}{#2}%
%    \end{macrocode}
%    We then set the |\pkgcls@targetdate| to zero so that any
%    |\DeclareRelease| or |\DeclareCurrentRelease| in the file we
%    now load are bypassed\footnote{The older release may also have
%    such declarations inside if it was a simply copy of the
%    \texttt{.sty} or \texttt{.cls} file current at that
%    date. Removing these declarations would make the file load a tiny
%    bit faster, but this way it works in any case.} and then we
%    finally load the correct release.
%
%    After loading that file we need to stop reading the current file
%    so we issue |\endinput|. Note that the |\relax| before that is
%    essential to ensure that the |\endinput| is only happening after
%    the file has been fully processed, otherwise it would act after the
%    first line of the |\@@input|!
% \changes{v1.2e}{2018/03/24}
%         {Use full file name for old release}
%    \begin{macrocode}
   \pkgcls@targetdate\z@
   \@@input #1\relax
   \endinput
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\pkgcls@show@selection}
%    This command records what selection was made. As that is needed
%    in two places (and it is rather lengthy) it was placed in a
%    separate command. The first argument is the name of the external
%    file that is being loaded and is only needed for debugging.  The
%    second argument is the date that corresponds to this file and it
%    is used as part of the message.
%    \begin{macrocode}
\def\pkgcls@show@selection#1#2{%
%<*tracerollback>
  \pkgcls@debug{Result: use  #1}%
%</tracerollback>
  \GenericInfo
   {\@spaces\@spaces\space}{Rollback for
    \@cls@pkg\space'\@currname' requested ->
    \ifnum\pkgcls@targetdate>\@ne
       date
       \ifnum\requestedLaTeXdate=\pkgcls@targetdate
          \requestedpatchdate
       \else
          \expandafter\@gobble\pkgcls@arg
       \fi.\MessageBreak
%    \end{macrocode}
%    Instead of ``best approximation'' we could say that we have been
%    able to exactly match the date (if it is exact), but that would
%    mean extra tests without much gain, so not done.
%    \begin{macrocode}
       Best approximation is
    \else
       version '\pkgcls@targetlabel'.\MessageBreak
       This corresponds to
    \fi
    \ifx\@nil#2\@nil
       a special release%
    \else
       the release introduced on #2%
    \fi
    \@gobble}%
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\pkgcls@rollbackdate@error}
%    This is called if the requested rollback date is earlier than the
%    earliest known release of a package or class.
%
%    A similar error is given if global rollback date and min-date on
%    a specific package conflict with each other, but that case is
%    happens only once so it is inlined.
% \changes{v1.3u}{2020/11/09}{Change help text because the package may have
%    existed then --- there is just no rollback data (gh/423).}
%    \begin{macrocode}
\def\pkgcls@rollbackdate@error#1{%
  \@latex@error{Suspicious rollback date given}%
     {The \@cls@pkg\space'\@currname'  has no rollback data
      before #1 which\MessageBreak
      is after your requested rollback date --- so
      something may be wrong here.\MessageBreak
      Continue and we use the earliest known release.}}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\DeclareCurrentRelease}
%    This declares the date (and possible name) of the current version
%    of a package or class.
%    \begin{macrocode}
\def\DeclareCurrentRelease#1#2{%
%    \end{macrocode}
%    First we test if |\pkgcls@targetdate| is greater than zero,
%    otherwise this code is bypassed (as there is no rollback
%    request).
%    \begin{macrocode}
  \ifnum\pkgcls@targetdate>\z@  % some sort of rollback request
%<*tracerollback>
    \pkgcls@debug{---DeclareCurrentRelease}%
    \pkgcls@debug{   1: #1}%
    \pkgcls@debug{   2: #2}%
%</tracerollback>
%    \end{macrocode}
%    If the value is greater than 1 we have to deal with a date
%    request, so we parse |#2| as a date and compare it with
%    |\pkgcls@targetdate|.
%    \begin{macrocode}
    \ifnum\pkgcls@targetdate>\@ne  % a date request
      \ifnum\@parse@version#2//00\@nil
           >\pkgcls@targetdate
%    \end{macrocode}
%    If it is greater that means the release date if this file is
%    later than the requested rollback date. Again we have two cases:
%    If there was a previous candidate release we use that one as the
%    current release is too young, but if there wasn't we have to use
%    this release nevertheless as there isn't any alternative.
%
%    However this case can only happen if there is a
%    |\DeclareCurrentRelease| but no declared older releases (so
%    basically the use of the declaration is a bit dubious).
%    \begin{macrocode}
        \ifx\pkgcls@candidate\@empty
          \pkgcls@rollbackdate@error{#2}%
        \else
          \pkgcls@use@this@release\pkgcls@candidate
                                  \pkgcls@releasedate
        \fi
%    \end{macrocode}
%    Otherwise the current file is the right release, so we record that
%    in the transcript and then carry on.
%    \begin{macrocode}
      \else
        \pkgcls@show@selection{current version}{#2}%
      \fi
    \else % a label request
%    \end{macrocode}
%    Otherwise we have a rollback request to a named version so we
%    check if that fits the current name and if not give an error as
%    this was the last possible opportunity.
%    \begin{macrocode}
      \def\reserved@a{#1}%
      \ifx\pkgcls@targetlabel\reserved@a
        \pkgcls@show@selection{current version}{#2}%
      \else
        \@latex@error{Requested version '\pkgcls@targetlabel' for
          \@cls@pkg\space'\@currname' is unknown}\@ehc
      \fi
    \fi
  \fi
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\IfTargetDateBefore}
%    This enables a simple form of conditional code inside a class or
%    package file. If there is a date request and the request date is
%    earlier than the first argument the code in the second argument
%    is processed otherwise the code in the third argument is
%    processed. If there was no date request then we also execute the
%    third argument, i.e., we will get the ``latest'' version of the
%    file.
%
%    Most often the second argument (before-date-code) will be empty.
%    \begin{macrocode}
\DeclareRobustCommand\IfTargetDateBefore[1]{%
  \ifnum\pkgcls@innerdate <%
        \expandafter\@parse@version\expandafter0#1//00\@nil
    \typeout{Exclude code introduced on #1}%
    \expandafter\@firstoftwo
  \else
    \typeout{Include code introduced on #1}%
    \expandafter\@secondoftwo
  \fi
}
%    \end{macrocode}
%  \end{macro}
%
%    \begin{macrocode}
%</2ekernel|latexreleasefirst>
%    \end{macrocode}
%
%
% \section{After Preamble}
% Finally we declare a package that allows all the commands declared
% above to be |\@onlypreamble| to be used after |\begin{document}|.
% \changes{v0.3f}{1994/03/16}
%         {Add pkgindoc package}
% \changes{v1.1a}{1998/03/21}
%         {Correct to new onlypreamble command list}
%    \begin{macrocode}
%<*afterpreamble>
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{pkgindoc}
         [2020-08-08 v1.3m Package Interface in Document (DPC)]
\def\reserved@a#1\do\@classoptionslist#2\do\filec@ntents#3\relax{%
  \gdef\@preamblecmds{#1#3}}
\expandafter\reserved@a\@preamblecmds\relax
%</afterpreamble>
%    \end{macrocode}
%
% \Finale
back to top