% \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} % % \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|latexrelease> % %\IncludeInRelease{2020/10/01}{\@currpath}% % {Add \@currpath}% \let\@currpath\@empty %\EndIncludeInRelease % %\IncludeInRelease{0000/00/00}{\@currpath}% % {Add \@currpath}% %\let\@currpath\@undefined %\EndIncludeInRelease % %<*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|latexrelease> % %\IncludeInRelease{2020/10/01}{\@pushfilename}% % {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@@} %\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} % %\IncludeInRelease{2020/02/02}{\@pushfilename}% % {Add \@expl@push@filename@@}% %\def\@pushfilename{% % \@expl@push@filename@@ % \xdef\@currnamestack{% % {\@currname}% % {\@currext}% % {\the\catcode`\@}% % \@currnamestack}% % \@expl@push@filename@aux@@} %\EndIncludeInRelease % % \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} %\IncludeInRelease{0000/00/00}{\@pushfilename}% % {Add \@expl@push@filename@@ and \@expl@push@filename@aux@@}% %\ifnum\sourceLaTeXdate<20200202\relax % \GenericInfo{}{Defining 00-00-00\string\@pushfilename.} %\def\@pushfilename{% % \xdef\@currnamestack{% % {\@currname}% % {\@currext}% % {\the\catcode`\@}% % \@currnamestack}} %\else % \GenericInfo{}{Defining 2020-02-02\string\@pushfilename.} %\def\@pushfilename{% % \@expl@push@filename@@ % \xdef\@currnamestack{% % {\@currname}% % {\@currext}% % {\the\catcode`\@}% % \@currnamestack}% % \@expl@push@filename@aux@@} %\fi %\EndIncludeInRelease \@onlypreamble\@pushfilename % \end{macrocode} % % % % % % \changes{v1.3l}{2020/06/05}{Added \cs{@expl@pop@filename@@}} % \begin{macrocode} % %\IncludeInRelease{2020/10/01}{\@popfilename}% % {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@@} %\EndIncludeInRelease % %\IncludeInRelease{2020/02/02}{\@popfilename}% % {Add \@expl@push@filename@@}% %\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil % \@expl@pop@filename@@} %\EndIncludeInRelease % % \end{macrocode} % % \changes{v1.4a}{2021/03/27} % {Do not completely roll back if \pkg{expl3} is loaded.} % \begin{macrocode} %\IncludeInRelease{0000/00/00}{\@popfilename}% % {Add \@expl@push@filename@@ and \@expl@push@filename@aux@@}% %\ifnum\sourceLaTeXdate<20200202\relax % \GenericInfo{}{Defining 00-00-00\string\@popfilename.} %\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil} %\else % \GenericInfo{}{Defining 2020-02-02\string\@popfilename.} %\def\@popfilename{\expandafter\@p@pfilename\@currnamestack\@nil % \@expl@pop@filename@@} %\fi %\EndIncludeInRelease \@onlypreamble\@popfilename % \end{macrocode} % % \begin{macrocode} % %<*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|latexrelease> % %\IncludeInRelease{2020/10/01}{\@kernel@currpathstack}% % {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} %\@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} %\ifx\@kernel@currpathstack\@empty % \def\reserved@a#1#2#3{% % \ifx\relax#3\else % \g@addto@macro\@kernel@currpathstack{{}}% % \expandafter\reserved@a % \fi}% % \expandafter\reserved@a\@currnamestack{}{}{\relax}% %\fi \def\@p@pfilepath#1{% \gdef\@currpath{#1}\@p@pfilepath@aux\@empty} \def\@p@pfilepath@aux#1\@nil{% \xdef\@kernel@currpathstack{#1}} %\EndIncludeInRelease % %\IncludeInRelease{0000/00/00}{\@kernel@currpathstack}% % {Add \@kernel@currpathstack}% %\let\@kernel@currpathstack\@undefined %\let\@p@pfilepath\@undefined %\let\@p@pfilepath@aux\@undefined %\EndIncludeInRelease % %<*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|latexrelease> %\IncludeInRelease{2020/10/01}% % {\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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\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} %\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} % % \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} %\IncludeInRelease{2018/04/01}% % {\@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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@ifl@t@r}{Guard against bad input}% %\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} %\let\@parse@version@\@undefined %\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|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> % \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} % %\IncludeInRelease{2017/01/01}% % {\@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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@if@pti@ns}{Spaces in option clash check}% %\def\@if@pti@ns#1#2{% % \let\reserved@a\@firstoftwo % \@for\reserved@b:=#2\do{% % \ifx\reserved@b\@empty % \else % \expandafter\in@\expandafter % {\expandafter,\reserved@b,}{,#1,}% % \ifin@ % \else % \let\reserved@a\@secondoftwo % \fi % \fi % }% % \reserved@a} %\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|latexrelease> %\IncludeInRelease{2021/11/15}% % {\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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\IfPackageLoadedtTF}{Test package loading}% % %\let \IfPackageLoadedTF \@ifpackageloaded %\let \IfClassLoadedTF \@ifclassloaded %\let \IfPackageLoadedWithOptionsTF \@ifpackagewith %\let \IfClassLoadedWithOptionsTF \@ifclasswith % %\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} % %\IncludeInRelease{2020/10/01}% % {\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 % %\EndIncludeInRelease % %\IncludeInRelease{0000/00/00}% % {\ProvidesPackage}{Undo: check name with \strcmp}% %\def\ProvidesPackage#1{% % \xdef\@gtempa{#1}% % \ifx\@gtempa\@currname\else % \@latex@warning@no@line{You have requested % \@cls@pkg\space`\@currname',\MessageBreak % but the \@cls@pkg\space provides `#1'}% % \fi % \@ifnextchar[\@pr@videpackage{\@pr@videpackage[]}}%] %\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|latexrelease> %\IncludeInRelease{2020/10/01}% % {\@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} % %\EndIncludeInRelease %\IncludeInRelease{2020/02/02}% % {\@pr@videpackage}{Protection for package info}% % %\def\@pr@videpackage[#1]{% % \expandafter\protected@xdef % <-- protected... % \csname ver@\@currname.\@currext\endcsname{#1}% %\ifx\@currext\@clsextension % \typeout{Document Class: \@gtempa\space#1}% % \else % \protected@wlog{Package: \@gtempa\space#1}% <--- protected % \fi} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@pr@videpackage}{Protection for package info}% % %\def\@pr@videpackage[#1]{% % \expandafter\xdef\csname ver@\@currname.\@currext\endcsname{#1}% % \ifx\@currext\@clsextension % \typeout{Document Class: \@gtempa\space#1}% % \else % \wlog{Package: \@gtempa\space#1}% % \fi} %\let\protected@wlog\@undefined % %\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} % %\IncludeInRelease{0000/00/00}% % {\ProvidesClass}{Track \ProvidesPackage}% %<*2ekernel|latexrelease> \let\ProvidesClass\ProvidesPackage \@onlypreamble\ProvidesClass % %\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} % %\IncludeInRelease{2021/06/01}% % {\@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}}% } % %\EndIncludeInRelease % \end{macrocode} % % \begin{macrocode} %\IncludeInRelease{2020/10/01}{\@pass@ptions} % {Add file replacement in \@pass@ptions}% % %\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@@ % \expandafter\xdef\csname opt@\reserved@a\endcsname{% % \@ifundefined{opt@\reserved@a}\@empty % {\csname opt@\reserved@a\endcsname,}% % \zap@space#2 \@empty}% % \expandafter\let % \csname opt@#3.#1\expandafter\endcsname % \csname opt@\reserved@a\endcsname} %\EndIncludeInRelease % \end{macrocode} % % \begin{macrocode} %\IncludeInRelease{0000/00/00}{\@pass@ptions} % {\@pass@ptions}% % %\def\@pass@ptions#1#2#3{% % \expandafter\xdef\csname opt@#3.#1\endcsname{% % \@ifundefined{opt@#3.#1}\@empty % {\csname opt@#3.#1\endcsname,}% % \zap@space#2 \@empty}} %\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} % %\IncludeInRelease{2021/06/01}% % {\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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\OptionNotUsed}{filter unused option list}% %\let\@remove@eq@value\@undefined % \end{macrocode} % % \begin{macrocode} %\def\OptionNotUsed{% % \ifx\@currext\@clsextension % \xdef\@unusedoptionlist{% % \ifx\@unusedoptionlist\@empty\else\@unusedoptionlist,\fi % \CurrentOption}% % \fi} %\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} % %\IncludeInRelease{2021/06/01}% % {\@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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@xprocess@ptions}{safer @xprocess@ptions}% %\let\@remove@eq@value\@undefined % \end{macrocode} % % \begin{macrocode} %\def\@xprocess@ptions{% % \ifx\@currext\@clsextension\else % \@for\CurrentOption:=\@classoptionslist\do{% % \ifx\CurrentOption\@empty\else % \@expandtwoargs\in@{,\CurrentOption,}{,\@declaredoptions,}% % \ifin@ % \@use@ption % \expandafter\let\csname ds@\CurrentOption\endcsname\@empty % \fi % \fi}% % \fi % \@process@pti@ns} %\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|latexrelease> %\IncludeInRelease{2020/10/01}% % {\@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 % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@process@pti@ns}{Unused options issue}% % %\def\@process@pti@ns{% % \@for\CurrentOption:=\@curroptions\do{% % \@ifundefined{ds@\CurrentOption}% % {\@use@ption % \default@ds}% % \@use@ption}% % \@for\CurrentOption:=\@declaredoptions\do{% % \expandafter\let\csname ds@\CurrentOption\endcsname\relax}% % \let\CurrentOption\@empty % \let\@fileswith@pti@ns\@@fileswith@pti@ns % \AtEndOfPackage{\let\@unprocessedoptions\relax}} %\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} % %\IncludeInRelease{2021/06/01}% % {\@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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@use@ption}{filter unused option list}% %\def\@use@ption{% % \@expandtwoargs\@removeelement\CurrentOption % \@unusedoptionlist\@unusedoptionlist % \csname ds@\CurrentOption\endcsname} %\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} % %\IncludeInRelease{2017/01/01}% % {\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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\ExecuteOptions}{Spaces in \ExecuteOptions}% %\def\ExecuteOptions#1{% % \def\reserved@a##1\@nil{% % \@for\CurrentOption:=#1\do % {\csname ds@\CurrentOption\endcsname}% % \edef\CurrentOption{##1}}% % \expandafter\reserved@a\CurrentOption\@nil} %\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} % %\IncludeInRelease{2021/06/01}% % {\@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}} % %\EndIncludeInRelease % \end{macrocode} % % \begin{macrocode} %\IncludeInRelease{0000/00/00} % {\@loadwithoptions}{Raw option lists load with options}% %\def\@loadwithoptions#1#2#3{% % \expandafter\let\csname opt@#3.#1\expandafter\endcsname % \csname opt@\@currname.\@currext\endcsname % #2{#3}} %\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|latexrelease> %\IncludeInRelease{2020/10/01}% % {\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 % %\EndIncludeInRelease % \end{macrocode} % % \begin{macrocode} %\IncludeInRelease{0000/00/00}% % {\RequirePackageWithOptions}{Unused options issue}% % %\def\RequirePackageWithOptions{% % \AtEndOfPackage{\let\@unprocessedoptions\relax}% % \@loadwithoptions\@pkgextension\RequirePackage} %\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} % %\IncludeInRelease{2020/10/01}% % {\@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} % %\EndIncludeInRelease %\IncludeInRelease{2017/01/01}% % {\@fileswith@pti@ns}{ifx tests in \@fileswith@pti@ns}% %\def\@fileswith@pti@ns#1[#2]#3[#4]{% % \ifx#1\@clsextension % \ifx\@classoptionslist\relax % \xdef\@classoptionslist{\zap@space#2 \@empty}% % \def\reserved@a{% % \@onefilewithoptions#3[{#2}][{#4}]#1% % \@documentclasshook}% % \else % \def\reserved@a{% % \@onefilewithoptions#3[{#2}][{#4}]#1}% % \fi % \else % \def\reserved@b##1,{% % \ifx\@nnil##1\relax\else % \ifx\@nnil##1\@nnil\else % \noexpand\@onefilewithoptions##1[{#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} % \end{macrocode} % % \begin{macrocode} %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@fileswith@pti@ns}{ifx tests in \@fileswith@pti@ns}% %\def\@fileswith@pti@ns#1[#2]#3[#4]{% % \ifx#1\@clsextension % \ifx\@classoptionslist\relax % \xdef\@classoptionslist{\zap@space#2 \@empty}% % \def\reserved@a{% % \@onefilewithoptions#3[{#2}][{#4}]#1% % \@documentclasshook}% % \else % \def\reserved@a{% % \@onefilewithoptions#3[{#2}][{#4}]#1}% % \fi % \else % \def\reserved@b##1,{% % \ifx\@nil##1\relax\else % \ifx\relax##1\relax\else % \noexpand\@onefilewithoptions##1[{#2}][{#4}]% % \noexpand\@pkgextension % \fi % \expandafter\reserved@b % \fi}% % \edef\reserved@a{\zap@space#3 \@empty}% % \edef\reserved@a{% % \expandafter\reserved@b\reserved@a,\@nil,}% % \fi % \reserved@a} %\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|latexrelease> %\IncludeInRelease{2020/10/01}% % {\@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{% % %\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 \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} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\@onefilewithoptions}{Hooks and unused options issue}% % % \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} %\def\load@onefilewithoptions#1[#2][#3]#4{% % \@pushfilename % \xdef\@currname{#1}% % \global\let\@currext#4% % \let\CurrentOption\@empty % \@reset@ptions % \makeatletter % \def\reserved@a{% % \@ifl@aded\@currext{#1}% % {\@if@ptions\@currext{#1}{#2}{}% % {\@latex@error % {Option clash for \@cls@pkg\space #1}% % {The package #1 has already been loaded % with options:\MessageBreak % \space\space[\@ptionlist{#1.\@currext}]\MessageBreak % There has now been an attempt to load it % with options\MessageBreak % \space\space[#2]\MessageBreak % Adding the global options:\MessageBreak % \space\space % \@ptionlist{#1.\@currext},#2\MessageBreak % to your \noexpand\documentclass declaration may fix this.% % \MessageBreak % Try typing \space \space to proceed.}}}% % {\@pass@ptions\@currext{#2}{#1}% % \global\expandafter % \let\csname ver@\@currname.\@currext\endcsname\@empty % \expandafter\let\csname\@currname.\@currext-h@@k\endcsname\@empty % \InputIfFileExists % {\@currname.\@currext}% % {}% % {\@missingfileerror\@currname\@currext}% % \let\@unprocessedoptions\@@unprocessedoptions % \csname\@currname.\@currext-h@@k\endcsname % \expandafter\let\csname\@currname.\@currext-h@@k\endcsname % \@undefined % \@unprocessedoptions}% % \@ifl@ter\@currext{#1}{#3}{}% % {\@latex@warning@no@line % {You have requested,\on@line, % version\MessageBreak % `#3' of \@cls@pkg\space #1,\MessageBreak % but only version\MessageBreak % `\csname ver@#1.\@currext\endcsname'\MessageBreak % is available}}% % \ifx\@currext\@clsextension\let\LoadClass\@twoloadclasserror\fi % \@popfilename % \@reset@ptions}% % \reserved@a} % %\let \load@onefile@withoptions \@undefined %\let \@missing@onefilewithoptions \@undefined % %\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|latexrelease> %\IncludeInRelease{2020/10/01}% % {\AtBeginDocument}{Use hook system}% \DeclareRobustCommand\AtBeginDocument{\AddToHook{begindocument}} \DeclareRobustCommand\AtEndDocument {\AddToHook{enddocument}} %\DeclareRobustCommand\AtEndDocument {\AddToHook{env/document/end}} % alternative impl % \end{macrocode} % % \begin{macrocode} % %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\AtBeginDocument}{Use hook system}% % %\DeclareRobustCommand\AtBeginDocument{\g@addto@macro\@begindocumenthook} %\DeclareRobustCommand\AtEndDocument{\g@addto@macro\@enddocumenthook} % %\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 \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|latexrelease> %\IncludeInRelease{2020/10/01}% % {\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} % %\EndIncludeInRelease %\IncludeInRelease{2019/10/01}% % {\filec@ntents}{Spaces in file names + optional arg}% % %\def\filecontents{\@tempswatrue\@fileswtrue % \@ifnextchar[\filec@ntents@opt\filec@ntents %} %\@namedef{filecontents*}{\@tempswafalse\@fileswtrue % \@ifnextchar[\filec@ntents@opt\filec@ntents %} %\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}% % \fi}% % \filec@ntents %} %\let\filec@ntents@force\@fileswfalse %\let\filec@ntents@overwrite\@fileswfalse % alternative name %\let\filec@ntents@noheader\@tempswafalse %\def\filec@ntents@nosearch{% % \let\filec@ntents@checkdir\@currdir % \def\filec@ntents@where{in current directory}} %\let\filec@ntents@checkdir\@empty %\def\filec@ntents@where{exists on the system} %\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% %\gdef\filec@ntents#1{% % \set@curr@file{\filec@ntents@checkdir#1}% % \edef\q@curr@file{\expandafter\quote@name\expandafter{\@curr@file}}% % \chardef\reserved@c\ifx\directlua\@undefined 15 \else 127 \fi% % \openin\@inputcheck\q@curr@file \space % % \ifeof\@inputcheck% % \@latex@warning@no@line% % {Writing file `\@currdir\@curr@file'}% % \ch@ck7\reserved@c\write\relax% % \immediate\openout\reserved@c\q@curr@file\relax% % \else% % \if@filesw% % \@latex@warning@no@line% % {File `\@curr@file' already \filec@ntents@where.\MessageBreak% % Not generating it from this source}% % \let\write\@gobbletwo% % \let\closeout\@gobble% % \else% % \edef\reserved@a{#1}% % \edef\reserved@a{\detokenize\expandafter{\reserved@a}}% % \edef\reserved@b{\detokenize\expandafter{\jobname}}% % \ifx\reserved@a\reserved@b% % \@fileswtrue% % \else% % \edef\reserved@b{\reserved@b\detokenize{.tex}}% % \ifx\reserved@a\reserved@b % \@fileswtrue% % \fi% % \fi% % \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% % \@latex@warning@no@line% % {Writing or overwriting file `\@currdir\@curr@file'}% % \immediate\openout\reserved@c\q@curr@file\relax% % \fi% % \fi% % \fi% % \closein\@inputcheck% % \if@tempswa% % \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% % \count@ 128\relax% % \loop% % \catcode\count@ 11\relax% % \advance\count@ \@ne% % \ifnum\count@<\@cclvi% % \repeat% % \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% % \immediate\write\reserved@c{##1}% % \else% % \edef^^M{\noexpand\end{\@currenvir}}% % \ifx\relax##1\relax% % \else% % \@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% % \@latex@warning{% % Ignoring text `##2' after \string\end{\@currenvir}}% % \fi% % \fi% % ^^M}% % \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% %\EndIncludeInRelease %\IncludeInRelease{0000/00/00}% % {\filec@ntents}{Spaces in file names + optional arg}% % %\let\filec@ntents@opt \@undefined %\let\filec@ntents@force \@undefined %\let\filec@ntents@overwrite \@undefined %\let\filec@ntents@noheader \@undefined %\let\filec@ntents@nosearch \@undefined %\let\filec@ntents@checkdir \@undefined %\let\filec@ntents@where \@undefined % %\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% % %\gdef\filec@ntents#1{% % \openin\@inputcheck#1 % % \ifeof\@inputcheck% % \@latex@warning@no@line% % {Writing file `\@currdir#1'}% % \chardef\reserved@c15 % % \ch@ck7\reserved@c\write% % \immediate\openout\reserved@c#1\relax% % \else% % \closein\@inputcheck% % \@latex@warning@no@line% % {File `#1' already exists on the system.\MessageBreak% % Not generating it from this source}% % \let\write\@gobbletwo% % \let\closeout\@gobble% % \fi% % \if@tempswa% % \immediate\write\reserved@c{% % \@percentchar\@percentchar\space% % \expandafter\@gobble\string\LaTeX2e file `#1'^^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% % \count@ 128\relax% % \loop% % \catcode\count@ 11\relax% % \advance\count@ \@ne% % \ifnum\count@<\@cclvi% % \repeat% % \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% % \immediate\write\reserved@c{##1}% % \else% % \edef^^M{\noexpand\end{\@currenvir}}% % \ifx\relax##1\relax% % \else% % \@latex@warning{Writing text `##1' before % % \string\end{\@currenvir}\MessageBreak as last line of #1}% % \immediate\write\reserved@c{##1}% % \fi% % \ifx\relax##2\relax% % \else% % \@latex@warning{% % Ignoring text `##2' after \string\end{\@currenvir}}% % \fi% % \fi% % ^^M}% % % \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% %\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|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 % % \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}% % % \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}% % % \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}% % \fi %<*tracerollback> \else \pkgcls@debug{Date request: ignored}% % \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}% % \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}% % \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}% % \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}% % % \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} % % \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 % % \end{macrocode} % % \Finale