https://github.com/latex3/latex2e
Raw File
Tip revision: 677a0faec3ada45402c67ba34d9a34e3dd9d5479 authored by Joseph Wright on 30 November 2022, 21:06:22 UTC
Step release tag
Tip revision: 677a0fa
latexrelease.dtx
% \iffalse meta-comment
%
% Copyright (C) 1993-2022
% 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
%
%<*dtx>
          \def\latexreleaseversion{<date only known in .sty file>}
          \ProvidesFile{latexrelease.dtx}
%</dtx>
%<driver>\ProvidesFile{latexrelease.drv}
%<fixltx2e>\ProvidesPackage{fixltx2e}
%<fixltx2e>   [2016/12/29 v2.1a fixes to LaTeX (obsolete)]
%<latexrelease>\ProvidesPackage{latexrelease}
%<*latexrelease>
% \fi
%         \ProvidesFile{latexrelease.dtx}
          [2022/02/28 v1.0o LaTeX release emulation and tests
              (including releases up to \latexreleaseversion)]
% \iffalse
%</latexrelease>
%<*driver>
 \documentclass{ltxdoc}
 \newcommand\Lopt[1]{\textsf{#1}}
 \let\Lpack\Lopt
 \providecommand{\file}[1]{\texttt{#1}}
 \providecommand{\MF}{\textsf{Metafont}}
 \providecommand{\danger}{\marginpar[\hfill\protect\Huge!!]{\protect\Huge!!\hfill}}
 \DeclareRobustCommand\cs[2][]{\texttt{\char`\\\detokenize{#2}}}
 \DeclareRobustCommand\pkg[1]{\textsf{#1}}
 \begin{document}
 \DocInput{latexrelease.dtx}
 \end{document}
%</driver>
% \fi
%
% \changes{v1.0i}{2017/12/17}{Add \cs{latexreleaseversion} info
%                             to \cs{ProvidesPackage} output}
%
%
% \let\package\textsf
%
%
% \GetFileInfo{latexrelease.dtx}
%
% \title{The \Lpack{latexrelease} package\thanks{This file
%         has version number \fileversion, last
%         revised \filedate.}}
% \author{The \LaTeX{} Project}
% \date{\filedate}
% \MaintainedByLaTeXTeam{latex}
%  \maketitle
%
% \section{Introduction}
% Prior to the 2015 release of \LaTeX{}, essentially no changes had been
% made to the \LaTeX\ format code for some years, with all
% improvements being instead added to the package \Lpack{fixltx2e}.
%
% While this worked at a technical level it meant that you had to
% explicitly opt-in to bug fixes and improvements, and the vast
% majority of documents did not benefit.
%
% As described in \LaTeX\ News 22, a new policy is being implemented
% in which improvements will now be added to the format by default,
% and this \Lpack{latexrelease} package may be used to ensure
% stability where needed, either by making a new format use an older
% definition of some commands, or conversely may be used to supply the
% new definitions for use with an old format.
%
% The basic use is:
%\begin{verbatim}
% \RequirePackage[2015/01/01]{latexrelease}
% \documentclass{article}
% ....
%\end{verbatim}
%
% After such a declaration the document will use definitions current
% in the January 2015 \LaTeX{}, whether the actual format being used is
% older, or newer than that date. In the former case a copy of
% |latexrelease.sty| would need to be made available for use with the
% older format.  This may be used, for example, to share a document
% between co-workers using different \LaTeX\ releases, or to protect a
% document from being affected by system updates. As well as the
% definitions within the format itself, individual packages may use
% the commands defined here to  adjust their definitions to the
% specified date as described below.
%
% Note that the \Lpack{latexrelease} package is intended for use
% at the start of a \emph{document}. Package and class code should not
% include this package as loading a package should not normally globally
% reset the effective version of \LaTeX\ that is in force, so affecting all
% other packages used in the document.
%
%
% The bulk of this package, after some initial setup and option
% handling consists of a series of |\IncludeInRelease| commands
% which have been extracted from the main source files of the \LaTeX\
% format. These contain the old and new versions of any commands with
% modified definitions.
%
% \section{Package Options}
% \begin{itemize}
% \item \emph{yyyy/mm/dd} or \emph{yyyy-nn-dd}
% The package accepts any possible \LaTeX\ format date as argument,
% although dates in the future for which the current release of this
% package has no information will generate a warning. Dates
% earlier than 2015 will work but will roll back to some point in 2015
% when the method was introduced.
% The |\requestedLaTeXdate| is set to the normalized date argument
% so that package rollback defaults to the specified date.
%
% \item%
% |current| This is the default behaviour, it does not change the
% effective date of the format but does ensure that the
% |\IncludeInRelease| command is defined.
% The |\requestedLaTeXdate| macro is reset to 0 so that package rollback
% does not use the implicit date.
%
% \item
% |latest| sets the effective date of the format to the release date
% of this file, so in an older format applies all patches currently
% available.
% The |\requestedLaTeXdate| macro is reset to 0 so that package rollback
% does not use the implicit date.
% \end{itemize}
%
% In all cases, when the package is loaded, the |\sourceLaTeXdate| is
% defined to be the numerical representation of |\fmtversion| before the
% rollback/forward actually happens, so it is possible to test from which
% was the original \LaTeX{} version before \Lpack{latexrelease} was loaded.
% This is particularly useful when some code in a package has to be
% redefined differently if rolling backwards in time or forwards.
%
% \section{Release Specific Code}
%
% The |\IncludeInRelease| mechanism allows the kernel developer to
% associate code with a specific date to choose different versions of
% definitions depending on the date specified as an option to the
% \Lpack{latexrelease} package. Is also available for use by package
% authors (or even in a document if necessary).
%
% \medskip
%
% \noindent\DescribeMacro{\IncludeInRelease}
% \marg{code-date}^^A
% \oarg{format-date}%^^A
% \marg{label}^^A
% \marg{message}^^A
% \meta{code}^^A
% |\EndIncludeInRelease|
%
% \begin{description}
%
% \item[\marg{code-date}] This date is associated with the \marg{code}
% argument and will be compared to the requested date in the option to
% the \Lpack{latexrelease}.
%
% \item[\oarg{format-date}] This optional argument can be used to
% specify a format date with the code in addition to the mandatory
% \marg{code-date} argument. This can be useful for package developers
% as described below.
%
% \item[\marg{label}] The \marg{label} argument is an identifier
% (string) that within a given package must be a unique label for each
% related set of optional definitions. Per package at most one code
% block from all the |\IncludeInRelease| declarations with the same
% label will be executed.
%
% \item[\marg{message}]
% The \marg{message} is an informative string that is used in
% messages. It has no other function.
%
% \item[\meta{code}]
% Any \TeX\ code after the |\IncludeInRelease| arguments
% up until the and the following |\EndIncludeInRelease|
% is to be
% conditionally included depending on the date of the format as
% described below.
%
% \end{description}
%
% The |\IncludeInRelease| declarations with a given label should be in
% reverse chronological order in the file. The one chosen will depend
% on this order, the effective format version and the date options, as
% described below.
%
% If your package \Lpack{mypackage} defines a |\widget| command but
% has one definition using the features available in the 2015 \LaTeX\
% release, and a different definition is required for older formats
% then you can use:
%\begin{verbatim}
% \IncludeInRelease{2015/01/01}{\widget}{Widget Definition}
%  \def\widget{new version}%
% \EndIncludeInRelease
%
% \IncludeInRelease{0000/00/00}{\widget}{Widget Definition}
%  \def\widget{old version}%
% \EndIncludeInRelease
%\end{verbatim}
%
% If a document using this package is used with a format with
% effective release date of 2015/01/01 or later the new code will be
% used, otherwise the old code will be used. Note the \emph{effective
% release date} might be the original \LaTeX\ release date as shown at
% the start of every \LaTeX\ job, or it may be set by the
% \Lpack{latexrelease} package, so for example a document author who
% wants to ensure the new version is used could use
%\begin{verbatim}
% \RequirePackage[2015/01/01]{latexrelease}
% \documentclass{article}
% \usepackage{mypackage}
%\end{verbatim}
%
% If the document  is used with a \LaTeX\ format from 2014 or before,
% then \Lpack{latexrelease} will not have been part of the original
% distribution, but it may be obtained from a later \LaTeX\ release or
% from CTAN and distributed with the document, it will make an older
% \LaTeX\ release act essentially like the 2015 release.
%
% \subsection{Intermediate Package Releases}
%
% The above example works well for testing against the latex format
% but is not always ideal for controlling code by the release date of
% the \emph{package}. Suppose \LaTeX\ is not updated but in March you
% update the \Lpack{mypackage} package and modify the definition of
% |\widget|. You could code the package as:
%\begin{verbatim}
% \IncludeInRelease{2015/03/01}{\widget}{Widget Definition}
%  \def\widget{even newer improved March version}%
% \EndIncludeInRelease
%
% \IncludeInRelease{2015/01/01}{\widget}{Widget Definition}
%  \def\widget{new version}%
% \EndIncludeInRelease
%
% \IncludeInRelease{0000/00/00}{\widget}{Widget Definition}
%  \def\widget{old version}%
% \EndIncludeInRelease
%\end{verbatim}
%
% This would work and allow a document author to choose a date such as
%\begin{verbatim}
% \RequirePackage[2015/03/01]{latexrelease}
% \documentclass{article}
% \usepackage{mypackage}
%\end{verbatim}
%
% To use the latest version, however it would have disadvantage that
% until the next release of \LaTeX, by default, if the document does
% not use \Lpack{latexrelease} to specify a date, the new improved
% code will not be selected as the effective date will be 2015/01/01
% and so the first code block will be skipped.
%
% For this reason |\IncludeInRelease| has an optional argument that
% specifies an alternative date to use if a date option has not been
% specified to \Lpack{latexrelease}.
%\begin{verbatim}
% \IncludeInRelease{2015/03/01}[2015/01/01]{\widget}{Widget Definition}
%  \def\widget{even newer improved March version}%
% \EndIncludeInRelease
%
% \IncludeInRelease{2015/01/01}{\widget}{Widget Definition}
%  \def\widget{new version}%
% \EndIncludeInRelease
%
% \IncludeInRelease{0000/00/00}{\widget}{Widget Definition}
%  \def\widget{old version}%
% \EndIncludeInRelease
%\end{verbatim}
%
% Now, by default on a 2015/01/01 \LaTeX\ format, the first code block
% will compare the format date to the optional argument 2015/01/01
% and so will execute the \emph{even newer improved} version. The
% remaining blocks using the |\widget| label argument will all then be
% skipped.
%
% If on the other hand the document requests an explicit release date
% using \Lpack{latexrelease} then this date will be used to decide what
% code block to include.
%
% \subsection{Using \cs{IncludeInRelease} in Packages}
%
% If |\IncludeInRelease| is used within a package then all such
% conditional code needs to be within such declarations, e.g., it is
% not possible in the above example to have the ``current'' definition
% of |\widget| somewhere in the main code and only the two older
% definitions inside |\IncludeInRelease| declarations. If you would do
% this then one of those |\IncludeInRelease| declarations would be
% included overwriting the even newer code in the main part of the
% package. As a result your package may get fragmented over time with
% various |\IncludeInRelease| declarations sprinkled throughout your
% code or you have to interrupt the reading flow by putting those
% declarations together but not necessarily in the place where they
% belong.
%
% To avoid this issue you can use the following coding
% strategy: place the current |\widget| definition in the main code
% where it correctly belongs.
% \begin{verbatim}
%   ...
%  \def\widget {even newer improved March version}
%  \def\@widget{newly added helper command no defined in older releases}
%   ...
%\end{verbatim}
% Then, near the end of your package place
% the following:
%  \begin{verbatim}
% \IncludeInRelease{2015/03/01}[2015/01/01]{\widget}{Widget Definition}
% \EndIncludeInRelease
%
% \IncludeInRelease{2015/01/01}{\widget}{Widget Definition}
%  \def\widget{new version}%
%  \let\@widget\@undefined % this doesn't exist in earlier releases
% \EndIncludeInRelease
%
% \IncludeInRelease{0000/00/00}{\widget}{Widget Definition}
%  \def\widget{old version}%
% \EndIncludeInRelease
%\end{verbatim}
% This way the empty code block hides the other |\IncludeInRelease|
% declarations unless there is an explicit request with a date
% 2015/01/01 or earlier.
%
% Now if you make a further change to |\widget| in the future you
% simply copy the current definition into the empty block and add a new
% empty declaration with today's date and the current format date. This
% way your main code stays readable and the old versions accumulate at
% the end of the package.\footnote{Of course there may be some cases
% in which the old code has to be in a specific place within the
% package as other code depends on it (e.g., if you
% \texttt{\string\let} something to it). In that case you have to
% place the code variations in the right place in your package rather
% than accumulating them at the very end.}
%
% The only other ``extra effort'' necessary when using this approach
% is that it may be advisable to undo new definitions in the code
% block for the previous release, e.g., in the above example we
% undefined |\@widget| as that isn't available in the 2015/01/01
% release but was defined in the main code. If all your conditional
% code is within |\IncludeInRelease| declarations that wouldn't been
% necessary as the new code only gets defined if that release is
% chosen.
%
% \section{Declaring entire modules}
%
% Sometimes a large chunk of code is added as a module to another larger
% code base.  As example of that in the 2020-10-01 release \LaTeX{} got
% a new hook management system, \pkg{lthooks}, which was added in one go
% and, as with all changes to the kernel, it was added to
% \pkg{latexrelease}.  However rolling back from a future date to the
% 2020-10-01 release didn't work because \pkg{latexrelease} would try to
% define again all those commands, which would result in many
% ``already defined'' errors and similar issues.
%
% To solve that problem, completely new modules can be defined in
% \pkg{latexrelease} using the commands:
% \begin{quote}
%   \cs{NewModuleRelease}%^^A
%     \verb|{|\meta{initial release date}%^^A
%       \verb|}{|\meta{name}\verb|}{|\meta{message}\verb|}|\\
%   \null\quad\meta{module code}\\
%   \cs{IncludeInRelease}%^^A
%     \verb|{0000/00/00}{|\meta{name}\verb|}{|\meta{message}\verb|}|\\
%   \null\quad\meta{undefine module code}\\
%   \cs{EndModuleRelease}
% \end{quote}
% With that setup, the module \meta{name} will be declared to exist only
% in releases equal or later \meta{initial release date}.
%
% If \pkg{latexrelease} is rolling backwards or forwards between dates
% after \meta{initial release date}, then all the \meta{module code} is
% skipped, except when inside \meta{IncludeInRelease} guards, in which
% case the code is applied or skipped as discussed above.
%
% If rolling forward from a date before the module's \meta{initial
% release date} to a date after that, then all the \meta{module code} is
% executed to define the module, and \cs{IncludeInRelease} guards are
% executed accordingly, depending on the date declared and the target
% date.
%
% If \pkg{latexrelease} is rolling back to a date before \meta{release
% date}, then the code in the \cs{IncludeInRelease} guard dated
% \verb|0000/00/00| is executed instead to undefine the module.  This
% guard \emph{is not} ended by the usual \cs{EndIncludeInRelease}, but
% instead by \cs{EndModuleRelease}.
%
% Finally, if rolling backwards or forwards between dates both before
% \meta{initial release date}, the entire code between
% \meta{NewModuleRelease} and \meta{EndModuleRelease} is entirely
% skipped.
%
% \subsection{Example}
%
% Here is an example usage of the structure described above, as it would
% be used in the \LaTeX{} kernel, taking \pkg{lthooks} as example:
% \begin{verbatim}
% %<*2ekernel|latexrelease>
% \ExplSyntaxOn
% %<latexrelease>\NewModuleRelease{2020/10/01}{lthooks}%
% %<latexrelease>                 {The~hook~management~system}
% \NewDocumentCommand \NewHook { m }
%   { \hook_new:n {#1} }
% %<latexrelease>\IncludeInRelease{2021/06/01}{\AddToHook}{Long~argument}
% \NewDocumentCommand \AddToHook { m o +m }
%   { \hook_gput_code:nnn {#1} {#2} {#3} }
% %<latexrelease>\EndIncludeInRelease
% %<latexrelease>
% %<latexrelease>\IncludeInRelease{2020/10/01}{\AddToHook}{Long~argument}
% %<latexrelease>\NewDocumentCommand \AddToHook { m o m }
% %<latexrelease>  { \hook_gput_code:nnn {#1} {#2} {#3} }
% %<latexrelease>\EndIncludeInRelease
% %<latexrelease>
% %<latexrelease>\IncludeInRelease{0000/00/00}{lthooks}{Undefine~lthooks}
% %<latexrelease>\cs_undefine:N \NewHook
% %<latexrelease>\cs_undefine:N \AddToHook
% %<latexrelease>\EndModuleRelease
% \ExplSyntaxOff
% %</2ekernel|latexrelease>
% \end{verbatim}
%
% In the example above, \cs{NewHook} is declared only once, and
% unchanged in the next release (2021/06/01 in the example), so it has
% no \cs{IncludeInRelease} guards, and will only be defined if needed.
% \cs{AddToHook}, on the other hand, changed between the two releases
% (made up for the example;  it didn't really happen)
% and has an \cs{IncludeInRelease} block for the current release (off
% \pkg{docstrip} guards, so it goes into the kernel too), and another
% for the previous release (in \pkg{docstrip} guards so it goes only
% into \pkg{latexrelease}).
%
% Note that in the example above, \cs{ExplSyntaxOn} and
% \cs{ExplSyntaxOff} were added \emph{outside} the module code because,
% as discussed above, sometimes the code outside \cs{IncludeInRelease}
% guards may be skipped, but not the code inside them, and in that case
% the catcodes would be wrong when defining the code.
%
% \section{fixltx2e}
%
% As noted above, prior to the 2015 \LaTeX\ release updates to the
% \LaTeX\ kernel were not made in the format source files but were
% made available in the \Lpack{fixltx2e} package. That package is no
% longer needed but we generate a small package from this source
% that just makes a warning message but otherwise does nothing.
%
%
%
%
%
% \MaybeStop{}
%
% \section{Implementation}
%
% We require at least a somewhat sane version of \LaTeXe{}. Earlier
% ones where really quite different from one another.
%    \begin{macrocode}
%<*latexrelease>
\NeedsTeXFormat{LaTeX2e}[1996/06/01]
%    \end{macrocode}
%
% \subsection{Setup}
%
% \begin{macro}{\sourceLaTeXdate}
%   \changes{v1.0l}{2021/01/23}{\cs{sourceLaTeXdate} added}
%   \changes{v1.0m}{2021/03/18}{Define \cs{sourceLaTeXdate} conditionally}
%   Store the original \LaTeX{} format version as a number in the format
%   |YYYYMMDD |.  This macro has to be defined conditionally, so that it
%   isn't changed in case \file{latexrelease.sty} is reloaded, but it
%   can't be defined in the kernel only, otherwise
%   \file{latexrelease.sty} wouldn't work in older \LaTeX{} due
%   to the missing macro.
%    \begin{macrocode}
\@ifundefined{sourceLaTeXdate}{%
  \edef\sourceLaTeXdate{%
    \expandafter\@parse@version\fmtversion//00\@nil}}{}%
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\IncludeInRelease}
% \begin{macro}{\EndIncludeInRelease}
%   These are defined in \file{ltvers.dtx}.
% \end{macro}
% \end{macro}
%
% \changes{v1.0c}{2015/02/19}{Swap argument order}
% \changes{v1.0k}{2018/05/08}{reset \cs{\requestedLaTeXdate} for current
%                             and latest options, github issue 43}
%    \begin{macrocode}
\DeclareOption*{%
  \def\@IncludeInRelease#1[#2]{\@IncludeInRele@se{#1}}%
  \let\requestedpatchdate\CurrentOption}
\DeclareOption{latest}{%
  \let\requestedpatchdate\latexreleaseversion
  \AtEndOfPackage{\def\requestedLaTeXdate{0}}}
\DeclareOption{current}{%
  \let\requestedpatchdate\fmtversion
  \AtEndOfPackage{\def\requestedLaTeXdate{0}}}
%    \end{macrocode}
%
%    \begin{macrocode}
\let\requestedpatchdate\fmtversion
\ProcessOptions\relax
%    \end{macrocode}
%
% Sanity check options, it allows some non-legal dates but always
% ensures |requestedLaTeXdate| gets set to a number.  Generate an
% error if there are any non digit tokens remaining after removing the
% |//|.
% \changes{v1.0j}{2018/01/30}{Explain both date formats in error message}
%    \begin{macrocode}
\def\reserved@a{%
\edef\requestedLaTeXdate{\the\count@}%
\reserved@b}
\def\reserved@b#1\\{%
\def\reserved@b{#1}%
\ifx\reserved@b\@empty\else
\PackageError{latexrelease}%
             {Unexpected option \requestedpatchdate}%
             {The option must be of the form yyyy/mm/dd or yyyy-mm-dd}%
\fi}
\afterassignment\reserved@a
\count@\expandafter
  \@parse@version\expandafter0\requestedpatchdate//00\@nil\\
%    \end{macrocode}
%
% less precautions needed for |\fmtversion|
%    \begin{macrocode}
\edef\currentLaTeXdate{%
   \expandafter\@parse@version\fmtversion//00\@nil}
%    \end{macrocode}
%
%    \begin{macrocode}
\ifnum\requestedLaTeXdate=\currentLaTeXdate
\PackageWarningNoLine{latexrelease}{%
  Current format date selected, no patches applied}
\expandafter\endinput
\fi
%    \end{macrocode}
%
% A newer version of latexrelease should have been distributed with
% the later format.
%    \begin{macrocode}
\ifnum\currentLaTeXdate
  >\expandafter\@parse@version\latexreleaseversion//00\@nil
\PackageWarningNoLine{latexrelease}{%
The current package is for an older LaTeX format:\MessageBreak
LaTeX \latexreleaseversion\space\MessageBreak
Obtain a newer version of this package!}
\expandafter\endinput
\fi
%    \end{macrocode}
% can't patch into the future, could make this an error
% but it has some uses to control package updates
% so allow for now.
%    \begin{macrocode}
\ifnum\requestedLaTeXdate
  >\expandafter\@parse@version\latexreleaseversion//00\@nil
\PackageWarningNoLine{latexrelease}{%
The current package is for LaTeX \latexreleaseversion:\MessageBreak
It has no patches beyond that date\MessageBreak
There may be an updated version\MessageBreak
of this package available from CTAN}
\expandafter\endinput
\fi
%    \end{macrocode}
%
% Update the format version to the requested date.
%    \begin{macrocode}
\let\fmtversion\requestedpatchdate
\let\currentLaTeXdate\requestedLaTeXdate
%    \end{macrocode}
%
%
% \subsection{Ignoring \texttt{\string_new} errors when rolling back}
%
% Enforce \cs{ExplSyntaxOn} and \cs{ExplSyntaxOff} to be \cs{relax} in
% \pkg{latexrelease} if they are not yet defined.  They are later
% restored to be undefined if needed.
%    \begin{macrocode}
\csname ExplSyntaxOn\endcsname
\csname ExplSyntaxOff\endcsname
%    \end{macrocode}
%
% \changes{v1.0m}{2021/03/18}
%         {Make \texttt{\string_new} definitions harmless}
%
% Define a set of changes here, but we'll only use them later to make
% sure they are applied after \pkg{expl3} is loaded.  If loading from a
% rather old format, we don't have \cs{ExplSyntaxOn} yet.
%    \begin{macrocode}
\begingroup
  \endlinechar=-1
  \catcode95=11 % _
  \catcode58=11 % :
  \catcode126=10 % ~
  \catcode32=09 % <space>
  \xdef\latexrelease@postltexpl{\unexpanded{%
%<@@=latexrelease>
%    \end{macrocode}
%
% First we'll define a \cs{declarecommand} that does \cs{renewcommand}
% if the command being defined already exists, and \cs{newcommand}
% otherwise.
%    \begin{macrocode}
\cs_gset_protected:Npn \@@_declare_command:w
  { \@star@or@long \@@_declare_command:Nw }
\cs_gset_protected:Npn \@@_declare_command:Nw #1
  { \cs_if_exist:NTF #1 { \renew@command } { \new@command } #1 }
%    \end{macrocode}
%
% Then define a version of \cs{e@alloc} that checks if the control
% sequence being defined already exists, and if so, checks if its
% meaning is the same as the one that would be defined with the call to
% \cs{e@alloc}.  If both tests pass, nothing is defined to save a
% register.  This version also takes care of setting
% \cs{allocationnumber} to the value it would have after the register is
% allocated.
%    \begin{macrocode}
\cs_gset_protected:Npn \@@_e@alloc:NnnnnN #1 #2 #3 #4 #5 #6
  {
    \cs_if_free:NTF #6
      { \use:n }
      {
        \exp_after:wN \@@_e@alloc:N
          \token_to_meaning:N #6 \scan_stop: {#2} #6
      }
        { \@@_e@alloc #1 {#2} {#3} {#4} {#5} #6 }
  }
%    \end{macrocode}
% Walk through the meaning of the control sequence token by token,
% looking for the register allocation number.
%    \begin{macrocode}
\cs_gset_protected:Npn \@@_e@alloc:N #1
  {
    \if_int_compare:w 0 < 0
        \if_int_compare:w 10 < 9#1 ~ 1 \fi:
        \if_charcode:w " #1 1 \fi: \exp_stop_f:
      \tex_afterassignment:D \@@_e@alloc:w
      \@tempcnta #1
      \use_i:nnn
    \fi:
    \use:n
      {
        \if_meaning:w \scan_stop: #1
          \exp_after:wN \use_iv:nnnn
        \fi:
        \@@_e@alloc:N
      }
  }
%    \end{macrocode}
% When found, check if it is the exact same register as it would be
% allocated, and if it is, set \cs{allocationnumber} accordingly and
% exit, otherwise undefine the register and allocate from scratch.
%    \begin{macrocode}
\cs_gset_protected:Npn \@@_e@alloc:w #1 \scan_stop: #2 #3
  {
    #2 \@@_tmp:w = \@tempcnta
    \token_if_eq_meaning:NNTF #3 \@@_tmp:w
      { \int_set_eq:NN \allocationnumber \@tempcnta  \use_none:n }
      { \cs_set_eq:NN #3 \tex_undefined:D            \use:n      }
  }
%    \end{macrocode}
%
% Now create a token list to hold the list of changed commands, and
% define a temporary macro that will loop through the command list,
% store each in \cs{l_@@_restores_tl}, save a copy, and redefine each.
%    \begin{macrocode}
\tl_clear_new:N \l_@@_restores_tl
\cs_gset:Npn \@@_redefines:w #1 #2
  {
    \quark_if_recursion_tail_stop:N #1
    \tl_put_right:Nn \l_@@_restores_tl {#1}
    \cs_set_eq:cN { @@_ \cs_to_str:N #1 } #1
    \cs_set_eq:NN #1 #2
    \@@_redefines:w
  }
%    \end{macrocode}
%
% The redefinitions below are needed because:
% \begin{description}
%   \def\makelabel#1{\cs{#1}}
%   \item[__kernel_chk_if_free_cs:N] This function is used ubiquitously
%     in the \pkg{l3kernel} to check if a control sequence is definable,
%     and give an error otherwise (similar to \cs{@ifdefinable}).
%     Making it a no-op is enough for most cases (except when defining
%     new registers);
%   \item[e@alloc] In the case of new registers, we waste an allocation
%     number if we do \cs[no-index]{new\meta{thing}} in a register
%     that's already allocated, so the redefinition of \cs{e@alloc}
%     checks if the new register is really necessary.  This code does
%     not clear the register, which might cause problems in the future,
%     if a register is allocated but not properly cleared before using;
%   \item[__kernel_msg_error:nnx] This command is used to error on
%     already defined scan marks.  Just making the error do nothing is
%     enough, as no action is taken in that case;
%   \item[msg_new:nnnn] Used to define new messages.  Making it
%     \texttt{\string_gset} is enough.  Other msg commands like
%     \cs{msg_new:nnn} and \cs[no-index]{__kernel_msg_new:nnn(n)} are
%     defined in terms of \cs{msg_new:nnnn}, so there is no need to
%     change the other ones;
%   \item[NewDocumentCommand] Used to define user-level commands in the
%     kernel.  Making it equal to \cs{DeclareDocumentCommand} solves the
%     problem;
%   \item[newcommand] Same as above.
% \end{description}
% And here we go:
%    \begin{macrocode}
\@@_redefines:w
  \__kernel_chk_if_free_cs:N \use_none:n
  \e@alloc \@@_e@alloc:NnnnnN
  \__kernel_msg_error:nnx \use_none:nnn
  \msg_new:nnnn \msg_gset:nnnn
  % \NewDocumentCommand \DeclareDocumentCommand % after ltcmd.dtx
  \newcommand \@@_declare_command:w
%    \end{macrocode}
%    Temp addition \ldots
%    \begin{macrocode}
  \__kernel_msg_error:nnn  \use_none:nnn  % needed while redirect for kernel msgs doesn't work
  \q_recursion_tail \q_recursion_tail
  \q_recursion_stop
%    \end{macrocode}
%
% Finally, redirect the error thrown by \cs{NewHook} to nowhere so it
% can be safely reused (the hook isn't redeclared if it already exists).
%    \begin{macrocode}
\msg_redirect_name:nnn { hooks } { exists } { none }
%    \end{macrocode}
%
% Now a one-off for |ltcmd.dtx|: we need to make \cs{NewDocumentCommand}
% not complain on an already existing command, but it has to be done
% after \cs{NewDocumentCommand} is defined, so this is separate from
% the \cs{latexrelease@postltexpl} actions above:
% \changes{v1.0o}{2022/02/28}
%         {Move most redefinitions to right after ltexpl.dtx}
%    \begin{macrocode}
\cs_gset_protected:Npn \latexrelease@postltcmd
  {
    \@@_redefines:w
      \NewDocumentCommand \DeclareDocumentCommand
      \q_recursion_tail \q_recursion_tail
      \q_recursion_stop
  }
%    \end{macrocode}
%
%    \begin{macrocode}
  }}%
\endgroup
%</latexrelease>
%    \end{macrocode}
%
% \subsection{Undoing the temp modifications}
%
% If \cs{ExplSyntaxOn} exists (defined and not equal \cs{relax}), then
% use the \pkg{expl3} restore code, otherwise restore \cs{ExplSyntaxOn}
% and \cs{ExplSyntaxOff} to be undefined.
%    \begin{macrocode}
%<*latexrelease-finish>
\@ifundefined{ExplSyntaxOn}%
  {\let\ExplSyntaxOn\@undefined
   \let\ExplSyntaxOff\@undefined
   \@gobble}%
  {\ExplSyntaxOn
   \@firstofone}%
  {%
%    \end{macrocode}
%
% Now just loop through the list of redefined commands and restore their
% previous meanings.
%    \begin{macrocode}
\tl_map_inline:Nn \l_@@_restores_tl
  {
    \cs_set_eq:Nc #1 { @@_ \cs_to_str:N #1 }
    \cs_undefine:c { @@_ \cs_to_str:N #1 }
  }
\tl_clear:N \l_@@_restores_tl
%    \end{macrocode}
%
% And restore the hook error message.
%    \begin{macrocode}
\msg_redirect_name:nnn { hooks } { exists } { }
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=>
  \ExplSyntaxOff}%
%</latexrelease-finish>
%    \end{macrocode}
%
% \subsection{Individual Changes}
%
% The code for each change will be inserted at this point, extracted
% from the kernel source files.
%
%
% \subsection{fixltx2e}
%
% Generate a stub \Lpack{fixltx2e} package:
%    \begin{macrocode}
%<*fixltx2e>
\IncludeInRelease{2015/01/01}{\fixltxe}{Old fixltx2e package}
\NeedsTeXFormat{LaTeX2e}
\PackageWarningNoLine{fixltx2e}{%
fixltx2e is not required with releases after 2015\MessageBreak
All fixes are now in the LaTeX kernel.\MessageBreak
See the latexrelease package for details}
\EndIncludeInRelease
\IncludeInRelease{0000/00/00}{\fixltxe}{Old fixltx2e package}
\def\@outputdblcol{%
  \if@firstcolumn
    \global\@firstcolumnfalse
    \global\setbox\@leftcolumn\copy\@outputbox
    \splitmaxdepth\maxdimen
    \vbadness\maxdimen
     \setbox\@outputbox\vbox{\unvbox\@outputbox\unskip}%
     \setbox\@outputbox\vsplit\@outputbox to\maxdimen
    \toks@\expandafter{\topmark}%
    \xdef\@firstcoltopmark{\the\toks@}%
    \toks@\expandafter{\splitfirstmark}%
    \xdef\@firstcolfirstmark{\the\toks@}%
    \ifx\@firstcolfirstmark\@empty
      \global\let\@setmarks\relax
    \else
      \gdef\@setmarks{%
        \let\firstmark\@firstcolfirstmark
        \let\topmark\@firstcoltopmark}%
    \fi
  \else
    \global\@firstcolumntrue
    \setbox\@outputbox\vbox{%
     \hb@xt@\textwidth{%
        \hb@xt@\columnwidth{\box\@leftcolumn \hss}%
        \hfil
        {\normalcolor\vrule \@width\columnseprule}%
        \hfil
       \hb@xt@\columnwidth{\box\@outputbox \hss}}}%
  \@combinedblfloats
    \@setmarks
    \@outputpage
    \begingroup
      \@dblfloatplacement
      \@startdblcolumn
      \@whilesw\if@fcolmade \fi{\@outputpage\@startdblcolumn}%
    \endgroup
  \fi}
\def\end@dblfloat{%
  \if@twocolumn
    \@endfloatbox
    \ifnum\@floatpenalty <\z@
      \@largefloatcheck
      \global\dp\@currbox1sp %
      \@cons\@currlist\@currbox
      \ifnum\@floatpenalty <-\@Mii
        \penalty -\@Miv
        \@tempdima\prevdepth
        \vbox{}%
        \prevdepth\@tempdima
        \penalty\@floatpenalty
      \else
        \vadjust{\penalty -\@Miv \vbox{}\penalty\@floatpenalty}\@Esphack
      \fi
    \fi
  \else
    \end@float
  \fi
}
\def\@testwrongwidth #1{%
  \ifdim\dp#1=\f@depth
  \else
    \global\@testtrue
  \fi}
\let\f@depth\z@
\def\@dblfloatplacement{\global\@dbltopnum\c@dbltopnumber
   \global\@dbltoproom \dbltopfraction\@colht
   \@textmin \@colht
   \advance \@textmin -\@dbltoproom
   \@fpmin \dblfloatpagefraction\textheight
   \@fptop \@dblfptop
   \@fpsep \@dblfpsep
   \@fpbot \@dblfpbot
   \def\f@depth{1sp}}
\def \@doclearpage {%
     \ifvoid\footins
       \setbox\@tempboxa\vsplit\@cclv to\z@ \unvbox\@tempboxa
       \setbox\@tempboxa\box\@cclv
       \xdef\@deferlist{\@toplist\@botlist\@deferlist}%
       \global \let \@toplist \@empty
       \global \let \@botlist \@empty
       \global \@colroom \@colht
       \ifx \@currlist\@empty
       \else
          \@latexerr{Float(s) lost}\@ehb
          \global \let \@currlist \@empty
       \fi
       \@makefcolumn\@deferlist
       \@whilesw\if@fcolmade \fi{\@opcol\@makefcolumn\@deferlist}%
       \if@twocolumn
         \if@firstcolumn
           \xdef\@deferlist{\@dbltoplist\@deferlist}%
           \global \let \@dbltoplist \@empty
           \global \@colht \textheight
           \begingroup
              \@dblfloatplacement
              \@makefcolumn\@deferlist
              \@whilesw\if@fcolmade \fi{\@outputpage
                                        \@makefcolumn\@deferlist}%
           \endgroup
         \else
           \vbox{}\clearpage
         \fi
       \fi
       \ifx\@deferlist\@empty \else\clearpage \fi
     \else
       \setbox\@cclv\vbox{\box\@cclv\vfil}%
       \@makecol\@opcol
       \clearpage
     \fi
}
\def \@startdblcolumn {%
  \@tryfcolumn \@deferlist
  \if@fcolmade
  \else
    \begingroup
      \let \reserved@b \@deferlist
      \global \let \@deferlist \@empty
      \let \@elt \@sdblcolelt
      \reserved@b
    \endgroup
  \fi
}
\def\@addtonextcol{%
  \begingroup
   \@insertfalse
   \@setfloattypecounts
   \ifnum \@fpstype=8
   \else
     \ifnum \@fpstype=24
     \else
       \@flsettextmin
       \@reqcolroom \ht\@currbox
       \advance \@reqcolroom \@textmin
       \ifdim \@colroom>\@reqcolroom
         \@flsetnum \@colnum
         \ifnum\@colnum>\z@
            \@bitor\@currtype\@deferlist
            \@testwrongwidth\@currbox
            \if@test
            \else
              \@addtotoporbot
            \fi
         \fi
       \fi
     \fi
   \fi
   \if@insert
   \else
     \@cons\@deferlist\@currbox
   \fi
  \endgroup
}
\def\@addtodblcol{%
  \begingroup
   \@insertfalse
   \@setfloattypecounts
   \@getfpsbit \tw@
   \ifodd\@tempcnta
     \@flsetnum \@dbltopnum
     \ifnum \@dbltopnum>\z@
       \@tempswafalse
       \ifdim \@dbltoproom>\ht\@currbox
         \@tempswatrue
       \else
         \ifnum \@fpstype<\sixt@@n
           \advance \@dbltoproom \@textmin
           \ifdim \@dbltoproom>\ht\@currbox
             \@tempswatrue
           \fi
           \advance \@dbltoproom -\@textmin
         \fi
       \fi
       \if@tempswa
           \@bitor \@currtype \@deferlist
          \@testwrongwidth\@currbox
           \if@test
           \else
              \@tempdima -\ht\@currbox
              \advance\@tempdima
                -\ifx \@dbltoplist\@empty \dbltextfloatsep \else
                                          \dblfloatsep \fi
              \global \advance \@dbltoproom \@tempdima
              \global \advance \@colht \@tempdima
              \global \advance \@dbltopnum \m@ne
              \@cons \@dbltoplist \@currbox
              \@inserttrue
           \fi
       \fi
     \fi
   \fi
   \if@insert
   \else
     \@cons\@deferlist\@currbox
   \fi
  \endgroup
}
\def \@addtocurcol {%
   \@insertfalse
   \@setfloattypecounts
   \ifnum \@fpstype=8
   \else
     \ifnum \@fpstype=24
     \else
       \@flsettextmin
       \advance \@textmin \@textfloatsheight
       \@reqcolroom \@pageht
       \ifdim \@textmin>\@reqcolroom
         \@reqcolroom \@textmin
       \fi
       \advance \@reqcolroom \ht\@currbox
       \ifdim \@colroom>\@reqcolroom
         \@flsetnum \@colnum
         \ifnum \@colnum>\z@
           \@bitor\@currtype\@deferlist
          \@testwrongwidth\@currbox
           \if@test
           \else
             \@bitor\@currtype\@botlist
             \if@test
               \@addtobot
             \else
               \ifodd \count\@currbox
                 \advance \@reqcolroom \intextsep
                 \ifdim \@colroom>\@reqcolroom
                   \global \advance \@colnum \m@ne
                   \global \advance \@textfloatsheight \ht\@currbox
                   \global \advance \@textfloatsheight 2\intextsep
                   \@cons \@midlist \@currbox
                   \if@nobreak
                     \nobreak
                     \@nobreakfalse
                     \everypar{}%
                   \else
                     \addpenalty \interlinepenalty
                   \fi
                   \vskip \intextsep
                   \box\@currbox
                   \penalty\interlinepenalty
                   \vskip\intextsep
                   \ifnum\outputpenalty <-\@Mii \vskip -\parskip\fi
                   \outputpenalty \z@
                   \@inserttrue
                 \fi
               \fi
               \if@insert
               \else
                 \@addtotoporbot
               \fi
             \fi
           \fi
         \fi
       \fi
     \fi
   \fi
   \if@insert
   \else
     \@resethfps
     \@cons\@deferlist\@currbox
   \fi
}
\def\@xtryfc #1{%
  \@next\reserved@a\@trylist{}{}%
  \@currtype \count #1%
  \divide\@currtype\@xxxii
  \multiply\@currtype\@xxxii
  \@bitor \@currtype \@failedlist
  \@testfp #1%
  \@testwrongwidth #1%
  \ifdim \ht #1>\@colht
     \@testtrue
  \fi
  \if@test
    \@cons\@failedlist #1%
  \else
    \@ytryfc #1%
  \fi}
\def\@ztryfc #1{%
  \@tempcnta\count #1%
  \divide\@tempcnta\@xxxii
  \multiply\@tempcnta\@xxxii
  \@bitor \@tempcnta {\@failedlist \@flfail}%
  \@testfp #1%
  \@testwrongwidth #1%
  \@tempdimb\@tempdima
  \advance\@tempdimb\ht #1%
  \advance\@tempdimb\@fpsep
  \ifdim \@tempdimb >\@colht
    \@testtrue
  \fi
  \if@test
    \@cons\@flfail #1%
  \else
    \@cons\@flsucceed #1%
    \@tempdima\@tempdimb
  \fi}
\def\@{\spacefactor\@m{}}
\def\@tempa#1#2{#1#2\relax}
\ifx\setlength\@tempa
  \def\setlength#1#2{#1 #2\relax}
\fi
\def\addpenalty#1{%
  \ifvmode
    \if@minipage
    \else
      \if@nobreak
      \else
        \ifdim\lastskip=\z@
          \penalty#1\relax
        \else
          \@tempskipb\lastskip
          \begingroup
            \advance \@tempskipb
              \ifdim\prevdepth>\maxdepth\maxdepth\else
                 \ifdim \prevdepth = -\@m\p@ \z@ \else \prevdepth \fi
               \fi
             \vskip -\@tempskipb
             \penalty#1%
             \vskip\@tempskipb
          \endgroup
          \vskip -\@tempskipb
          \vskip \@tempskipb
        \fi
      \fi
    \fi
  \else
    \@noitemerr
  \fi}
\def\@fnsymbol#1{%
   \ifcase#1\or \TextOrMath\textasteriskcentered *\or
   \TextOrMath \textdagger \dagger\or
   \TextOrMath \textdaggerdbl \ddagger \or
   \TextOrMath \textsection  \mathsection\or
   \TextOrMath \textparagraph \mathparagraph\or
   \TextOrMath \textbardbl \|\or
   \TextOrMath {\textasteriskcentered\textasteriskcentered}{**}\or
   \TextOrMath {\textdagger\textdagger}{\dagger\dagger}\or
   \TextOrMath {\textdaggerdbl\textdaggerdbl}{\ddagger\ddagger}\else
   \@ctrerr \fi
}
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname eTeXversion\endcsname\relax
\DeclareRobustCommand\TextOrMath{%
  \ifmmode  \expandafter\@secondoftwo
  \else     \expandafter\@firstoftwo  \fi}
\protected@edef\TextOrMath#1#2{\TextOrMath{#1}{#2}}
\else
\protected\expandafter\def\csname TextOrMath\space\endcsname{%
  \ifmmode  \expandafter\@secondoftwo
  \else     \expandafter\@firstoftwo  \fi}
\edef\TextOrMath#1#2{%
  \expandafter\noexpand\csname TextOrMath\space\endcsname
  {#1}{#2}}
\fi
\def\@esphack{%
  \relax
  \ifhmode
    \spacefactor\@savsf
    \ifdim\@savsk>\z@
      \nobreak \hskip\z@skip  % <------
      \ignorespaces
    \fi
  \fi}
\def\@Esphack{%
  \relax
  \ifhmode
    \spacefactor\@savsf
    \ifdim\@savsk>\z@
      \nobreak \hskip\z@skip  % <------
      \@ignoretrue
      \ignorespaces
    \fi
   \fi}
\DeclareRobustCommand\em
        {\@nomath\em \ifdim \fontdimen\@ne\font >\z@
                       \eminnershape \else \itshape \fi}
\def\eminnershape{\upshape}
\DeclareRobustCommand*\textsubscript[1]{%
  \@textsubscript{\selectfont#1}}
\def\@textsubscript#1{%
  {\m@th\ensuremath{_{\mbox{\fontsize\sf@size\z@#1}}}}}
\def\@DeclareMathSizes #1#2#3#4#5{%
  \@defaultunits\dimen@ #2pt\relax\@nnil
  \if $#3$%
    \expandafter\let\csname S@\strip@pt\dimen@\endcsname\math@fontsfalse
  \else
    \@defaultunits\dimen@ii #3pt\relax\@nnil
    \@defaultunits\@tempdima #4pt\relax\@nnil
    \@defaultunits\@tempdimb #5pt\relax\@nnil
    \toks@{#1}%
    \expandafter\xdef\csname S@\strip@pt\dimen@\endcsname{%
      \gdef\noexpand\tf@size{\strip@pt\dimen@ii}%
      \gdef\noexpand\sf@size{\strip@pt\@tempdima}%
      \gdef\noexpand\ssf@size{\strip@pt\@tempdimb}%
      \the\toks@
    }%
  \fi
}
\providecommand*\MakeRobust[1]{%
  \@ifundefined{\expandafter\@gobble\string#1}{%
    \@latex@error{The control sequence `\string#1' is undefined!%
      \MessageBreak There is nothing here to make robust}%
    \@eha
  }%
  {%
    \@ifundefined{\expandafter\@gobble\string#1\space}%
    {%
      \expandafter\let\csname
      \expandafter\@gobble\string#1\space\endcsname=#1%
      \edef\reserved@a{\string#1}%
      \def\reserved@b{#1}%
      \edef\reserved@b{\expandafter\strip@prefix\meaning\reserved@b}%
      \edef#1{%
        \ifx\reserved@a\reserved@b
          \noexpand\x@protect\noexpand#1%
        \fi
        \noexpand\protect\expandafter\noexpand
        \csname\expandafter\@gobble\string#1\space\endcsname}%
    }%
    {\@latex@info{The control sequence `\string#1' is already robust}}%
   }%
}
\MakeRobust\(
\MakeRobust\)
\MakeRobust\[
\MakeRobust\]
\MakeRobust\makebox
\MakeRobust\savebox
\MakeRobust\framebox
\MakeRobust\parbox
\MakeRobust\rule
\MakeRobust\raisebox
\def\@xfloat #1[#2]{%
  \@nodocument
  \def \@captype {#1}%
   \def \@fps {#2}%
   \@onelevel@sanitize \@fps
   \def \reserved@b {!}%
   \ifx \reserved@b \@fps
     \@fpsadddefault
   \else
     \ifx \@fps \@empty
       \@fpsadddefault
     \fi
   \fi
   \ifhmode
     \@bsphack
     \@floatpenalty -\@Mii
   \else
     \@floatpenalty-\@Miii
   \fi
  \ifinner
     \@parmoderr\@floatpenalty\z@
  \else
    \@next\@currbox\@freelist
      {%
       \@tempcnta \sixt@@n
       \expandafter \@tfor \expandafter \reserved@a
         \expandafter :\expandafter =\@fps
         \do
          {%
           \if \reserved@a h%
             \ifodd \@tempcnta
             \else
               \advance \@tempcnta \@ne
             \fi
           \else\if \reserved@a t%
             \@setfpsbit \tw@
           \else\if \reserved@a b%
             \@setfpsbit 4%
           \else\if \reserved@a p%
             \@setfpsbit 8%
           \else\if \reserved@a !%
             \ifnum \@tempcnta>15
               \advance\@tempcnta -\sixt@@n\relax
             \fi
           \else
             \@latex@error{Unknown float option `\reserved@a'}%
             {Option `\reserved@a' ignored and `p' used.}%
             \@setfpsbit 8%
           \fi\fi\fi\fi\fi
           }%
       \@tempcntb \csname ftype@\@captype \endcsname
       \multiply \@tempcntb \@xxxii
       \advance \@tempcnta \@tempcntb
       \global \count\@currbox \@tempcnta
       }%
    \@fltovf
  \fi
  \global \setbox\@currbox
    \color@vbox
      \normalcolor
      \vbox \bgroup
        \hsize\columnwidth
        \@parboxrestore
        \@floatboxreset
}
 \def\@stpelt#1{\global\csname c@#1\endcsname \m@ne\stepcounter{#1}}
\EndIncludeInRelease
%</fixltx2e>
%    \end{macrocode}
%
% \Finale
%
\endinput
back to top