diff options
Diffstat (limited to 'macros/latex/contrib/koma-script/scrkernel-basics.dtx')
-rw-r--r-- | macros/latex/contrib/koma-script/scrkernel-basics.dtx | 5356 |
1 files changed, 5356 insertions, 0 deletions
diff --git a/macros/latex/contrib/koma-script/scrkernel-basics.dtx b/macros/latex/contrib/koma-script/scrkernel-basics.dtx new file mode 100644 index 0000000000..44e82629b8 --- /dev/null +++ b/macros/latex/contrib/koma-script/scrkernel-basics.dtx @@ -0,0 +1,5356 @@ +% \iffalse meta-comment +% ====================================================================== +% scrkernel-basics.dtx +% Copyright (c) Markus Kohm, 2002-2022 +% +% This file is part of the LaTeX2e KOMA-Script bundle. +% +% This work may be distributed and/or modified under the conditions of +% the LaTeX Project Public License, version 1.3c of the license. +% The latest version of this license is in +% http://www.latex-project.org/lppl.txt +% and version 1.3c or later is part of all distributions of LaTeX +% version 2005/12/01 or later and of this work. +% +% This work has the LPPL maintenance status "author-maintained". +% +% The Current Maintainer and author of this work is Markus Kohm. +% +% This work consists of all files listed in MANIFEST.md. +% ====================================================================== +%%% From File: $Id: scrkernel-basics.dtx 3913 2022-06-28 07:45:49Z kohm $ +%<prepare>%%% (run: prepare) +%<option>%%% (run: option) +%<body>%%% (run: body) +%<load>%%% (run: load) +%<package&prepare>\NeedsTeXFormat{LaTeX2e}[1995/06/01] +%<*dtx> +\ifx\ProvidesFile\undefined\def\ProvidesFile#1[#2]{}\fi +\begingroup + \def\filedate$#1: #2-#3-#4 #5${\def\filedate{#2/#3/#4}} + \filedate$Date: 2022-06-28 09:45:49 +0200 (Di, 28. Jun 2022) $ + \def\filerevision$#1: #2 ${\def\filerevision{r#2}} + \filerevision$Revision: 3913 $ + \edef\reserved@a{% + \noexpand\endgroup + \noexpand\ProvidesFile{scrkernel-basics.dtx}% + [\filedate\space\filerevision\space + KOMA-Script + } +\reserved@a +%</dtx> +%<*dtx|(package&prepare)> +%<package>\ProvidesPackage{% +%<package&base> scrbase% +%<package&koma> scrkbase% +%<package>}[% +%!KOMAScriptVersion + package +%<*dtx> + source +%</dtx> + (% +%<base> KOMA-Script-independent +%<koma> KOMA-Script-dependent + basics and keyval usage)] +%</dtx|(package&prepare)> +%<*dtx> +\ifx\documentclass\undefined + \input scrdocstrip.tex + \@@input scrkernel-version.dtx + \@@input scrstrip.inc + \KOMAdefVariable{COPYRIGHTFROM}{2002} + \generate{\usepreamble\defaultpreamble + \file{scrbase.sty}{% + \from{scrkernel-version.dtx}{package,scrbase}% + \from{scrkernel-basics.dtx}{package,prepare,base}% + \from{scrkernel-basics.dtx}{package,option,base}% + \from{scrkernel-language.dtx}{package,option,base}% + \from{scrkernel-basics.dtx}{package,body,base}% + \from{scrkernel-language.dtx}{package,body,base}% + \from{scrlogo.dtx}{logo}% + }% + } + \@@input scrstrop.inc +\else + \let\endbatchfile\relax +\fi +\endbatchfile +\documentclass[USenglish]{koma-script-source-doc} +\usepackage{babel} +\usepackage{hvlogos} +\setcounter{StandardModuleDepth}{2} +\begin{document} +\DocInput{scrkernel-basics.dtx} +\end{document} +%</dtx> +% \fi^^A meta-comment +% +% \changes{v1.0}{2002/07/06}{starting implementation} +% \changes{v3.12}{203/03/05}{usage of \cs{@tempa}, \cs{@tempb}, \cs{@tempc} +% eliminated} +% \changes{v3.36}{2022/02/16}{switch over from \cls*{scrdoc} to +% \cls*{koma-script-source-doc}} +% \changes{v3.36}{2022/02/21}{whole implementation documentation in English} +% +% \GetFileInfo{scrkernel-basics.dtx} +% \title{Basic Funktionality Used by Almost all +% \href{https://komascript.de}{\KOMAScript} Classes and Packages} +% \author{\href{mailto:komascript@gmx.info}{Markus Kohm}} +% \date{Revision \fileversion{} of \filedate} +% \maketitle +% \begin{abstract} +% New versions of \KOMAScript{} make increasing use of the \pkg{keyval} +% package. The \pkg{keyval} package is part of the \pkg{graphics} package +% and as such must be included on all \TeX{} systems with \LaTeX{}. However, +% it does not meet the requirements of \KOMAScript{} in some +% respects. Therefore, extensions are made here which can be used by +% \KOMAScript classes and \KOMAScript packages. +% +% In addition, more and more parts of \KOMAScript{} are used by more than +% one package or by packages and classes. These basic things have therefore +% been split into two packages, \pkg*{scrbase} (for things that can also be +% used by other classes and packages) and \pkg*{scrkbase} (for things that +% are reserved for \pkg*{scrkbase}). This makes the packages and classes +% themselves smaller and they can still be used independently. Of course you +% can also use this package without the rest of \KOMAScript{}. +% \end{abstract} +% \tableofcontents +% +% \section{User Manual} +% +% You can find the user documentation of package \pkg*{scrbase} and the +% commands implemented in \file{scrkernel-basics.dtx} in the \KOMAScript{} +% manual, either the German \file{scrguide} or the English \file{scrguien}. +% +% +% \subsection{Functions not yet in the Manual} +% +% Some user commands are not documented in the \KOMAScript{} manuals, e.g., +% because they are not stable enough to be used by average users or more or +% less for internal usage only. Some are only not documented in the +% \KOMAScript{} manual, because nobody has done it yet. +% +% \DescribeCommand\IfLTXAtLeastTF +% \marginpar{\raggedleft\tiny Added: 2021-01-31}% +% This is the same like \cs{IfFormatAtLeast} of \LaTeX{} from 2020/10/01, but +% works also with older \LaTeX{} kernels. +% +% \DescribeCommand\Ifislengthprimitive +% \marginpar{\raggedleft\tiny Added: 2015/10/19\\Renamed: 2022/02/17}% +% \cs{Ifislengthprimitive}\marg{macro}\marg{then code}\marg{else code} +% expands the \meta{macro} and tests if the result can be used as a length +% primitive. If this is the case the \meta{then code} is executed, otherwise +% the \meta{else code}. Note, that this command can be false negative, +% because, i.e., with \LuaLaTeX{} there can be primitives, that are like length, +% but that are not known by \cs{Ifislengthprimitive}. +% +% \DescribeCommand\Ifisdefchar +% \marginpar{\raggedleft\tiny Added: 2015/10/19\\Renamed: 2022/02/17}% +% \cs{Ifislengthprimitive}\marg{macro}\marg{then code}\marg{else code} +% expands the \meta{macro} and tests if the result is a \cs{char}. If this is +% the case the \meta{then code} is executed, otherwise the \meta{else code}. +% Note, that this command can be false positive, if the \cs{char} value is +% incorrect. +% +% +% \MaybeStop{\PrintIndex} +% +% \section{Implementation of \pkg*{scrbase} and \pkg*{scrkbase}} +% +% \subsection{Loading \pkg*{scrkbase}} +% Who ever loads ths package, always wants the same version of the already +% used \KOMAScript version. +% \begin{macrocode} +%<*load> +\RequirePackage{scrkbase}[\KOMAScriptVersion] +%</load> +% \end{macrocode} +% +% +% \subsection{\eTeX{} test} +% \changes{v3.02c}{2009/02/19}{error message without \eTeX} +% +% \begin{macrocode} +%<*prepare> +%<*base> +\begingroup + \def\reserved@b{}% + \def\reserved@a#1{% + \PackageError{scrbase}{seems you are not running e-TeX#1}{% + Since 2004 the LaTeX team recommends to use e-TeX.\MessageBreak + KOMA-Script since version 2.95 uses several e-TeX features.\MessageBreak + At actual systems `latex' should already use e-TeX.\MessageBreak + At deprecated systems it may be called `elatex'.\MessageBreak + Use either unsupported KOMA-Script up to version 2.9u or\MessageBreak + ask you administrator for LaTeX using e-TeX#1.\MessageBreak + Not using e-TeX#1 is a fatal error!\MessageBreak + Processing cannot be continued!}% + \endgroup + \batchmode \errmessage{}\csname @@end\endcsname\end\relax + \csname endinput\endcsname + }% + \expandafter\ifx\csname eTeXversion\endcsname\relax\else + \ifnum\eTeXversion <2 + \def\reserved@b{ V 2}% + \else + \let\reserved@a\endgroup + \fi + \fi +\expandafter\reserved@a\expandafter{\reserved@b} +%</base> +% \end{macrocode} +% +% +% \subsection{The \KOMAScript-only package loads the universal package} +% +% Once again the same version is wanted. +% \begin{macrocode} +%<koma>\RequirePackage{scrbase}[\KOMAScriptVersion] +% \end{macrocode} +% +% \subsection{Package \pkg*{scrlfile}} +% +% We need to react on the loading other packages like \pkg{polyglossia}. For +% this we use \pkg*{scrlfile}. But we can use any version. +% +% \begin{macrocode} +%<base>\RequirePackage{scrlfile} +% \end{macrocode} +% +% \subsection{Package \pkg*{keyval}} +% +% The \KOMAScript{} key handling bases on package \pkg{keyval}. +% \begin{macrocode} +%<base>\RequirePackage{keyval} +% \end{macrocode} +% +% +% \subsection{Using protected kernel macros} +% Some package like \pkg{amsgen} redefine internal \LaTeX{} kernel macros, but +% break them for other purposes than the own. So I have to make them work +% again. The \KOMAScript{} classes have less problems with this, because most +% of these packages cannot be loaded before a class. So the classes can simply +% copy the original macro, before it is redefined. But I do not know, when a +% package is loaded. So I have to implement the whole macro again with another +% name (and can only hope, that such packages do not damage them also). +% +% \begin{macro}{\kernel@ifstar} +% \changes{v3.20}{2016/04/12}{added} +% I hope, the \LaTeX{} kernel will define this in future and other packages do +% not redefine like they do with \cs{@ifstar}. So I use \cs{providecommand} to +% not redefine the kernel macro, if it does exist. +% \begin{macrocode} +%<base>\providecommand*\kernel@ifstar[1]{\kernel@ifnextchar*{\@firstoftwo{#1}}} +% \end{macrocode} +% \end{macro}^^A \kernel@ifstar +% +% +% \subsection{Improved \LaTeX{} kernel commands} +% The \LaTeX{} kernel already provides some useful commands, but some can be +% improved. +% +% \begin{command}{\rloop} +% \changes{v3.30}{2020/03/07}{added} +% The \cs{loop} \dots \cs{repeat} of the \LaTeX{} kernel cannot be used inside +% a \cs{loop} \dots \cs{repeat} without extra code for preserving +% \cs{iterate}. So here is a re-entrant version that is also long. This +% version can be used even inside a \cs{loop} \dots \cs{repeat}. However you +% should not use \cs{loop} \dots \cs{repeat} inside \cs{rloop} \dots +% \cs{repeat}. +% \begin{macrocode} +%<*base> +\newcommand{\rloop}[1]{} +\long\def\rloop#1\repeat{% + \ifdefined\iterate + \edef\iterate{\unexpanded{#1\relax\expandafter\iterate\fi\def\iterate}% + {\unexpanded\expandafter{\iterate}}}% + \else + \def\iterate{#1\relax\expandafter\iterate\fi\let\iterate\relax}% + \fi + \iterate +} +%</base> +% \end{macrocode} +% \end{command} +% +% \begin{command}{\IfLTXAtLeastTF} +% \changes{v3.33}{2021/01/21}{new} +% This is the same like \cs{IfFormatAtLeastTF} of the current \LaTeX{} kernel, +% but does also work, if \cs{IfFormatAtLeastTF} is not defined because of +% very old \LaTeX{} kernel. +% \begin{macrocode} +%<*base> +\newcommand*{\IfLTXAtLeastTF}{\@ifl@t@r\fmtversion} +\ifcsname IfFormatAtLeastTF\endcsname + \let\IfLTXAtLeastTF\IfFormatAtLeastTF +\fi +\@onlypreamble\IfLTXAtLeastTF +%</base> +% \end{macrocode} +% \end{command} +% +% +% \subsection{Testing macros} +% +% \begin{macro}{\scr@ifundefinedorrelax} +% \changes{v2.95c}{2006/08/12}{added} +% \changes{v2.97b}{2007/03/08}{broken logic fixed} +% \changes{v2.97c}{2007/04/18}{broken functionality fixed} +% \changes{v2.97c}{2007/04/18}{\cs{scr@ifundefined} renamed} +% \changes{v3.02c}{2009/02/19}{special treatment of \eTeX{} removed} +% This macro is like \cs{@ifundefined}, but does not define the test macro +% \cs{relax} if it was undefined before. Note: With up-to-date \LaTeX{} this +% is the same with the original \cs{@ifundefined}. +% \begin{macrocode} +%<*base> +\newcommand{\scr@ifundefinedorrelax}[1]{% + \ifcsname #1\endcsname + \expandafter\ifx\csname #1\endcsname\relax + \expandafter\expandafter\expandafter\@firstoftwo + \else + \expandafter\expandafter\expandafter\@secondoftwo + \fi + \else + \expandafter\@firstoftwo + \fi +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@ifundefinedorrelax +% +% +% \subsection{Extending messages} +% +% \begin{command}{\PackageErrorNoLine} +% \changes{v3.12}{2013/09/19}{added} +% \changes{v3.28}{2019/11/23}{nonsense command removed} +% Falk correctly stated, that \cs{PackageError} already does not show a line +% number. So we do not need this command. +% \end{command} +% +% +% \subsection{Definition of the \KOMAScript{} \pkg*{keyval} basis} +% +% \KOMAScript{} could use \pkg{keyval} keys with the same set of keywords +% ``\texttt{KOMA}'' to make it possible, that packages can redefine keys of +% classes and other packages. However this would be dangerous and can easily +% break. So we split the set of keywords in an family of keywords and family +% member of keywords and define commands to process the keywords either of a +% member or a whole family. +% +% \begin{command}{\DefineFamily,\DefineFamilyMember,\DefineFamilyKey} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by \cs{kernel@ifnextchar}} +% \begin{macro}{\scr@if@family} +% \changes{v3.00}{2008/04/30}{added} +% \begin{macro}{\scr@if@familymember} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.27}{2019/07/19}{the empty member exists by default} +% \begin{macro}{\scr@define@family@key} +% \changes{v3.00}{2008/04/30}{added} +% \begin{macro}{\scr@define@family@key@nodefault} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.18a}{2015/07/03}{missing \% added} +% Family, member of a family and \pkg{keyval} key for a member of a +% family. The default of the member of a family is always the file name of a +% class or package (while reading the file). +% \begin{macrocode} +%<*base> +\newcommand*{\DefineFamily}[1]{% + \scr@ifundefinedorrelax{#1@key@familylist}{% + \@namedef{#1@key@familylist}{}% + }{}% +} +\newcommand*{\scr@if@family}[2]{% + \scr@ifundefinedorrelax{#1@key@familylist}{% + \PackageError{scrbase}{% + unknown family `#1'% + }{% + You've tried to #2 for family `#1'.\MessageBreak + This my be done only for previous defined families.\MessageBreak + You should call `\string\DefineFamily{#1}' first.% + }% + }% +} +\newcommand*{\DefineFamilyMember}[2][.\@currname.\@currext]{% + \scr@if@family{#2}{define a family member}{% + \edef\reserved@a{% + \noexpand\in@{#2#1,}{\csname #2@key@familylist\endcsname}}% + \reserved@a + \ifin@\else + \expandafter\edef\csname #2@key@familylist\endcsname{% + \@nameuse{#2@key@familylist}#2#1,}% + \fi + }% +} +\newcommand*{\scr@if@familymember}[3]{% + \scr@if@family{#2}{#3}{% + \IfArgIsEmpty{#1}{% + \@firstofone + }{% + \edef\reserved@a{% + \noexpand\in@{#2#1,}{\csname #2@key@familylist\endcsname}}% + \reserved@a + \ifin@ + \expandafter\@firstofone + \else + \PackageError{scrbase}{% + unknown member `#1' at family `#2'% + }{% + You've tried to #3 for member `#1' of family `#2'.\MessageBreak + This my be done only for previous defined family members.\MessageBreak + You should call `\string\DefineFamilyMember[{#1}]{#2}' first.% + }% + \expandafter\@gobble + \fi + }% + }% +} +\newcommand*{\DefineFamilyKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar[%] + {% + \edef\reserved@a{#1}% + \expandafter\scr@define@family@key + \expandafter{\reserved@a}{#2}{#3}% + }{% + \edef\reserved@a{#1}% + \expandafter\scr@define@family@key@nodefault + \expandafter{\reserved@a}{#2}{#3}% + }% +} +\newcommand{\scr@define@family@key}{} +\long\def\scr@define@family@key#1#2#3[#4]#5{% + \scr@if@familymember{#1}{#2}{define a key}{% + \define@key{#2#1}{#3}[{#4}]{% + \def\FamilyOfKey{#2}\def\FamilyMemberOfKey{#1}% + \FamilyKeyStateUnknown + #5% + \def\FamilyOfKey{#2}\def\FamilyMemberOfKey{#1}% + }% + }% +} +\newcommand{\scr@define@family@key@nodefault}[4]{% + \scr@if@familymember{#1}{#2}{define a key}{% + \define@key{#2#1}{#3}{% + \def\FamilyOfKey{#2}\def\FamilyMemberOfKey{#1}% + \FamilyKeyStateUnknown + #4% + \def\FamilyOfKey{#2}\def\FamilyMemberOfKey{#1}% + }% + \@namedef{KV@#2#1@#3@default}{% + \def\FamilyOfKey{#2}\def\FamilyMemberOfKey{#1}% + \FamilyKeyStateNeedValue + }% + }% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@define@family@key@nodefault +% \end{macro}^^A \scr@define@family@key +% \end{macro}^^A \scr@if@familymember +% \end{macro}^^A \scr@if@family +% \end{command}^^A \DefineFamily,\DefineFamilyMember,\DefineFamilyKey +% +% +% \begin{command}{\RelaxFamilyKey} +% \changes{v3.15}{2014/12/03}{added} +% Sometimes it is useful to be able to \emph{un-define} a key. This will not +% un-define all helper macros but only the key and a default value will become +% \cs{relax}. +% \begin{macrocode} +%<*base> +\newcommand*{\RelaxFamilyKey}[3][.\@currname.\@currext]{% + \scr@ifundefinedorrelax{KV@#2#1@#3}{}{% + \expandafter\let\csname KV@#2#1@#3\endcsname\relax + }% + \scr@ifundefinedorrelax{KV@#2#1@#3@default}{}{% + \expandafter\let\csname KV@#2#1@#3@default\endcsname\relax + }% +} +%</base> +% \end{macrocode} +% \end{command}^^A \RelaxFamilyKey +% +% \begin{command}{\FamilyKeyState,\FamilyKeyStateProcessed,\FamilyKeyStateUnknown, +% \FamilyKeyStateUnknownValue,\FamilyKeyStateNeedValue} +% \changes{v3.12}{2013/03/04}{added} +% \cs{FamilyKeyState} is the state of processing a key. The initial state is +% \cs{FamilyKeyStateUnknown}, so the state is indeed unknown. If a key has +% been processed by the definition code and everything is OK, you should run +% \cs{FamilyKeyStateProcessed}. This will set \cs{FamilyKeyState} also to +% \cs{FamilyKeyStateProcessed} to indicate, the key has been processed +% successfully. If the value assigned to the key is unknown, you should run +% \cs{FamilyKeyStateUnknownValue}. And if the value is needed but no value has +% been assigned, \cs{FamilyKeyStateNeedValue} is the correct choice. Note: +% \cs{FamilyKeyState} is valid only immediately after processing a key. +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyKeyState}{} +\newcommand*{\FamilyKeyStateUnknown}{% + \let\FamilyKeyState\FamilyKeyStateUnknown +} +\newcommand*{\FamilyKeyStateUnknownValue}{% + \let\FamilyKeyState\FamilyKeyStateUnknownValue +} +\newcommand*{\FamilyKeyStateNeedValue}{% + \let\FamilyKeyState\FamilyKeyStateNeedValue +} +\newcommand*{\FamilyKeyStateProcessed}{% + \let\FamilyKeyState\FamilyKeyStateProcessed +} +\let\FamilyKeyState\FamilyKeyStateUnknown +%</base> +% \end{macrocode} +% \end{command}^^A \FamilyKeyState … \FamilyKeyStateNeedValue +% +% \begin{command}{\FamilyOfKey,\FamilyMemberOfKey} +% \changes{v3.12}{2013/03/04}{added} +% While processing a key, this is the family and the member of family. +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyOfKey}{} +\newcommand*{\FamilyMemberOfKey}{} +%</base> +% \end{macrocode} +% \end{command}^^A \FamilyOfKey,\FamilyMemberOfKey +% +% \begin{macro}{\KOMA@key} +% \changes{v2.97c}{2007/04/19}{optional argument added} +% \changes{v3.17}{2015/02/24}{rudimentary value storage} +% \pkg{keyval} keys of \KOMAScript{} are defined with \cs{KOMAkey} to setup +% the family to ``\texttt{KOMA}'' automatically. Additionally the value +% storage is initialized. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@key}[1][.\@currname.\@currext]{% + \DefineFamilyMember[{#1}]{KOMA}% + \@ifundefined{scr@kav@KOMA#1}{\@namedef{scr@kav@KOMA#1}{}}{}% + \DefineFamilyKey[{#1}]{KOMA}% +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@kav@add} +% \changes{v3.17}{2015/02/24}{added} +% This macro stores a \texttt{\meta{key}=\meta{value}} pair in a internal +% list. The first argument is the family member, the second the \meta{key} and +% the third the \meta{value}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@kav@add}[3]{% + \@ifundefined{scr@kav@KOMA#1}{% + \KOMA@internal@error\KOMA@kav@add{#1}% + }{% + \expandafter\l@addto@macro\csname scr@kav@KOMA#1\endcsname{\do{{#2}{#3}}}% + }% +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@kav@xadd} +% \changes{v3.17}{2015/02/24}{added} +% This macro stores a \texttt{\meta{key}=\meta{value}} pair in a internal +% list after expanding both, the \meta{key} and the \meta{value}. The first +% argument is the family member, the second the \meta{key} and the third the +% \meta{value}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@kav@xadd}[3]{% + \@ifundefined{scr@kav@KOMA#1}{% + \KOMA@internal@error\KOMA@kav@xadd{#1}% + }{% + \protected@edef\reserved@a{{#2}{#3}}% + \expandafter\l@addto@macro\csname scr@kav@KOMA#1\expandafter\endcsname + \expandafter{\expandafter\do\expandafter{\reserved@a}}% + }% +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@kav@remove} +% \changes{v3.17}{2015/02/24}{added} +% This macro removes a \texttt{\meta{key}=\meta{value}} pair from the internal +% list. The first argument is the family member, the second the \meta{key} and +% the third the \meta{value}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@kav@remove}[3]{% + \@ifundefined{scr@kav@KOMA#1}{% + \KOMA@internal@error\KOMA@kav@remove{#1}% + }{% + \begingroup + \def\reserved@a{\endgroup\@namedef{scr@kav@KOMA#1}{}}% + \edef\reserved@b{\detokenize{{#2}{#3}}}% + \def\do##1{% + \edef\reserved@c{\detokenize{##1}}% + \ifx\reserved@b\reserved@c\else + \l@addto@macro\reserved@a{% + \expandafter\l@addto@macro\csname scr@kav@KOMA#1\endcsname{% + \do{##1}% + }% + }% + \fi + }% + \@nameuse{scr@kav@KOMA#1}% + \reserved@a + }% +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@kav@removekey} +% \changes{v3.17}{2015/02/24}{added} +% This macro removes all \texttt{\meta{key}=\meta{value}} pairs of a given +% \meta{key} from the internal list. The first argument is the family member, +% the second the \meta{key}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@kav@removekey}[2]{% + \@ifundefined{scr@kav@KOMA#1}{% + \KOMA@internal@error\KOMA@kav@removekey{#1}% + }{% + \begingroup + \def\reserved@a{\endgroup\@namedef{scr@kav@KOMA#1}{}}% + \edef\reserved@b{\detokenize{#2}}% + \def\reserved@d##1##2{\edef\reserved@c{\detokenize{##1}}}% + \def\do##1{% + \reserved@d##1\relax + \ifx\reserved@b\reserved@c\else + \l@addto@macro\reserved@a{% + \expandafter\l@addto@macro\csname scr@kav@KOMA#1\endcsname{% + \do{##1}% + }% + }% + \fi + }% + \@nameuse{scr@kav@KOMA#1}% + \reserved@a + }% +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@kav@replacevalue,\KOMA@kav@xreplacevalue} +% \changes{v3.17}{2015/02/25}{added} +% If \cs{FamilyKeyState} is \cs{FamilyKeyStateProcessed}, +% these macros replace a \texttt{\meta{key}=\meta{value}} pair in the internal list. +% The first argument is the family member, the second the \meta{key} and the +% third is the new \meta{value}. \cs{KOMA@kav@xreplacevalue} expands both, the +% \meta{key} and the \meta{value}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@kav@replacevalue}[3]{% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \@ifundefined{scr@kav@KOMA#1}{% + \KOMA@internal@error\KOMA@kav@replacevalue{#1}% + }{% + \KOMA@kav@removekey{#1}{#2}% + \KOMA@kav@add{#1}{#2}{#3}% + }% + \fi +} +\newcommand*{\KOMA@kav@xreplacevalue}[3]{% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \@ifundefined{scr@kav@KOMA#1}{% + \KOMA@internal@error\KOMA@kav@replacevalue{#1}% + }{% + \KOMA@kav@removekey{#1}{#2}% + \KOMA@kav@xadd{#1}{#2}{#3}% + }% + \fi +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@kav@replacebool} +% \changes{v3.17}{2015/02/24}{added} +% If \cs{FamilyKeyState} is \cs{FamilyKeyStateProcessed}, +% this macro replaces the value of a if key in the internal list. +% The first argument is the family member, the second the \meta{key} and the +% third is the boolean switch (\cs{if\dots} statement) representing the new value. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@kav@replacebool}[3]{% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \@ifundefined{scr@kav@KOMA#1}{% + \KOMA@internal@error\KOMA@kav@replacebool{#1}% + }{% + \KOMA@kav@remove{#1}{#2}{false}% + \KOMA@kav@remove{#1}{#2}{true}% + \expandafter\ifx\csname if#3\expandafter\endcsname + \csname iftrue\endcsname + \KOMA@kav@xadd{#1}{#2}{true}% + \else + \KOMA@kav@xadd{#1}{#2}{false}% + \fi + }% + \fi +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@kav@defall} +% \changes{v3.17}{2015/02/24}{added} +% This macro defines a macro/command with the \texttt{\meta{key}=\meta{value}} +% list of all stored pairs. The first argument is the macro/command to be +% defined with the list. The second is the family member. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@kav@defall}[2]{% + \@ifundefined{scr@kav@KOMA#2}{% + \KOMA@internal@error\KOMA@kav@defall{#1}% + }{% + \begingroup + \let\reserved@a\@empty + \def\reserved@b##1##2{\l@addto@macro\reserved@a{,{##1=##2}}}% + \def\do##1{\reserved@b##1}% + \@nameuse{scr@kav@KOMA#2}% + \ifx\reserved@a\@empty + \def\reserved@b{\endgroup\let#1\@empty}% + \else + \edef\reserved@b{% + \unexpanded{\endgroup\def#1}{% + \unexpanded + \expandafter\expandafter\expandafter{% + \expandafter\@gobble\reserved@a}}}% + \fi + \reserved@b + }% +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@kav@defone} +% \changes{v3.17}{2015/02/25}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% This macro defines a macro/command with all stored values of a \meta{key} +% from the internal list of \texttt{\meta{key}=\meta{value}} pairs. +% The first argument is the macro/command to be defined. The second is the +% family member and the third is the \meta{key}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@kav@defone}[3]{% + \@ifundefined{scr@kav@KOMA#2}{% + \KOMA@internal@error\KOMA@kav@defall{#1}% + }{% + \begingroup + \let\reserved@a\@empty + \def\reserved@b##1##2{% + \Ifstr{##1}{#3}{\l@addto@macro\reserved@a{,{##2}}}{}% + }% + \def\do##1{\reserved@b##1}% + \@nameuse{scr@kav@KOMA#2}% + \ifx\reserved@a\@empty + \def\reserved@b{\endgroup\let#1\@empty}% + \else + \edef\reserved@b{% + \unexpanded{\endgroup\def#1}{% + \unexpanded + \expandafter\expandafter\expandafter{% + \expandafter\@gobble\reserved@a}}}% + \fi + \reserved@b + }% +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@internal@error} +% \changes{v3.17}{2015/02/24}{added} +% General internal error message with the recommendation to report a bug. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@internal@error}[2]{% + \PackageError{scrkbase}{internal error using \string#1{#2}}{% + You've found an internal error either in KOMA-Script or a third + party\MessageBreak + definition, that uses KOMA-Script internal macros.\MessageBreak + Please send a bug report with a minimal but complete example, + that\MessageBreak + shows this error, to komascript at gmx dot info or report it + at\MessageBreak + <http://www.komascript.de/forum/20> (you need an account to do so).% + }% +} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \subsection{Options} +% +% From version 2.97c \KOMAScript{} processes all options in the order they +% have been set and no longer in the order they have been defined. This is +% much more intuitive for users. Packages first process the global options +% then the local options. +% +% \begin{macro}{\@globaloptionslist} +% \changes{v2.96}{2006/11/26}{added} +% \changes{v2.96}{2006/11/26}{process class options} +% \changes{v3.20}{2016/02/06}{delay decisions} +% The lost of global options is sometimes needed. But because \pkg{xkeyval} +% has the opinion it should remove all options with equal char from the list +% of class options, we define out own macro with a copy of the class +% options. Until \KOMAScript{} 3.19a the copy has been done here. But if +% \pkg*{scrbase} is loaded before \cs{documentclass} this is too early. From +% \KOMAScript{} 3.20 the assignment has been moved to +% \cs{FamilyProcessOptions}. And from \KOMAScript{} 3.33 the normal class +% option list is only used if the raw option list is not available. +% \begin{macrocode} +%<*base> +\newcommand*{\@globaloptionslist}{} +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\scr@removeunused,\scr@optiontest,\scr@pti@ntest} +% \changes{v2.97c}{2007/04/18}{added} +% \changes{v3.12}{2013/03/04}{removed} +% \end{macro}^^A \scr@removeunused,\scr@optiontest,\scr@pti@ntest +% +% \begin{command}{\FamilyProcessOptions} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.11a}{2012/06/11}{classes do not report errors for unknown values} +% \changes{v3.12}{2013/03/04}{error handling} +% \changes{v3.33}{2021/03/02}{new version using raw options lists of \LaTeX{} +% 2021/05/01} +% Note: Wrong values should not result in errors or warnings and only seldom +% in information. The best is to signal all kind of errors via +% \cs{FamilyKeyState}. Only values, that cannot be handled by any family +% member have to be reported. This is done inside \cs{FamilyProcessOptions} +% depending on \cs{FamilyKeyState} of each member. +% Note also: This command is not re-entrant. So it cannot be used while +% processing another option. +% Note also: We use 2021/05/01 instead of the official \LaTeX{} release date, +% to detect a \LaTeX{} kernel version with raw option lists, because there +% were relevant earlier \LaTeX{} developer releases with that date. +% \begin{macrocode} +%<*base> +\IncludeInRelease{2021/05/01}{\FamilyProcessOptions}% + {Usage of raw or classic option list} +\newcommand*{\FamilyProcessOptions}[2][.\@currname.\@currext]{% +% \end{macrocode} +% Before processing of the options we have to execute an initialise several +% hooks: +% \begin{macrocode} + \ifx\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions + \PackageError{scrbase}{nested \string\FamilyProcessOptions\space + detected\MessageBreak}{% + \string\FamilyProcessOptions\space has been used while processing or + setting options.\MessageBreak + This is currently not allowed. You should contact the author of the + causing\MessageBreak + code.\MessageBreak + This error is fatal. You should not continue.% + }% + \fi + \scr@ifundefinedorrelax{scr@before@process@options@#2@hook}{}{% + \@nameuse{scr@before@process@options@#2@hook}% + }% + \scr@ifundefinedorrelax{scr@before@process@options@#2#1@hook}{}{% + \@nameuse{scr@before@process@options@#2#1@hook}% + \expandafter\let\csname scr@before@process@options@#2#1@hook\endcsname + \relax + }% + \scr@ifundefinedorrelax{scr@after@options@#2@hook}{% + \@namedef{scr@after@options@#2@hook}{% + \@namedef{scr@after@options@#2@hook}{}% + }% + }{% + \expandafter\edef\csname scr@after@options@#2@hook\endcsname{% + \noexpand\@namedef{scr@after@options@#2@hook}{% + \unexpanded\expandafter\expandafter\expandafter + {\csname scr@after@options@#2@hook\endcsname}% + }% + }% + }% + \ifx\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions@immediate + \@namedef{scr@after@options@#2@hook@topmost}{% + \@namedef{scr@after@options@#2@hook@topmost}{}% + }% + \expandafter\l@addto@macro\csname scr@after@options@#2@hook\endcsname{% + \let\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions@immediate + \@nameuse{scr@after@options@#2@hook@topmost}% + }% + \let\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions + \fi + \let\ds@\@empty +% \end{macrocode} +% Here we set up \cs{@curroptions} to the raw options of the current class or +% package or empty if the options are not defined. +% \begin{macrocode} + \@ifundefined{@raw@opt@\@currname.\@currext}{% + \let\@curroptions\@empty + }{% + \expandafter\let\expandafter\@curroptions + \csname @raw@opt@\@currname.\@currext\endcsname + }% +% \end{macrocode} +% If this is not a class, we first have to process all raw class options. +% \changes{v3.33}{2021/03/12}{switched to fast test like \LaTeX{} 2021/06/01} +% \changes{v3.34}{2021/05/30}{use \cs{@raw@classoptionslist} only, if defined} +% Note, if \pkg*{scrbase} or a depending package is loaded before the class, +% \cs{@raw@classoptionslist} should not be processed. +% \begin{macrocode} + \ifx\@currext\@clsextension\else + \@ifundefined{@raw@classoptionslist}{}{% + \@for\CurrentOption:=\@raw@classoptionslist\do{% + \scr@trim@spaces\CurrentOption + \ifx\CurrentOption\@empty\else + \@ifundefined{ds@\CurrentOption}{% + \scr@ifprocess@curroption{#1}{#2}{% + \@expandtwoargs\@removeelement{% + \expandafter\@remove@eq@value\CurrentOption=\@nil}% + \@unusedoptionlist\@unusedoptionlist + }{}% + }{% + \@use@ption + \expandafter\let\csname ds@\CurrentOption\endcsname\@empty + }% + \fi + }% + }% + \fi +% \end{macrocode} +% \changes{v3.34}{2021/06/05}{extra test because of \LaTeX{} raw option issue} +% Afterwards we have to process the current options. Unfortunately there is an +% issue with the raw option list of the \LaTeX{} kernel, that could result in +% \cs{CurrentOption} in the option list instead of the one step expansion of +% \cs{CurrentOption} (see +% \url{https://sourceforge.net/p/koma-script/tickets/10/}). This would result +% in an infinite loop using the usual loop: +% \begin{macrocode} +%<*dontusethis> + \@for\CurrentOption:=\@curroptions\do{% + \scr@trim@spaces\CurrentOption + \@ifundefined{ds@\CurrentOption}{% + \@use@ption + \scr@ifprocess@curroption{#1}{#2}{}\default@ds + }\@use@ption + }% +%</dontusethis> +% \end{macrocode} +% So for a little more rosbustnes we do an extra test. +% \begin{macrocode} + \@for\reserved@a:=\@curroptions\do{% + \scr@trim@spaces\reserved@a + \def\reserved@b{\CurrentOption}% + \ifx\reserved@a\reserved@b + \PackageError{scrbase}{% + \string\CurrentOption\space loop detected\MessageBreak + Perhaps someone uses:\MessageBreak\space\space + \ifx\@currext\@clsextension + \string\PassOptionsToClass + \else + \string\PassOptionsToPackage + \fi + {\string\CurrentOption}{…}.\MessageBreak + With LaTeX 2020/10/01 or 2021/06/01 this results in + \string\CurrentOption\MessageBreak + in the raw option list and therefore is not allowed.\MessageBreak + Please ask the class or package author to use:\MessageBreak\space\space + \string\expandafter + \ifx\@currext\@clsextension + \string\PassOptionsToClass + \else + \string\PassOptionsToPackage + \fi + \MessageBreak\space\space\space + \string\expandafter{\string\CurrentOption}{…}\MessageBreak + instead or update LaTeX (if possible)% + }% + \let\CurrentOption\@empty + \else + \let\CurrentOption\reserved@a + \fi + \@ifundefined{ds@\CurrentOption}{% + \@use@ption + \scr@ifprocess@curroption{#1}{#2}{}\default@ds + }\@use@ption + }% +% \end{macrocode} +% Clear all the definitions for declared options and the current option. Then +% reset the marker macro, initiate emptying the unprocessed options list of +% the current file and execute the exit hook. +% \begin{macrocode} + \@for\CurrentOption:=\@declaredoptions\do{% + \expandafter\let\csname ds@\CurrentOption\endcsname\relax}% + \let\CurrentOption\@empty + \let\@fileswith@pti@ns\@@fileswith@pti@ns + \AtEndOfPackage{\expandafter\let + \csname unprocessedoptions-\@currname.\@currext\endcsname + \relax}% + \@nameuse{scr@after@options@#2@hook}% +} +\EndIncludeInRelease +% \end{macrocode} +% And here the old version for old \LaTeX{} kernel version: +% \begin{macrocode} +\IncludeInRelease{0000/00/00}{\FamilyProcessOptions}% + {Usage of raw or classic option list} +\newcommand*{\FamilyProcessOptions}[2][.\@currname.\@currext]{% + \ifx\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions + \PackageError{scrbase}{nested \string\FamilyProcessOptions\space + detected\MessageBreak}{% + \string\FamilyProcessOptions\space has been used while processing or + setting options.\MessageBreak + This is currently not allowed. You should contact the author of the + causing\MessageBreak + code.\MessageBreak + This error is fatal. You should not continue.% + }% + \fi +% \end{macrocode} +% \changes{v3.18}{2015/06/17}{new hooks before processing the options} +% From version 3.18 we execute two hooks. The first one is valid for all +% classes and packages of a family. This is multi-time hook, not deleting +% itself. The second one is valid only one time for one member. +% \begin{macrocode} + \scr@ifundefinedorrelax{scr@before@process@options@#2@hook}{}{% + \@nameuse{scr@before@process@options@#2@hook}% + }% + \scr@ifundefinedorrelax{scr@before@process@options@#2#1@hook}{}{% + \@nameuse{scr@before@process@options@#2#1@hook}% + \expandafter\let\csname scr@before@process@options@#2#1@hook\endcsname + \relax + }% +% \end{macrocode} +% \changes{v3.23}{2017/02/16}{fix: the after hook uses the family instead of +% the member} +% Initialization of \cs{AtEndOfFamilyOptions} inclusive hook. +% \begin{macrocode} + \scr@ifundefinedorrelax{scr@after@options@#2@hook}{% + \@namedef{scr@after@options@#2@hook}{% +% \end{macrocode} +% The first hook action is to delete the hook. +% \begin{macrocode} + \@namedef{scr@after@options@#2@hook}{}% + }% + }{% + \expandafter\edef\csname scr@after@options@#2@hook\endcsname{% +% \end{macrocode} +% The first action in the hook is to reactivate the current hook. +% \begin{macrocode} + \noexpand\@namedef{scr@after@options@#2@hook}{% + \unexpanded\expandafter\expandafter\expandafter + {\csname scr@after@options@#2@hook\endcsname}% + }% + }% + }% +% \end{macrocode} +% \changes{v3.23}{2017/02/16}{new hook added for \cs{AtEndOfFamilyOptions*}} +% From version 3.23 there is one more hook before \cs{AtEndOfFamilyOptions*} +% to be initialized and executed. We can detect the topmost level comparing +% the definition of \cs{AtEndOfFamilyOptions}. This is faster than by the +% definition of the hook itself (we have to do so in \cs{FamilyOptions}). +% \begin{macrocode} + \ifx\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions@immediate + \@namedef{scr@after@options@#2@hook@topmost}{% +% \end{macrocode} +% The hook definitions also contains the hook deletion. This is important for +% recursive calls, to distinguish lower levels from the topmost level. +% \begin{macrocode} + \@namedef{scr@after@options@#2@hook@topmost}{}% + }% +% \end{macrocode} +% The top hook is added to the hook of the (topmost) level, while resetting +% the definition of \cs{AtEndOfFamilyOptions}. +% \begin{macrocode} + \expandafter\l@addto@macro\csname scr@after@options@#2@hook\endcsname{% + \let\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions@immediate + \@nameuse{scr@after@options@#2@hook@topmost}% + }% +% \end{macrocode} +% Don't forget to change the command to fill one of the hooks from immediate +% execution to adding code to the corresponding hook. +% \begin{macrocode} + \let\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions + \fi +% \end{macrocode} +% Continue the adaption of code from \cs{ProcessOptions}. +% \begin{macrocode} + \let\ds@\@empty + \edef\@curroptions{\@ptionlist{\@currname.\@currext}}% + \ifx\@currext\@clsextension\else +% \end{macrocode} +% Within classes the current option list is same like the global option +% list. So classes are not allowed to process the global option list +% additionally to the local one. But packages do process the global option +% list, but do not report errors or warnings about these options. +% \changes{v3.18}{2015/06/17}{handling of not defined \cs{@globaloptionslist}} +% \changes{v3.20}{2016/02/06}{\cs{@globaloptionslist} assignment always} +% \begin{macrocode} + \let\@globaloptionslist\@classoptionslist + \scr@ifundefinedorrelax{XKV@classoptionslist}{% +%<trace> \PackageInfo{scrbase}{Using \string\@classoptionslist}% + }{% + \ifx\XKV@classoptionslist\@empty +%<trace> \PackageInfo{scrbase}{Using \string\@classoptionslist}% + \else +%<trace> \PackageInfo{scrbase}{Using \string\XKV@classoptionslist}% + \let\@globaloptionslist\XKV@classoptionslist + \fi + }% + \scr@ifundefinedorrelax{@globaloptionslist}{}{% + \@for\CurrentOption:=\@globaloptionslist\do{% +% \end{macrocode} +% The options are processed in the order they have been set into the global +% option list. But only these options are processed, that are not empty and +% that are known by the current package. So these are only classic options not +% \pkg{keyval} options. +% \begin{macrocode} + \ifx\CurrentOption\@empty\else + \@expandtwoargs\in@{,\CurrentOption,}{,\@declaredoptions,}% + \ifin@ + \@use@ption + \expandafter\let\csname ds@\CurrentOption\endcsname\@empty + \else +% \end{macrocode} +% But if they are not classic options, they could be \pkg{keyval} options. In +% this case we test, if member (\texttt{\#1}) of family (\texttt{\#2}) has +% such an option. If this is the case, the options is executed once with +% member and once again with member. In case of an unknown key or value +% nothing else happens. +% \begin{macrocode} + \scr@ifprocess@curroption{#1}{#2}{% + \@expandtwoargs\@removeelement\CurrentOption + \@unusedoptionlist\@unusedoptionlist + }{}% + \fi + \fi + }% + }% + \fi +% \end{macrocode} +% Now, processing local options of classes and packages follows. In this case +% unknown options (keys) or values of packages immediately can result in error +% messages. But in classes they are only added to the list of unused global +% options. +% \begin{macrocode} + \@for\CurrentOption:=\@curroptions\do{% +% \end{macrocode} +% \changes{v3.26}{2018/10/22}{options are not fully expanded for the tests} +% \changes{v3.26}{2018/10/22}{\cs{@use@ption} is not used for +% \texttt{\meta{key}\quotechar=\meta{value}} options} +% From \KOMAScript~3.26 the options are not fully expanded to test, if it is a +% classic option. The essential expansion already has been done. So removing +% the full expansion avoids errors because of missing +% \cs{endcsname}. Additionally using \cs{@use@option} hat been removed for all +% \texttt{\meta{key}=\meta{value}} options, because this would result in the +% same error because of the |\csname ds@\CurrentOption\endcsname|, that is +% used inside \cs{@use@option}. Instead of \cs{@use@option} we just remove the +% option from the list of unused options. +% \begin{macrocode} + \edef\reserved@a{\expandafter\detokenize\expandafter{\CurrentOption}}% + \scr@ifundefinedorrelax{ds@\reserved@a}{% + \@expandtwoargs\@removeelement\CurrentOption + \@unusedoptionlist\@unusedoptionlist + \scr@ifprocess@curroption{#1}{#2}{}\default@ds + }\@use@ption + }% +% \end{macrocode} +% Almost at the end we delete the options code of all declared options. This +% is the same as with the \LaTeX{} kernel command +% \cs{ProcessOptions*}. Additionally at the end of the package (not +% \pkg*{tocbasic} but the package, that is using the command) all unprocessed +% options are processed. +% \changes{v3.33}{2021/02/15}{prepared for \LaTeX{} 2020/10/01} +% \begin{macrocode} + \@for\CurrentOption:=\@declaredoptions\do{% + \expandafter\let\csname ds@\CurrentOption\endcsname\relax}% + \let\CurrentOption\@empty + \let\@fileswith@pti@ns\@@fileswith@pti@ns + \IfLTXAtLeastTF{2020/10/01}{% + \AtEndOfPackage{\expandafter\let + \csname unprocessedoptions-\@currname.\@currext\endcsname + \relax}% + }{% + \AtEndOfPackage{\let\@unprocessedoptions\relax}% + }% +% \end{macrocode} +% Last but not least the hook has to be executed and (self-)deleted. +% \changes{v3.23}{2017/02/16}{fix using family instead of member} +% \begin{macrocode} + \@nameuse{scr@after@options@#2@hook}% +} +\EndIncludeInRelease +\@onlypreamble\FamilyProcessOptions +% \end{macrocode} +% \begin{command}{\BeforeFamilyProcessOptions} +% \changes{v3.18}{2015/06/17}{added} +% Add code to the hook used immediately before executing the options via +% \cs{FamilyProcessOptions}. Neither the family nor the member need to +% exist. So you are able to already add code to the hook before the class or +% package has been loaded. +% \begin{macrocode} +\newcommand*{\BeforeFamilyProcessOptions}[3][.\@currname.\@currext]{% + \scr@ifundefinedorrelax{scr@before@process@options@#2#1@hook}{% + \@namedef{scr@before@process@options@#2#1@hook}{#3}% + }{% + \expandafter\g@addto@macro + \csname scr@before@process@options@#2#1@hook\endcsname{#3}% + }% +} +% \end{macrocode} +% \end{command}^^A \BeforeFamilyProcessOptions +% \begin{command}{\AtEndOfFamilyOptions} +% \changes{v3.12}{2013/03/04}{added} +% \changes{v3.23}{2017/02/16}{star variant added} +% Inside the code of an option you can delay execution of code till the end of +% the current \cs{FamilyProcessOptions}, \cs{FamilyExecuteOptions}, +% \cs{FamilyOptions} or \cs{FamilyOption}. The only argument is the code. The +% argument is delegated to \cs{l@addto@macro} (instead of reading it +% directly). The non-star variant delays only till the end of the current +% level. The star-variant delays till the end of all levels. +% \begin{macro}{\scr@AtEndOfFamilyOptions} +% \changes{v3.12}{2013/05/29}{added} +% \begin{macro}{\scr@@AtEndOfFamilyOptions,\scr@AtEndOfFamilyOptions@immediate} +% \changes{v3.23}{2017/02/16}{added} +% \begin{macrocode} +\newcommand*{\scr@AtEndOfFamilyOptions}{% + \kernel@ifstar {\scr@@AtEndOfFamilyOptions{@topmost}}% + {\scr@@AtEndOfFamilyOptions\@empty}% +} +\newcommand*{\scr@@AtEndOfFamilyOptions}[1]{% + \expandafter + \l@addto@macro\csname scr@after@options@\FamilyOfKey @hook#1\endcsname +} +\newcommand*{\scr@AtEndOfFamilyOptions@immediate}{% + \kernel@ifstar {\@firstofone}{\@firstofone}% +} +\newcommand*{\AtEndOfFamilyOptions}{} +\let\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions@immediate +% \end{macrocode} +% \end{macro}^^A \scr@@AtEndOfFamilyOptions,\scr@AtEndOfFamilyOptions@immediate +% \end{macro}^^A \scr@AtEndOfFamilyOptions +% \end{command}^^A \AtEndOfFamilyOptions +% \begin{macro}{\scr@ifprocess@curroption} +% \changes{v3.13}{2014/01/04}{brackets around \cs{CurrentOption} inside \cs{setkeys}} +% This macro executes the current \pkg{keyval} option for member +% \texttt{\#1} of family \texttt{\#2}. If the option does not know the value, +% the forth argument is used. Otherwise it is ignored. Note, before the member +% option the family option is executed. If this is successful the member does +% not need to know the option. +% \begin{macrocode} +\newcommand*\scr@ifprocess@curroption[2]{% +% \end{macrocode} +% \changes{v3.26}{2018/10/22}{using \cs{scr@sp@def} instead of \cs{def} for +% splitting the key} +% Because white spaces are not always and forever removed from the option +% list, here \cs{scr@sp@def} is used to eliminate unwanted white spaces before +% the key, before and after the equal sign and at the end of the value. +% \begin{macrocode} + \def\reserved@a##1=##2\@nil{\scr@sp@def\reserved@a{##1}}% + \expandafter\reserved@a\CurrentOption=\@nil + \scr@ifundefinedorrelax{KV@#2@\reserved@a}{% + \scr@ifundefinedorrelax{KV@#2#1@\reserved@a}{% + \let\FamilyKeyState\OptionNotUsed + }{% + \protected@edef\reserved@b{\noexpand\setkeys{#2#1}{{\CurrentOption}}% + \noexpand\def\noexpand\CurrentOption{\CurrentOption}}% + \reserved@b + \ifx\FamilyKeyState\FamilyKeyStateUnknown + \PackageInfo{scrbase}{Unknown processing state.\MessageBreak + Processing option `\CurrentOption'\MessageBreak + of member `#1' of family\MessageBreak + `#2' doesn't set\MessageBreak + a valid state. This will be interpreted\MessageBreak + as \string\FamilyKeyStateProcessed + }% + \FamilyKeyStateProcessed + \fi + }{% + \let\FamilyKeyState\OptionNotUsed + }% + }{% + \protected@edef\reserved@b{\noexpand\setkeys{#2}{{\CurrentOption}}% + \noexpand\def\noexpand\CurrentOption{\CurrentOption}}% + \reserved@b + \ifx\FamilyKeyState\FamilyKeyStateUnknown + \PackageInfo{scrbase}{Unknown processing state.\MessageBreak + Processing option `\CurrentOption'\MessageBreak + of family `#2'\MessageBreak + doesn't set a valid state.\MessageBreak + This will be interpreted\MessageBreak + as \string\FamilyKeyStateProcessed + }% + \FamilyKeyStateProcessed + \fi + \def\reserved@a##1=##2\@nil{\scr@sp@def\reserved@a{##1}}% + \expandafter\reserved@a\CurrentOption=\@nil + \scr@ifundefinedorrelax{KV@#2#1@\reserved@a}{}{% + \protected@edef\reserved@b{\noexpand\setkeys{#2#1}{{\CurrentOption}}% + \noexpand\def\noexpand\CurrentOption{\CurrentOption}}% + \ifx\FamilyKeyState\FamiliyKeyStateProcessed + \reserved@b + \FamilyKeyStateProcessed + \else + \reserved@b + \ifx\FamilyKeyState\FamilyKeyStateUnknown + \PackageInfo{scrbase}{Unknown processing state.\MessageBreak + Processing option `\CurrentOption'\MessageBreak + of member `#1' of family\MessageBreak + `#2' doesn't set\MessageBreak + a valid state. This will be interpreted\MessageBreak + as \string\FamilyKeyStateProcessed + }% + \FamilyKeyStateProcessed + \fi + \fi + }% + }% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +% \end{macrocode} +% \begin{macro}{\scr@sp@d,\scr@sp@b,\scr@sp@c,\scr@sp@def} +% \changes{v3.26}{2018/08/29}{moved from \file{tocbasic.dtx} to +% \file{scrkernel-basics.dtx} and renamed} +% \changes{v3.26b}{2019/01/17}{\cs{long}} +% The helper macro \cs{scr@sp@def} defines a macro (\texttt{\#1}) to contain a +% token list (\texttt{\#2}) and removes tailing spaces at the beginning an the +% end. The original definition was from \pkg{keyval}. The other macros are +% helpers to realize \cs{scr@sp@def}. +% \begin{macrocode} +\def\@tempa#1{% + \long\def\scr@sp@def##1##2{% + \futurelet\scr@sp@tempa\scr@sp@d##2\@nil\@nil#1\@nil\relax##1}% + \def\scr@sp@d{% + \ifx\scr@sp@tempa\@sptoken + \expandafter\scr@sp@b + \else + \expandafter\scr@sp@b\expandafter#1% + \fi}% + \long\def\scr@sp@b#1##1 \@nil{\scr@sp@c##1}% +} +\@tempa{ } +\long\def\scr@sp@c#1\@nil#2\relax#3{\@temptokena{#1}\edef#3{\the\@temptokena}} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@sp@d,\scr@sp@b,\scr@sp@c,\scr@sp@def +% \end{macro}^^A \scr@process@curroption +% \end{command}^^A \FamilyProcessOptions +% +% \begin{command}{\KOMAProcessOptions} +% \changes{v2.97c}{2007/04/18}{added} +% \changes{v3.00}{2008/04/30}{no optional argument} +% This command executes all options, not only classic declared by +% \cs{DeclareOption} or \cs{DeclareOption*}, but also \pkg{keyval} options in +% the order these options have been used (not declared). For packages first +% the global options, than the local options. For classes global and local +% options are the same and only local options are processed. This is similar +% to the \LaTeX{} kernel command \cs{ProcessOptions*} (with the difference of +% processing \pkg{keyval} options too). Family options are always executed +% before member options. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMAProcessOptions}{\FamilyProcessOptions{KOMA}} +\@onlypreamble\KOMAProcessOptions +%</koma> +% \end{macrocode} +% \end{command} +% +% \begin{macro}{\scr@trim@spaces} +% \changes{v3.12}{2013/11/06}{added} +% \changes{v3.26}{2018/08/29}{moved from \file{scrkernel-language.dtx} to +% \file{scrkernel-basics.dtx}} +% \changes{v3.33}{2021/03/02}{moved to preparation section} +% Helper macro to remove white spaces from the beginning or the end. This is +% useful for list processing with \cs{@for} to remove spaces before or after +% commas. The argument is a macro with the string to be trimmed and the result +% is stored again in this macro. +% \begin{macrocode} +%<*base> +\newcommand\scr@trim@spaces[1]{% + \expandafter\scr@sp@def\expandafter#1\expandafter{#1}% +} +%</base> +%</prepare> +% \end{macrocode} +% \end{macro}^^A \scr@trim@space +% +% +% \begin{option}{internalonly} +% \changes{v2.96}{2006/11/26}{added} +% \changes{v2.97c}{2007/06/20}{no argument needed} +% \changes{v3.27a}{2019/11/04}{\cs{FamilyKeyStateProcessed} added} +% \changes{v3.27a}{2019/11/04}{defined only inside the package} +% \changes{v3.27a}{2019/11/04}{defined temporary inside the classes} +% \changes{v3.28}{2019/11/18}{deprecated} +% \begin{macro}{\dont@let@as@internal@defined} +% \changes{v2.96}{2006/11/26}{added} +% \changes{v3.28}{2019/11/18}{removed} +% \end{macro} +% \begin{macrocode} +%<*option> +%<*base> +\DefineFamily{KOMA} +\DefineFamilyMember{KOMA} +\DefineFamilyKey{KOMA}{internalonly}[\relax]{% + \PackageInfo{scrbase}{Ignoring deprecated option `internalonly'}% + \FamilyKeyStateProcessed +} +\AtEndOfPackage{% + \RelaxFamilyKey[.scrbase.sty]{KOMA}{internalonly}% +} +%</base> +% \end{macrocode} +% If \pkg*{scrbase} has been loaded before the class, the option will be +% reported as unused, despite it already has been processed. We could solve +% this using a dummy option inside the classes. However, because the option is +% deprecated the following code should never been used. +% \begin{macrocode} +%</option> +%<*load&class&neveruse> +\KOMA@key{internalonly}[\relax]{% + \FamilyKeyStateProcessed +} +\AtEndOfClass{\RelaxFamilyKey[.\KOMAClassFileName]{KOMA}{internalonly}}% +%</load&class&neveruse> +%<*option> +% \end{macrocode} +% \end{option} +% +% +% \changes{v2.96}{2006/08/20}{processing options} +% \changes{v2.97c}{2007/04/18}{using \cs{KOMAProcessOptions} for processing options} +% \begin{macrocode} +%<koma>\KOMAProcessOptions\relax +%<base>\FamilyProcessOptions{KOMA}\relax +%</option> +%<*body> +% \end{macrocode} +% +% +% \subsection{Some additional math missing from \eTeX} +% +% \begin{command}{\XdivY} +% \changes{v3.05a}{2010/03/10}{added} +% \meta{X} divided by \meta{Y} and rounded to the lower integer. +% \begin{macrocode} +%<*base> +\newcommand*{\XdivY}[2]{% + \numexpr ( #1 + #2 / 2 ) / #2 - 1\relax +} +%</base> +% \end{macrocode} +% \end{command} +% +% \begin{command}{\XmodY} +% \changes{v3.05a}{2010/03/10}{added} +% \meta{X} modulo \meta{Y} (rest of integer division \meta{X} divided by \meta{Y}). +% \begin{macrocode} +%<*base> +\newcommand*{\XmodY}[2]{% + \numexpr #1 - #2 * \XdivY{#1}{#2}\relax +} +%</base> +% \end{macrocode} +% \end{command} +% +% \subsection{Often needed commands and macros} +% +% \begin{macro}{\scr@ForEachTrimmedListElement} +% \changes{v3.27}{2019/04/16}{new (internal)} +% Executes \cs{\#2\{\meta{element}\}} for each \meta{element} of the comma +% separated list \#1. Spaces before for after \meta{element} are eliminated +% and empty elements are ignored. +% \begin{macrocode} +%<*base> +\newcommand{\scr@ForEachTrimmedListElement}[2]{% + \begingroup + \def\reserved@a{\endgroup}% + \@for \reserved@b:=#1 \do {% + \scr@trim@spaces\reserved@b + \ifx\reserved@b\@empty\else + \edef\reserved@a{% + \unexpanded\expandafter{\reserved@a#2}% + {\unexpanded\expandafter{\reserved@b}}% + }% + \fi + }% + \reserved@a +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@ForEachTrimmedListElement +% +% \begin{macro}{\@atdocumenttrue,\@atdocumentfalse,\if@atdocument} +% \changes{v2.95}{2002/12/05}{added} +% \changes{v3.37}{2022/05/06}{\cs{atdocumenttrue} moved with \LaTeX{} +% 2020/10/01 or newer} +% The boolean switch becomes true while |\begin{document}|. \KOMAScript{} uses +% it for commands and macros, which are different in the document preamble and +% the document body. +% \begin{macrocode} +%<*base> +\newif\if@atdocument +\IfLTXAtLeastTF{2020/10/01}{% + \AddToHook{begindocument/before}{\@atdocumenttrue}% +}{% + \AtBeginDocument{\@atdocumenttrue}% +} +\@onlypreamble\@atdocumentrue +\@onlypreamble\@atdocumentfalse +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\let@as@internal@defined} +% \changes{v2.95}{2002/08/19}{added} +% \changes{v2.95c}{2006/08/12}{warning while redefining} +% \changes{v2.96}{2006/11/26}{making user commands from internal macros can +% be banned for single macros} +% \changes{v2.97c}{2007/06/20}{making user commands from internal macros can +% generally banned} +% \changes{v3.10}{2010/10/26}{\cs{ignorespaces} at \cs{document} patch added} +% \changes{v3.13a}{2014/08/13}{unwanted white spaces removed} +% \changes{v3.28}{2019/11/18}{removed} +% \end{macro} +% +% \begin{command}{\ifundefined,\ifundefinedorrelax,\Ifundefinedorrelax} +% \changes{v2.95}{2002/08/21}{added} +% \changes{v2.95c}{2006/08/12}{using an internal macro to define it} +% \changes{v2.97c}{2007/06/20}{\cs{ifundefinedorrelax} replaces \cs{ifundefined}} +% \changes{v3.28}{2019/11/18}{\cs{ifundefinedorrelax} renamed to +% \cs{Ifundefinedorrelax}} +% \changes{v3.29}{2020/01/17}{fix of missing backslash} +% Same as \cs{scr@ifundefinedorrelax} but at user level. +% \begin{macrocode} +%<*base> +\newcommand*{\Ifundefinedorrelax}{\scr@ifundefinedorrelax}% +%</base> +% \end{macrocode} +% \end{command} +% +% \begin{command}{\ifnotundefined,\Ifnotundefined} +% \changes{v2.95}{2002/08/21}{added} +% \changes{v2.95c}{2006/08/12}{using \eTeX{} if possible} +% \changes{v3.02c}{2009/02/19}{\eTeX{} is mandatory} +% \changes{v3.28}{2019/11/18}{\cs{ifnotundefined} renamed to \cs{Ifnotundefined}} +% This is the opposite to \cs{Ifundefinedorrelax}. Sometimes it is useful. +% \begin{macrocode} +%<*base> +\providecommand*{\ifnotundefined}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifnotundefined'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifnotundefined' by `\string\Ifnotundefined'% + }% + \Ifnotundefined +} +\newcommand{\Ifnotundefined}[1]{% + \ifcsname #1\endcsname + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +%</base> +% \end{macrocode} +% \end{command} +% +% \begin{command}{\ifstr,\Ifstr} +% \changes{v2.95}{2004/07/20}{\meta{if code} and \meta{then code} delegated +% after the command execution} +% \changes{v3.04b}{2010/01/29}{\cs{edef} replaced by \cs{protected@edef}} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr} (but still +% available as deprecated command)} +% This command compares two fully expanded token lists. So an alternative name +% would be \cs{Ifxequal}. +% \begin{macrocode} +%<*base> +\providecommand*{\ifstr}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifstr'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifstr' by `\string\Ifstr'% + }% + \Ifstr +} +\newcommand\Ifstr[2]{% + \begingroup\protected@edef\reserved@a{#1}\protected@edef\reserved@b{#2}% + \ifx\reserved@a\reserved@b + \endgroup\expandafter\@firstoftwo + \else + \endgroup\expandafter\@secondoftwo + \fi +} +%</base> +% \end{macrocode} +% \end{command} +% +% \begin{command}{\ifstrstart,\Ifstrstart} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart} (but +% still available as deprecated command)} +% If the expansion of the first argument starts with expansion of the second +% one use the third argument, otherwise the fourth. +% \begin{macrocode} +%<*base> +\providecommand*{\ifstrstart}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifstrstart'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifstrstart' by `\string\Ifstrstart'% + }% + \Ifstrstart +} +\newcommand*{\Ifstrstart}[2]{% + \begingroup + \edef\reserved@a{\noexpand\@ifstrstart{#1}{#2}}% + \reserved@a{\aftergroup\@firstoftwo}{\aftergroup\@secondoftwo}% + \endgroup +} +% \end{macrocode} +% \begin{macro}{\@ifstrstart} +% \changes{v3.12}{2013/11/05}{added} +% Helper. +% \begin{macrocode} +\newcommand*{\@ifstrstart}[2]{% + \def\reserved@a ##1#2##2\@nil{% + \if\relax\detokenize{##1}\relax + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }% + \reserved@a#1#2\@nil +} +%</base> +% \end{macrocode} +% \end{macro}^^A \@ifstrstart +% \end{command}^^A \ifstrstart,\Ifstrstart +% +% \begin{command}{\IfArgIsEmpty} +% \changes{v3.19}{2015/08/29}{added} +% \changes{v3.27}{2019/03/11}{\cs{long}} +% \changes{v3.27}{2019/07/19}{needed already to process options} +% If the first argument is absolutely empty execute the second one, otherwise +% the third one. +%</body> +%<*prepare> +%<*base> +% \begin{macrocode} +\newcommand{\IfArgIsEmpty}[1]{% + \if\relax\detokenize{#1}\relax + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +% \end{macrocode} +%</base> +%</prepare> +%<*body> +% \end{command}^^A \IfArgIsEmpty +% +% +% \begin{command}{\ifislengthprimitive,\Ifislengthprimitive} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.36}{2022/02/17}{\cs{ifislengthprimitive} renamed to +% \cs{Ifislengthprimitive} (but still defined as deprecated)} +% If the first argument expands to a primitive, that can be used as a length, +% execute the second argument, otherwise the third one. +% \begin{macrocode} +%<*base> +\providecommand*{\ifislengthprimitive}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifislengthprimitive'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifislengthprimitive' by `\string\Ifislengthprimitive'% + }% + \Ifislengthprimitive +} +\newcommand*{\Ifislengthprimitive}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifislengthprimitive#1\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifislengthprimitive} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% Helper macro to test against several length like \TeX{} primitives. +% \begin{macrocode} +\newcommand*{\scr@ifislengthprimitive}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifislengthprimitive + }{% + \def\reserved@c{\aftergroup\scr@secondoftwoAfterNil}% + \@for\reserved@a:=\baselineskip,\dp,\hsize,\ht,\lineskip,% + \parindent,\parskip,\pdfpageheight,\pdfpagewidth,% + \wd,\vsize \do {% + \expandafter\Ifstr\expandafter{\expandafter\string\reserved@a}{% + \meaning #1% + }{% + \def\reserved@c{\aftergroup\scr@TestDimenAssignTillNil}% + }% + }% + \reserved@c + }% + \endgroup + #1% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@ifislengthprimitive +% \end{command}^^A \ifislengthprimitive,\Ifislengthprimitive +% +% +% \begin{command}{\ifisdimen,\Ifisdimen} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.20}{2015/10/19}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifisdimen} renamed to \cs{Ifisdimen} (but +% still defined as deprecated command)} +% If the first argument expands to a \cs{dimen} register (and nothing else), +% execute the second argument, otherwise the third one. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisdimen}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisdimen'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisdimen' by `\string\Ifisdimen'% + }% + \Ifisdimen +} +\newcommand*{\Ifisdimen}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisdimen#1\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisdimen} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Helper macro, that tests a macro recursive to expand to a \cs{dimen} register. +% \begin{macrocode} +\newcommand*{\scr@ifisdimen}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisdimen + }{% + \Ifstrstart{\meaning #1}{\string\dimen}{% + \aftergroup\scr@TestDimenAssignTillNil + }{% + \aftergroup\scr@secondoftwoAfterNil + }% + }% + \endgroup + #1% +} +% \end{macrocode} +% \end{macro}^^A \scr@ifisdimen +% \begin{macro}{\scr@TestDimenAssignTillNil} +% \changes{v3.20}{2015/10/19}{added} +% Argument \texttt{\#1} delimited by \cs{@nil} is assigned to a temporary +% length. If this uses the argument completely, the argument \texttt{\#2} behind +% \cs{@nil} will executed, otherwise argument \texttt{\#3}. In any case +% \texttt{\#1} will removed from the input totally. +% \begin{macrocode} +\newcommand*\scr@TestDimenAssignTillNil{} +\def\scr@TestDimenAssignTillNil#1\@nil{% + \begingroup + \afterassignment\scr@AfterEndGroupIfArgIsRelaxTillNnil + \@tempdima=#1\relax\@nnil +} +% \end{macrocode} +% \begin{macro}{\scr@IfAfterEndgroupArgIsRelaxTillNnil,\scr@IfArgIsRelaxAfterRelaxTillNnil} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% The helper macros read an argument delimited by \cs{@nnil}. If this +% arguments consists of a number of \cs{relax} only, the second argument (first +% behind \cs{@nnil}) will be execute, otherwise the third (second behind \cs{@nnil}). +% \begin{macrocode} +\newcommand*\scr@AfterEndGroupIfArgIsRelaxTillNnil{} +\def\scr@AfterEndGroupIfArgIsRelaxTillNnil#1\@nnil{% + \endgroup + \Ifstr{\detokenize{#1}}{\detokenize{\relax}}{\@firstoftwo}{% + \Ifstrstart{\detokenize{#1}}{\detokenize{\relax}}{% + \scr@IfArgIsRelaxAfterRelaxTillNnil #1\@nnil + }{\@secondoftwo}% + }% +} +\newcommand*\scr@IfArgIsRelaxAfterRelaxTillNnil{} +\def\scr@IfArgIsRelaxAfterRelaxTillNnil \relax#1\@nnil{% + \Ifstr{\detokenize{#1}}{\detokenize{\relax}}{\@firstoftwo}{% + \Ifstrstart{\detokenize{#1}}{\detokenize{\relax}}{% + \scr@IfArgIsRelaxAfterRelaxTillNnil #1\@nnil + }{\@secondoftwo}% + }% +} +% \end{macrocode} +% \end{macro}^^A \scr@IfArgIsRelaxTillNnil,\scr@IfArgIsRelaxAfterRelaxTillNnil +% \end{macro}^^A \scr@TestSkipAssignTillNil +% \begin{macro}{\scr@@secondoftwoAfterNil,\scr@secondoftwoAfterNil} +% \changes{v3.20}{2015/10/19}{added} +% The helper macros reads arguments \texttt{\#1} delimited by \cs{@nil} and +% executes \texttt{\#3}. We have to take care for the case of an empty first +% argument, which would make \cs{@nil} to be the argument. Because of this we +% need two helpers. +% \begin{macrocode} +\newcommand*{\scr@secondoftwoAfterNil}{\scr@@secondoftwoAfterNil\@empty} +\newcommand*{\scr@@secondoftwoAfterNil}{} +\def\scr@@secondoftwoAfterNil#1\@nil{\@secondoftwo} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@@secondoftwoAfterNil,\scr@secondoftwoAfterNil +% \end{command}^^A \ifisdimen,\Ifisdimen +% +% \begin{command}{\ifisskip,\Ifisskip} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.18a}{2015/07/07}{\cs{baselineskip} and \cs{parskip} are skips} +% \changes{v3.20}{2015/10/19}{\cs{baselineskip} and \cs{parskip} are not skips} +% \changes{v3.20}{2015/10/19}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifisskip} renamed to \cs{Ifisskip}} +% If the first argument expands to a \cs{skip} register (and nothing else), +% execute the second argument, otherwise the third one. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisskip}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisskip'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisskip' by `\string\Ifisskip'% + }% + \Ifisskip +} +\newcommand*{\Ifisskip}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisskip#1\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisskip} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Helper macro, that tests a macro recursive to expand to a \cs{skip} register. +% \begin{macrocode} +\newcommand*{\scr@ifisskip}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisskip + }{% + \Ifstrstart{\meaning #1}{\string\skip}{% + \aftergroup\scr@TestSkipAssignTillNil + }{% + \aftergroup\scr@secondoftwoAfterNil + }% + }% + \endgroup + #1% +} +% \end{macrocode} +% \end{macro}^^A \scr@ifisskip +% \begin{macro}{\scr@TestSkipAssignTillNil} +% \changes{v3.20}{2015/10/19}{added} +% Argument \texttt{\#1} delimited by \cs{@nil} is assigned to a temporary +% \cs{skip}. If this uses the argument completely, the argument \texttt{\#2} behind +% \cs{@nil} will executed, otherwise argument \texttt{\#3}. In any case +% \texttt{\#1} will removed from the input totally. +% \begin{macrocode} +\newcommand*\scr@TestSkipAssignTillNil{} +\def\scr@TestSkipAssignTillNil#1\@nil{% + \begingroup + \afterassignment\scr@AfterEndGroupIfArgIsRelaxTillNnil + \@tempskipa=#1\relax\@nnil +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@TestSkipAssignTillNil +% \end{command}^^A \ifiskip,\Ifisskip +% +% \begin{command}{\ifiscount,\Ifiscount} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.20}{2015/10/19}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifiscount} renamed to \cs{Ifiscount}} +% If the first argument expands to a \cs{count} register (and nothing else), +% execute the second argument, otherwise the third one. +% \begin{macrocode} +%<*base> +\providecommand*{\ifiscount}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifiscount'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifiscount' by `\string\Ifiscount'% + }% + \Ifiscount +} +\newcommand*{\Ifiscount}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifiscount#1\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifiscount} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Helper macro, that tests a macro recursive to expand to a \cs{count} register. +% \begin{macrocode} +\newcommand*{\scr@ifiscount}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifiscount + }{% + \Ifstrstart{\meaning #1}{\string\count}{% + \aftergroup\scr@TestCountAssignTillNil + }{% + \aftergroup\scr@secondoftwoAfterNil + }% + }% + \endgroup + #1% +} +% \end{macrocode} +% \end{macro}^^A \scr@ifiscount +% \begin{macro}{\scr@TestSkipCountTillNil} +% \changes{v3.20}{2015/10/19}{added} +% Argument \texttt{\#1} delimited by \cs{@nil} is assigned to a temporary +% counter. If this uses the argument completely, the argument \texttt{\#2} behind +% \cs{@nil} will executed, otherwise argument \texttt{\#3}. In any case +% \texttt{\#1} will removed from the input totally. +% \begin{macrocode} +\newcommand*\scr@TestCountAssignTillNil{} +\def\scr@TestCountAssignTillNil#1\@nil{% + \begingroup + \afterassignment\scr@AfterEndGroupIfArgIsRelaxTillNnil + \@tempcnta=#1\relax\@nnil +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@TestCountAssignTillNil +% \end{command}^^A \ifiscount,\Ifiscount +% +% +% \begin{command}{\ifisdimexpr,\Ifisdimexpr} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.20}{2015/10/19}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifisdimexpr} renamed to \cs{Ifisdimexpr}} +% If the first argument expands to a \cs{dimexpr}, +% execute the second argument, otherwise the third one. There is an important +% difference to \cs{Ifisdimen}: If the argument begins with \cs{dimexpr} but +% is not a valid \emph{dimension expression} \cs{Ifisdimexpr} detects a +% \cs{dimexpr}, but using this expression later will result in an error. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisdimexpr}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisdimexpr'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisdimexpr' by `\string\Ifisdimexpr'% + }% + \Ifisdimexpr +} +\newcommand*{\Ifisdimexpr}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisdimexpr#1\relax\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisdimexpr} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Helper macro, that tests a macro recursive to expand to a \cs{dimexpr}. +% \begin{macrocode} +\newcommand*{\scr@ifisdimexpr}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisdimexpr + }{% + \Ifstrstart{\meaning #1}{\string\dimexpr}{% + \aftergroup\scr@TestDimenAssignTillNil + }{% + \aftergroup\scr@secondoftwoAfterNil + }% + }% + \endgroup + #1% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@ifisdimexpr +% \end{command}^^A \ifisdimexpr,\Ifisdimexpr +% +% +% \begin{command}{\ifisglueexpr,\Ifisglueexpr} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.20}{2015/10/19}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifisglueexpr} renamed to \cs{Ifisglueexpr}} +% If the first argument expands to a \cs{glueexpr}, +% execute the second argument, otherwise the third one. There is an important +% difference to \cs{Ifisskip}: If the argument begins with \cs{glueexpr} but +% is not a valid \emph{glue expression} \cs{Ifisglueexpr} detects a +% \cs{göueexpr}, but using this expression later will result in an error. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisglueexpr}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisglueexpr'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisglueexpr' by `\string\Ifisglueexpr'% + }% + \Ifisglueexpr +} +\newcommand*{\Ifisglueexpr}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisglueexpr#1\relax\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisglueexpr} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Helper macro, that tests a macro recursive to expand to a \cs{glueexpr}. +% \begin{macrocode} +\newcommand*{\scr@ifisglueexpr}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisglueexpr + }{% + \Ifstrstart{\meaning #1}{\string\glueexpr}{% + \aftergroup\scr@TestSkipAssignTillNil + }{% + \aftergroup\scr@secondoftwoAfterNil + }% + }% + \endgroup + #1% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@ifisglueexpr +% \end{command}^^A \ifisglueexpr,\Ifisglueexpr +% +% +% \begin{command}{\ifisnumexpr,\Ifisnumexpr} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.20}{2015/10/19}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifisnumexpr} renamed to \cs{Ifisnumexpr}} +% If the first argument expands to a \cs{numexpr}, +% execute the second argument, otherwise the third one. There is an important +% difference to \cs{Ifiscount}: If the argument begins with \cs{numexpr} but +% is not a valid \emph{numerical expression} \cs{Ifisnumexpr} detects a +% \cs{numexpr}, but using this expression later will result in an error. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisnumexpr}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisnumexpr'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisnumexpr' by `\string\Ifisnumexpr'% + }% + \Ifisnumexpr +} +\newcommand*{\Ifisnumexpr}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisnumexpr#1\relax\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisnumexpr} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Helper macro, that tests a macro recursive to expand to a \cs{numexpr}. +% \begin{macrocode} +\newcommand*{\scr@ifisnumexpr}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisnumexpr + }{% + \Ifstrstart{\meaning #1}{\string\numexpr}{% + \aftergroup\scr@TestCountAssignTillNil + }{% + \aftergroup\scr@secondoftwoAfterNil + }% + }% + \endgroup + #1% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@ifisnumexpr +% \end{command}^^A \ifisnumexpr,\Ifisnumexpr +% +% +% \begin{command}{\ifisdefchar,\Ifisdefchar} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.36}{2022/02/17}{\cs{ifisdefchar} renamed to \cs{Ifisdefchar}} +% If the first argument expands to a value defined using \cs{chardef}, +% execute the second argument, otherwise the third one. Note: If the expanded +% argument begins with \verb|\char"| but is not a valid \emph{character value} +% \cs{Ifisdefchar} detects a valid value, but using this value later will +% result in an error. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisdefchar}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisdefchar'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisdefchar' by `\string\Ifisdefchar'% + }% + \Ifisdefchar +} +\newcommand*{\Ifisdefchar}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisdefchar#1\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisdefchar} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Helper macro, that tests a macro recursive to expand to a \cs{char}. +% \begin{macrocode} +\newcommand*{\scr@ifisdefchar}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisdefchar + }{% + \Ifstrstart{\meaning #1}{\string\char\string"}{% + \aftergroup\scr@TestCountAssignTillNil + }{% + \aftergroup\scr@secondoftwoAfterNil + }% + }% + \endgroup + #1% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@ifisdefchar +% \end{command}^^A \ifisdefchar,\Ifisdefchar +% +% +% \begin{command}{\ifiscounter,\Ifiscounter} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.28}{2019/11/19}{\cs{ifiscounter} renamed to \cs{Ifiscounter}} +% If the first argument expands to a \LaTeX{} counter, execute the second +% argument, otherwise the third one. +% \begin{macrocode} +%<*base> +\providecommand*{\ifiscounter}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifiscounter'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifiscounter' by `\string\Ifiscounter'% + }% + \Ifiscounter +} +\newcommand*{\Ifiscounter}[1]{% + \begingroup + \scr@ifundefinedorrelax{c@#1}{% + \aftergroup\@secondoftwo + }{% + \aftergroup\@firstoftwo + }% + \endgroup +} +%</base> +% \end{macrocode} +% \end{command}^^A \ifiscounter,\Ifiscounter +% +% +% \begin{command}{\ifisinteger,\Ifisinteger} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.12a}{2014/01/24}{white space removed} +% \changes{v3.20}{2015/10/19}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifisinteger} renamed to \cs{Ifisinteger}} +% If the first argument expands to a (positive or negative) integer, execute +% the second argument, otherwise the third one. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisinteger}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisinteger'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisinteger' by `\string\Ifisinteger'% + }% + \Ifisinteger +} +\newcommand*{\Ifisinteger}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisinteger#1\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisinteger} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Helper macro to test recursive to a algebraic sign or a number without sign. +% \begin{macrocode} +\def\scr@ifisinteger#1{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisinteger\aftergroup#1% + }{% + \Ifstrstart{\meaning #1}{\detokenize{the character}}{% + \if #1-\aftergroup\scr@ifisinteger + \else + \if #1+\aftergroup\scr@ifisinteger + \else + \ifnum 0=0\if #10\else\if #11\else\if #12\else\if #13\else + \if #14\else\if #15\else\if #16\else\if #17\else + \if #18\else\if #19\else 1\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi + \relax + \aftergroup\scr@TestCountAssignTillNil + \aftergroup#1% + \else + \aftergroup\scr@secondoftwoAfterNil + \aftergroup#1% + \fi + \fi + \fi + }{% + \Ifstrstart{\meaning #1}{\string\char\string"}{% + \aftergroup\scr@TestCountAssignTillNil + }{% + \def\reserved@c{% + \aftergroup\scr@secondoftwoAfterNil + }% + \@for\reserved@a:=\abovedisplayskip,\abovedisplayshortskip,% + \adjdemerits,% + \baselineskip,\belowdisplayskip,% + \belowdisplayshortskip,\binoppenalty,\boxmaxdepth,% + \brokenpenalty,% + \clubpenalty,\count,% + \dimen,\dimexpr,\doublehyphendemerits,\dp,% + \emergenystretch,\exhyphenpenalty,% + \finalhyphendemerits,% + \glueexpr,% + \hbadness,\hfuzz,\hsize,\ht,\hyphenpenalty,% + \lastskip,\lastpenalty,\linepenalty,% + \lineskip,\lineskiplimit,% + \maxdepth,\numexpr,% + \overfullrule,% + \parfillskip,\parindent,\parskip,% + \pdfpageheight,\pdfpagewidth,% + \predisplaypenalty,\pretolerance,% + \relpenalty,\widowpenalty,% + \skip,\splitmaxdepth,\splittopskip,% + \tolerance,\topskip,% + \wd,\vbadness,\vfuzz,\vsize + \do {% + \expandafter\Ifstr\expandafter{\expandafter\string\reserved@a}{% + \meaning #1% + }{% + \def\reserved@c{\aftergroup\scr@TestCountAssignTillNil}% + }% + }% + \reserved@c + }% + \aftergroup#1% + }% + }% + \endgroup +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@ifisinteger +% \end{command}^^A \ifisinteger,\Ifisinteger +% +% +% \begin{macro}{\scr@ifrelax@to@nnil} +% \changes{v3.12}{2013/11/05}{added} +% Helper macro to be used after an assignment. If everything until the first +% \cs{@nnil} is exactly one \cs{relax}, the second argument (first after the +% \cs{@nnil}) will be executed, otherwise the third argument (second after the +% \cs{@nnil}). +% \begin{macrocode} +%<*base> +\newcommand*{\scr@ifrelax@to@nnil}{} +\def\scr@ifrelax@to@nnil#1\@nnil{% + \begingroup + \def\reserved@a{#1}\def\reserved@b{\relax}% + \ifx\reserved@a\reserved@b + \aftergroup\@firstoftwo + \else + \aftergroup\@secondoftwo + \fi + \endgroup +} +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{command}{\ifisdimension,\Ifisdimension} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.12a}{2014/01/24}{white space removed} +% \changes{v3.20}{2015/10/20}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifisdimension} renamed to \cs{Ifisdimension}} +% If the step by step expansion of the first argument results in a (positive +% or negative) length, the second argument will be executed, otherwise the +% third one. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisdimension}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisdimension'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisdimension' by `\string\Ifisdimension'% + }% + \Ifisdimension +} +\newcommand*{\Ifisdimension}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisdimension#1\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisdimension} +% \changes{v3.20}{2015/10/20}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% \changes{v3.28}{2019/11/23}{arithmetic plus sign fixed} +% To make this command absolutely correct without false positive and false +% negative results, it would be very complicated. Instead we use a heuristic: +% If the argument consists of a arbitrary number of arithmetic signs followed +% by at most one dot, comma or digit or followed by something, that is a valid +% lengths primitive, we try an assignment. Invalid assignments can result in +% errors. This is not the best solution but makes things a lot easier. +% \begin{macrocode} +\newcommand*{\scr@ifisdimension}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisdimension\aftergroup#1% + }{% + \Ifstrstart{\meaning #1}{\detokenize{the character}}{% + \if #1-\aftergroup\scr@ifisdimension + \else + \if #1+\aftergroup\scr@ifisdimension + \else + \if #1.% + \aftergroup\scr@TestDimensionAssignTillNil + \aftergroup#1% + \else + \if #1,% + \aftergroup\scr@TestDimensionAssignTillNil + \aftergroup#1% + \else + \ifnum 0=0\if #10\else\if #11\else\if #12\else\if #13\else + \if #14\else\if #15\else\if #16\else\if #17\else + \if #18\else\if #19\else 1\fi\fi + \fi\fi\fi\fi + \fi\fi\fi\fi + \relax + \aftergroup\scr@TestDimensionAssignTillNil + \aftergroup#1% + \else + \aftergroup\scr@secondoftwoAfterNil + \aftergroup#1% + \fi + \fi + \fi + \fi + \fi + }{% + \Ifstrstart{\meaning #1}{\string\char\string"}{% + \aftergroup\scr@TestDimensionAssignTillNil + }{% + \def\reserved@c{% + \aftergroup\scr@secondoftwoAfterNil + \aftergroup\@empty + }% + \@for\reserved@a:=\abovedisplayskip,\abovedisplayshortskip,% + \adjdemerits,% + \baselineskip,\belowdisplayskip,% + \belowdisplayshortskip,\binoppenalty,\boxmaxdepth,% + \brokenpenalty,% + \clubpenalty,\count,% + \dimen,\dimexpr,\doublehyphendemerits,\dp,% + \emergenystretch,\exhyphenpenalty,% + \finalhyphendemerits,% + \glueexpr,% + \hbadness,\hfuzz,\hsize,\ht,\hyphenpenalty,% + \lastskip,\lastpenalty,\linepenalty,% + \lineskip,\lineskiplimit,% + \maxdepth,\numexpr,% + \overfullrule,% + \parfillskip,\parindent,\parskip,% + \pdfpageheight,\pdfpagewidth,% + \predisplaypenalty,\pretolerance,% + \relpenalty,\widowpenalty,% + \skip,\splitmaxdepth,\splittopskip,% + \tolerance,\topskip,% + \wd,\vbadness,\vfuzz,\vsize + \do {% + \expandafter\Ifstr\expandafter{\expandafter\string\reserved@a}{% + \meaning #1% + }{% + \def\reserved@c{\aftergroup\scr@TestDimensionAssignTillNil}% + }% + }% + \reserved@c + }% + \aftergroup#1% + }% + }% + \endgroup +} +% \end{macrocode} +% \begin{macro}{\scr@TestDimenionAssignTillNil} +% \changes{v3.20}{2015/10/19}{added} +% Argument \texttt{\#1} delimited by \cs{@nil} is assigned to a temporary +% length. If this uses the argument completely, the argument \texttt{\#2} behind +% \cs{@nil} will executed, otherwise argument \texttt{\#3}. In any case +% \texttt{\#1} will removed from the input totally. The difference to +% \cs{scr@TestDimenAssignTillNil} is the \texttt{pt} test. +% \begin{macrocode} +\newcommand*\scr@TestDimensionAssignTillNil{} +\def\scr@TestDimensionAssignTillNil#1\@nil{% + \begingroup + \afterassignment\scr@AfterEndGroupIfArgIsRelaxTillptNnil + \@tempdima=#1pt\@nnil +} +% \end{macrocode} +% \begin{macro}{\scr@IfArgIsRelaxAfterRelaxTillptNnil,\scr@IfAfterEndgroupArgIsRelaxTillptNnil} +% \changes{v3.20}{2015/10/19}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% Die Hilfsmakros lesen ein durch \cs{@nnil} begrenztes Argument. Falls dieses +% Argument nur aus einer Folge von \cs{relax} besteht, wird das erste Argument +% nach \cs{@nnil} ausgeführt, sonst das zweite. +% \begin{macrocode} +\newcommand*\scr@AfterEndGroupIfArgIsRelaxTillptNnil{} +\def\scr@AfterEndGroupIfArgIsRelaxTillptNnil#1\@nnil{% + \endgroup + \Ifstr{\detokenize{#1}}{\detokenize{pt}}{\@firstoftwo}{% + \Ifstrstart{\detokenize{#1}}{\detokenize{\relax}}{% + \scr@IfArgIsRelaxAfterRelaxTillptNnil #1\@nnil + }{\@secondoftwo}% + }% +} +\newcommand*\scr@IfArgIsRelaxAfterRelaxTillptNnil{} +\def\scr@IfArgIsRelaxAfterRelaxTillptNnil \relax#1pt\@nnil{% + \Ifstr{\detokenize{#1}}{\detokenize{pt}}{\@firstoftwo}{% + \Ifstrstart{\detokenize{#1}}{\detokenize{\relax}}{% + \scr@IfArgIsRelaxAfterRelaxTillptNnil #1\@nnil + }{\@secondoftwo}% + }% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@IfArgIsRelaxAfterRelaxTillptNnil,\scr@IfAfterEndgroupArgIsRelaxTillptNnil +% \end{macro}^^A \scr@DimensionSkipAssignTillNil +% \end{macro}^^A \scr@ifisdimension +% \end{command}^^A \ifisdimension,\Ifisdimension +% +% +% \begin{command}{\ifisglue} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.12a}{2014/01/24}{white space removed} +% \changes{v3.20}{2015/10/21}{re-implemented} +% \changes{v3.28}{2019/11/19}{\cs{ifisglue} renamed to \cs{Ifisglue}} +% If the step-by-step expansion of the first argument results in a (positive +% or negativ) length with glue, the second argument is executed, otherwise the +% third one. +% \begin{macrocode} +%<*base> +\providecommand*{\ifisglue}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifisglue'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifisglue' by `\string\Ifisglue'% + }% + \Ifisglue +} +\newcommand*{\Ifisglue}[1]{% + \IfArgIsEmpty{#1}{\@secondoftwo}{\scr@ifisglue#1\@nil}% +} +% \end{macrocode} +% \begin{macro}{\scr@ifisglue} +% \changes{v3.20}{2015/10/21}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstrstart} renamed to \cs{Ifstrstart}} +% \changes{v3.28}{2019/11/23}{arithmetic plus sign fixed} +% \changes{v3.28}{2019/11/23}{in plus case \cs{ifisdimension} replaced by +% \cs{ifisglue}} +% To make this command absolutely correct without false positive and false +% negative results, it would be very complicated. Instead we use a heuristic: +% If the argument consists of a arbitrary number of arithmetic signs followed +% by at most one dot, comma or digit or followed by something, that is a valid +% primitive for skips, we try an assignment. Invalid assignments can result in +% errors. This is not the best solution but makes things a lot easier. +% \begin{macrocode} +\newcommand*{\scr@ifisglue}[1]{% + \begingroup + \Ifstrstart{\meaning #1}{\detokenize{macro:}}{% + \aftergroup\expandafter\aftergroup\scr@ifisglue\aftergroup#1% + }{% + \Ifstrstart{\meaning #1}{\detokenize{the character}}{% + \if #1-\aftergroup\scr@ifisglue + \else + \if #1+\aftergroup\scr@ifisglue + \else + \if #1.% + \aftergroup\scr@TestGlueAssignTillNil + \aftergroup#1% + \else + \if #1,% + \aftergroup\scr@TestGlueAssignTillNil + \aftergroup#1% + \else + \ifnum 0=0\if #10\else\if #11\else\if #12\else\if #13\else + \if #14\else\if #15\else\if #16\else\if #17\else + \if #18\else\if #19\else 1\fi\fi + \fi\fi\fi\fi + \fi\fi\fi\fi + \relax + \aftergroup\scr@TestGlueAssignTillNil + \aftergroup#1% + \else + \aftergroup\scr@secondoftwoAfterNil + \aftergroup#1% + \fi + \fi + \fi + \fi + \fi + }{% + \Ifstrstart{\meaning #1}{\string\char\string"}{% + \aftergroup\scr@TestGlueAssignTillNil + }{% + \def\reserved@c{% + \aftergroup\scr@secondoftwoAfterNil + \aftergroup\@empty + }% + \@for\reserved@a:=\abovedisplayskip,\abovedisplayshortskip,% + \adjdemerits,% + \baselineskip,\belowdisplayskip,% + \belowdisplayshortskip,\binoppenalty,\boxmaxdepth,% + \brokenpenalty,% + \clubpenalty,\count,% + \dimen,\dimexpr,\doublehyphendemerits,\dp,% + \emergenystretch,\exhyphenpenalty,% + \finalhyphendemerits,% + \glueexpr,% + \hbadness,\hfuzz,\hsize,\ht,\hyphenpenalty,% + \lastskip,\lastpenalty,\linepenalty,% + \lineskip,\lineskiplimit,% + \maxdepth,\numexpr,% + \overfullrule,% + \parfillskip,\parindent,\parskip,% + \pdfpageheight,\pdfpagewidth,% + \predisplaypenalty,\pretolerance,% + \relpenalty,\widowpenalty,% + \skip,\splitmaxdepth,\splittopskip,% + \tolerance,\topskip,% + \wd,\vbadness,\vfuzz,\vsize + \do {% + \expandafter\Ifstr\expandafter{\expandafter\string\reserved@a}{% + \meaning #1% + }{% + \def\reserved@c{\aftergroup\scr@TestGlueAssignTillNil}% + }% + }% + \reserved@c + }% + \aftergroup#1% + }% + }% + \endgroup +} +% \end{macrocode} +% \begin{macro}{\scr@TestGlueAssignTillNil} +% \changes{v3.20}{2015/10/21}{added} +% Argument \texttt{\#1} delimited by \cs{@nil} is assigned to a temporary +% \cs{skip}. If this uses the argument completely, the argument \texttt{\#2} behind +% \cs{@nil} will executed, otherwise argument \texttt{\#3}. In any case +% \texttt{\#1} will removed from the input totally. The difference to +% \cs{scr@TestSkipAssignTillNil} is the \texttt{pt} test. +% \begin{macrocode} +\newcommand*\scr@TestGlueAssignTillNil{} +\def\scr@TestGlueAssignTillNil#1\@nil{% + \begingroup + \afterassignment\scr@AfterEndGroupIfArgIsRelaxTillptNnil + \@tempskipa=#1pt\@nnil +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@TestGlueAssignTillNil +% \end{macro}^^A \scr@ifisglue +% \end{command}^^A \ifisglue,\Ifisglue +% +% +% \begin{command}{\ifnumber,\Ifnumber} +% \changes{v3.12}{2013/10/30}{using \cs{aftergroup} instead of +% \cs{endgroup}\cs{expandafter}} +% \changes{v3.12a}{2014/01/24}{white space removed} +% \changes{v3.27}{2019/08/26}{empty arguments fixed} +% \changes{v3.28}{2019/11/18}{\cs{ifnumber} renamed to \cs{Ifnumber}} +% If the first argument is a positive integer, the second argument is +% executed, otherwise the third. +% \begin{macrocode} +%<*base> +\providecommand*{\ifnumber}{% +% \end{macrocode} +% Note: We must not output the warning if package \pkg{babelbib} has been +% loaded, because the package defines the same command but only, if it has not +% been defined already. Unfortunately and against all conventions, it even +% defines internal macros of \pkg*{scrbase} with prefix \cs{scr@}. This is +% very dangerous and would result in errors, if \pkg{babelbib} is loaded +% before \pkg*{scrbase}. Maybe I will remove this special treatment of +% \pkg{babelbib} after switching over to \pkg{biblatex} for the \KOMAScript{} +% manuals. +% \begin{macrocode} + \scr@ifundefinedorrelax{ver@babelbib.sty}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifnumber'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifnumber' by `\string\Ifnumber'% + }% + }{}% + \Ifnumber +} +\newcommand\Ifnumber[1]{% + \begingroup\@tempswafalse\let\scr@next\scr@test@number + \IfArgIsEmpty{#1}{}{\expandafter\scr@next#1\scr@next}% + \if@tempswa + \aftergroup\@firstoftwo + \else + \aftergroup\@secondoftwo + \fi + \endgroup +} +% \end{macrocode} +% \begin{macro}{\test@number,\scr@test@number} +% \changes{v3.36}{2022/02/17}{\cs{test@number} renamed to \cs{scr@test@number}} +% For the real test scan the first argument token by token. +% \begin{macrocode} +\newcommand*{\scr@test@number}[1]{% + \ifx \scr@next#1% + \let\scr@next\relax + \else + \@tempcnta=\expandafter\expandafter\expandafter\number + \expandafter`#1\relax + \ifnum \@tempcnta>47 + \ifnum \@tempcnta<58 + \@tempswatrue + \else\@tempswafalse\fi + \else\@tempswafalse\fi +% \end{macrocode} +% Remove the rest, if a non-digit has been found. +% \begin{macrocode} + \if@tempswa\else\let\scr@next\gobble@till@scr@next\fi + \fi + \scr@next +} +% \end{macrocode} +% \begin{macro}{\gobble@tillscr@@next} +% Use a delimited \emph{empty} macro. +% \begin{macrocode} +\newcommand*{\gobble@till@scr@next}{} +\def\gobble@till@scr@next#1\scr@next{} +%</base> +% \end{macrocode} +% \end{macro}^^A \gobble@tillscr@next +% \end{macro}^^A \test@number, \scr@test@number +% \end{command}^^A \ifnumber,\Ifnumber +% +% \begin{command}{\ifintnumber,\Ifintnumber} +% \changes{v3.12}{2013/10/30}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifintnumber} renamed to +% \cs{Ifintnumber}} +% If the first argument is a positive or negative integer, execute the second +% argument, otherwise the third one. There are multiple arithmetic signs allowed. +% \begin{macrocode} +%<*base> +\providecommand*{\ifintnumber}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifintnumber'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifintnumber' by `\string\Ifintnumber'% + }% + \Ifintnumber +} +\newcommand\Ifintnumber[1]{% + \begingroup\@tempswafalse\let\scr@next\scr@test@sign + \expandafter\scr@next#1\scr@next + \if@tempswa + \aftergroup\@firstoftwo + \else + \aftergroup\@secondoftwo + \fi + \endgroup +} +% \end{macrocode} +% \begin{macro}{\scr@test@sign} +% \changes{v3.12}{2013/10/30}{added} +% \begin{macrocode} +\newcommand*{\scr@test@sign}[1]{% + \ifx \scr@next#1 + \let\scr@next\relax + \else + \if #1-% + \else + \ifx #1+% + \else + \def\scr@next{\let\scr@next\scr@test@number\scr@next #1}% + \fi + \fi + \fi + \scr@next +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@test@sign +% \end{command}^^A \ifintnumber,\Ifintnumber +% +% \begin{command}{\ifdimen,\Ifdimen} +% \changes{v3.28}{2019/11/18}{renamed to \cs{Ifdimen}} +% If the first argument is a dimension number, the second argument will be +% executed, otherwise the third. +% \begin{macrocode} +%<*base> +\providecommand*{\ifdimen}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifdimen'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifdimen' by `\string\Ifdimen'% + }% + \Ifdimen +} +\newcommand{\Ifdimen}[1]{% + \begingroup\@tempswatrue\let\scr@next\scr@test@posdimen + \expandafter\scr@test@dimen#1\scr@next + \if@tempswa + \endgroup\expandafter\@firstoftwo + \else + \endgroup\expandafter\@secondoftwo + \fi +} +% \end{macrocode} +% \begin{macro}{\test@dimen,\scr@test@dimen} +% \changes{v3.36}{2022/02/17}{\cs{test@dimen} renamed to \cs{scr@test@dimen}} +% We have to remove the arithmetic signs. +% \begin{macrocode} +\newcommand*{\scr@test@dimen}[1]{% + \ifx -#1\else\ifx +#1\else + \def\scr@next{\let\scr@next\scr@test@posdimen\scr@next#1}\fi\fi + \scr@next +} +% \end{macrocode} +% \begin{macro}{\test@posdimen,\scr@test@posdimen} +% \changes{v3.36}{2022/02/17}{\cs{test@posdimen} renamed to \cs{scr@test@posdimen}} +% Is the rest a dimension. Despite this is not correct, we allow more than one +% decimal point or decimal comma. Should this be changed? +% \begin{macrocode} +\newcommand*{\scr@test@posdimen}[1]{% + \ifx \scr@next#1% + \@tempswafalse\let\scr@next\relax + \else + \if .#1\else\if ,#1\else + \@tempcnta=% + \expandafter\expandafter\expandafter\number\expandafter`#1\relax + \ifnum \@tempcnta>47 + \ifnum \@tempcnta<58 + \else\def\scr@next{\scr@test@dimunt#1}\fi + \else\def\scr@next{\scr@test@dimunt#1}\fi + \fi\fi + \fi + \scr@next +} +% \end{macrocode} +% \begin{macro}{\test@dimunt,\test@trueunt,\scr@test@dimunt,\scr@test@trueunt} +% Last but not least the unit has to be tested. We have standard units and +% true units. So we first cut of a ``\texttt{true}''. +% \begin{macrocode} +\newcommand*{\scr@test@dimunt}{} +\def\scr@test@dimunt#1\scr@next{% + \expandafter\scr@test@trueunt#1truetrue\scr@test@trueunt +} +\newcommand*{\scr@test@trueunt}{} +\def\scr@test@trueunt#1true#2true#3\scr@test@trueunt{% + \edef\reserved@a{#1}% + \ifx\reserved@a\@empty\scr@test@@dimunt{#2}\else\scr@test@@dimunt{#1}\fi +} +% \end{macrocode} +% \begin{macro}{\test@@ifdimunt,\scr@test@@dimunt} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% Currently we know eleven or twelve units. Unit \texttt{px} is only valid +% with PDF output. +% \begin{macrocode} +\newcommand*\scr@test@@dimunt[1]{% + \@tempswafalse + \Ifstr{#1}{pt}{\@tempswatrue}{% + \Ifstr{#1}{pc}{\@tempswatrue}{% + \Ifstr{#1}{in}{\@tempswatrue}{% + \Ifstr{#1}{bp}{\@tempswatrue}{% + \Ifstr{#1}{cm}{\@tempswatrue}{% + \Ifstr{#1}{mm}{\@tempswatrue}{% + \Ifstr{#1}{dd}{\@tempswatrue}{% + \Ifstr{#1}{cc}{\@tempswatrue}{% + \Ifstr{#1}{sp}{\@tempswatrue}{% + \Ifstr{#1}{ex}{\@tempswatrue}{% + \Ifstr{#1}{em}{\@tempswatrue}{% + \scr@ifpdfoutput{% + \Ifstr{#1}{px}{\@tempswatrue}{}% + }{}% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \test@@ifdimunt,\scr@test@@dimunt +% \end{macro}^^A \test@dimunt,\test@trueunt,\scr@test@dimunt,\scr@test@trueunt +% \end{macro}^^A \scr@test@posdimen +% \end{macro}^^A \scr@test@dimen +% \end{command}^^A \ifdimen,\Ifdimen +% +% +% \begin{command}{\ifpdftex} +% \changes{v2.95}{2002/08/19}{added} +% \changes{v3.28}{2019/11/18}{removed} +% \end{command} +% \begin{macro}{\scr@ifpdftex} +% \changes{v2.95}{2002/08/19}{added} +% \changes{v3.30}{2020/03/06}{\cs{ifnotundefined} replaced by \cs{Ifnotundefined}} +% If \pdfTeX{} is used, execute the first argument, otherwise the +% second. Note, we do not read the arguments but delegate them to +% \cs{Ifnotundefined}. +% \begin{macrocode} +%<*base> +\newcommand{\scr@ifpdftex}{\Ifnotundefined{pdftexversion}} +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\scr@ifluatex} +% \changes{v3.21}{2016/05/27}{added} +% \changes{v3.30}{2020/03/06}{\cs{ifnotundefined} replaced by \cs{Ifnotundefined}} +% If \LuaTeX{} is used, execute the first argument, otherwise the +% second. Note, we do not read the arguments but delegate them to +% \cs{Ifnotundefined}. +% \begin{macrocode} +%<*base> +\newcommand{\scr@ifluatex}{\Ifnotundefined{luatexversion}} +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\scr@ifpdforluatex} +% \changes{v3.21}{2016/05/27}{added} +% If either \LuaTeX{} or \pdfTeX{} is used, execute the first argument, +% otherwise the second. Note, we do not read the arguments but delegate them +% to \cs{@firstoftwo} and \cs{@secondoftwo}. +% \begin{macrocode} +%<*base> +\newcommand*{\scr@ifpdforluatex}{% + \scr@ifpdftex{\@firstoftwo}{\scr@ifluatex{\@firstoftwo}{\@secondoftwo}}% +} +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{command}{\ifvtex,\ifVTeX} +% \changes{v2.95}{2002/08/19}{added} +% \changes{v2.97c}{2007/06/20}{\cs{ifvtex} renamed to \cs{ifVTeX}} +% \changes{v3.28}{2019/11/18}{removed} +% \end{command} +% \begin{macro}{\scr@ifvtex,\scr@ifVTeX} +% \changes{v2.95}{2002/08/19}{added} +% \changes{v2.97c}{2007/06/20}{\cs{scr@ifvtex} renamed to \cs{scr@ifVTeX}} +% \changes{v3.30}{2020/03/06}{\cs{ifnotundefined} replaced by \cs{Ifnotundefined}} +% If \VTeX{} is used, execute the first argument, otherwise the +% second. Note, we do not read the arguments but delegate them to +% \cs{Ifnotundefined}. +% \begin{macrocode} +%<*base> +\newcommand{\scr@ifVTeX}{\Ifnotundefined{VTeXversion}} +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{command}{\ifpdfoutput,\Ifpdfoutput} +% \changes{v2.7g}{2001/04/17}{added} +% \changes{v2.8q}{2001/10/19}{\cs{pdfoutput} does not become \cs{relax} if it +% was undefined before} +% \changes{v2.8q}{2001/10/19}{\cs{ifpdfoutput} is only defined if new} +% \changes{v2.8q}{2001/10/19}{usage of \cs{scr@ifpdfoutput}} +% \changes{v3.28}{2019/11/18}{\cs{ifpdfoutput} renamed to \cs{Ifpdfoutput}} +% \begin{macro}{\scr@ifpdfoutput} +% \changes{v2.8q}{2001/10/19}{added} +% \changes{v2.8q}{2001/11/13}{full functional} +% \changes{v2.95}{2002/08/21}{knowing \VTeX} +% \changes{v2.95}{2004/07/20}{expandable} +% \changes{v3.21}{2016/05/27}{works for \LuaTeX{} after version 0.85} +% If the output (currently) produces a PDF, the first argument is executed, +% otherwise the second one. This macro is used inside the implementation of +% option \opt{pagesize}, so we cannot remove it or declare it as deprecated. +% \begin{macrocode} +%<*base> +\newcommand{\scr@ifpdfoutput}{% + \scr@ifundefinedorrelax{pdfoutput}{% + \scr@ifundefinedorrelax{outputmode}{% + \scr@ifundefinedorrelax{OpMode}{% + \expandafter\@secondoftwo% + }{% + \ifnum\OpMode=1 + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }% + }{% + \ifnum\outputmode>0 + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }% + }{% + \ifnum\pdfoutput>0 + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }% +}% +\providecommand*{\ifpdfoutput}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifpdfoutput'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifpdfoutput' by `\string\Ifpdfoutput'% + }% + \Ifpdfoutput +} +\newcommand*{\Ifpdfoutput}{\scr@ifpdfoutput} +%</base> +% \end{macrocode} +% \end{macro} +% \end{command} +% +% \begin{command}{\ifpsoutput,\Ifpsoutput} +% \changes{v2.95}{2002/08/21}{added} +% \changes{v3.28}{2019/11/18}{renamed to \cs{Ifpsoutput}} +% \begin{macro}{\scr@ifpsoutput} +% \changes{v2.95}{2002/08/21}{added} +% \changes{v2.95}{2004/07/20}{expandable} +% \changes{v3.30}{2020/03/06}{\cs{ifnotundefined} replaced by \cs{Ifnotundefined}} +% If the output is (currently) expected to be PS some time, the first argument +% is executed, otherwise the second one. This macro is used inside the +% implementation of option \opt{pagesize}, so we cannot remove it or declare +% it as deprecated. +% \begin{macrocode} +%<*base> +\newcommand*{\scr@ifpsoutput}{% + \Ifnotundefined{if@dvips}{% + \if@dvips + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }{% + \Ifnotundefined{OpMode}{% + \ifnum\OpMode=2 + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }{% + \expandafter\@secondoftwo + }% + }% +} +\providecommand*{\ifpsoutput}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifpsoutput'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifpsoutput' by `\string\Ifpsoutput'% + }% + \Ifpsoutput +} +\newcommand*{\Ifpsoutput}{\scr@ifpsoutput} +%</base> +% \end{macrocode} +% \end{macro} +% \end{command} +% +% \begin{command}{\ifdvioutput,\Ifdvioutput} +% \changes{v2.95}{2002/08/21}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifdvioutput} renamed to \cs{Ifdvioutput}} +% \begin{macro}{\scr@ifdvioutput} +% \changes{v2.95}{2002/08/21}{added} +% \changes{v2.95}{2004/07/20}{expandable} +% \changes{v3.23}{2017/02/14}{works for \LuaTeX{} after version 0.85} +% If the output (currently) produces a DVI, the first argument is executed, +% otherwise the second one. This macro is used inside the implementation of +% option \opt{pagesize}, so we cannot remove it or declare it as deprecated. +% \begin{macrocode} +%<*base> +\newcommand*{\scr@ifdvioutput}{% + \scr@ifundefinedorrelax{pdfoutput}{% + \scr@ifundefinedorrelax{outputmode}{% + \scr@ifundefinedorrelax{OpMode}{% + \expandafter\@firstoftwo + }{% + \ifnum\OpMode=0 + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }% + }{% + \ifnum\outputmode>0 + \expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi + }% + }{% + \ifnum\pdfoutput=0 + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }% +} +\providecommand*{\ifdvioutput}{% + \PackageWarning{scrbase}{Usage of deprecated command + `\string\ifdvioutput'.\MessageBreak + The command has been renamed because of a\MessageBreak + recommendation of The LaTeX Project Team.\MessageBreak + Please replace `\string\ifdvioutput' by `\string\Ifdvioutput'% + }% + \Ifdvioutput +} +\newcommand*{\Ifdvioutput}{\scr@ifdvioutput} +%</base> +% \end{macrocode} +% \end{macro} +% \end{command} +% +% \begin{macro}{\scr@smashdp} +% \changes{v2.97c}{2007/09/17}{added} +% \changes{v3.02a}{2009/01/23}{using own definition instead of \cs{smash}} +% \changes{v3.36}{2022/02/18}{as robust as \cs{smash}} +% Generate a box and output it with height and width but no depth. Note: Using +% internal macros \cs{finsm@sh}, \cs{mathsm@sh} and \cs{makesm@ash} from the +% \LaTeX{} kernel is a very ugly hack and dangerous. Using \cs{smash} itself +% would be problematic, because \pkg{amsmath} redefines it and the new +% definition is not fully compatible. But maybe a better definition could be +% found depending on, whether \pkg{amsmath} has been loaded or not. +% \begin{macrocode} +%<*base> +\DeclareRobustCommand{\scr@smashdp}[1]{% + \relax + \begingroup + \def\finsm@sh{\dp\z@\z@ \leavevmode\box\z@}% + \ifmmode + \expandafter\mathpalette\expandafter\mathsm@sh + \else + \expandafter\makesm@sh + \fi + {#1}% + \endgroup +} +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{command}{\IfRTL} +% \changes{v3.24}{2017/05/04}{added} +% \changes{v3.36}{2022/02/18}{white space removed} +% If we are in the right-to-left mode of a package like \pkg{bidi} the first +% argument will be used otherwise the second one. +% \begin{macrocode} +%<*base> +\newcommand*{\IfRTL}{% + \scr@ifundefinedorrelax{if@RTL}{\@secondoftwo}{% + \expandafter\ifx\csname if@RTL\expandafter\endcsname + \csname iftrue\endcsname + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi + }% +} +%</base> +% \end{macrocode} +% \end{command}^^A \IfRTL +% \begin{command}{\IfLTR} +% \changes{v3.24}{2017/05/04}{added} +% \changes{v3.36}{2022/02/18}{white space removed} +% If we are not in the right-to-left mode of a package like \pkg{bidi} any +% kind of left-to-right mode is assumed and the first argument is used, +% otherwise the second one. +% \begin{macrocode} +%<*base> +\newcommand*{\IfLTR}{% + \scr@ifundefinedorrelax{if@RTL}{\@firstoftwo}{% + \expandafter\ifx\csname if@RTL\expandafter\endcsname + \csname iftrue\endcsname + \expandafter\@secondoftwo + \else + \expandafter\@firstoftwo + \fi + }% +} +%</base> +% \end{macrocode} +% \end{command}^^A \IfLTR +% +% \begin{command}{\PackageInfoNoLine} +% \changes{v2.97d}{2007/10/03}{added} +% Like \cs{PackageInfo} but without output of line number at the end. +% \begin{macrocode} +%<*base> +\providecommand*{\PackageInfoNoLine}[2]{% + \PackageInfo{#1}{#2\@gobble}% +} +%</base> +% \end{macrocode} +% \end{command} +% +% \begin{command}{\ClassInfoNoLine} +% \changes{v2.98c}{2008/02/15}{added} +% Like \cs{ClassInfo} but without output of line number at the end. +% \begin{macrocode} +%<*base> +\providecommand*{\ClassInfoNoLine}[2]{% + \ClassInfo{#1}{#2\@gobble}% +} +%</base> +% \end{macrocode} +% \end{command} +% +% \begin{macro}{\@removefromreset} +% \changes{v3.15}{2014/11/21}{added}% +% For \LaTeX{} releases before 2018/04/01 and without using a package like +% \pkg{remreset} or \pkg{chngcntr} we still need \cs{@removefromreset}. +% \begin{macrocode} +%<*base> +\providecommand*\@removefromreset[2]{% + {% + \expandafter\let\csname c@#1\endcsname\@removefromreset + \def\@elt##1{% + \expandafter\ifx\csname c@##1\endcsname\@removefromreset + \else\noexpand\@elt{##1}\fi + }% + \expandafter\xdef\csname cl@#2\endcsname{\csname cl@#2\endcsname}% + }% +} +%</base> +% \end{macrocode} +% \end{macro} +% +% \begin{command}{\IfActiveMkBoth} +% \changes{v3.26}{2018/09/03}{added} +% \begin{macro}{\if@scrActiveMkBoth} +% \changes{v3.26}{2018/09/03}{added} +% \changes{v3.27}{2019/07/26}{handling for \cs{marks}} +% This command test, whether or not \cs{@mkboth} does change a mark or not. +% \begin{macrocode} +%<*base> +\newif\ifscr@ActiveMkBoth +\def\scr@ActiveMkBothfalse{\global\let\ifscr@ActiveMkBoth\iffalse} +\def\scr@ActiveMkBothtrue {\global\let\ifscr@ActiveMkBoth\iftrue} +\newcommand*{\IfActiveMkBoth}{% + \begingroup + \def\markboth##1##2{\scr@ActiveMkBothtrue}% + \def\markright##1{\scr@ActiveMkBothtrue}% + \def\markleft##1{\scr@ActiveMkBothtrue}% + \def\markboth##1{\scr@ActiveMkBothtrue}% + \def\markdouble##1{\scr@ActiveMkBothtrue}% + \def\mark##1{\scr@ActiveMkBothtrue}% + \def\marks##1##2{\scr@ActiveMkBothtrue}% + \scr@ActiveMkBothfalse + \setbox\@tempboxa\vbox{\@mkboth{}{}}% + \endgroup + \ifscr@ActiveMkBoth + \expandafter\@firstoftwo + \else + \expandafter\@secondoftwo + \fi +} +%</base> +% \end{macrocode} +% \end{macro}^^A \if@scrActiveMkBoth +% \end{command}^^A \IfActiveMkBoth +% +% +% \subsection{Definition of the \KOMAScript{} \pkg*{keyval} main handling} +% +% \begin{command}{\FamilyExecuteOptions} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.04b}{2010/01/29}{\cs{edef} replaced by \cs{protected@edef}} +% \changes{v3.04b}{2010/02/02}{prevent overwriting of \cs{scr@key@atlist} and +% \cs{scr@key@name} in \cs{setkeys}} +% \changes{v3.12}{2013/03/04}{re-implemented} +% \changes{v3.12}{2013/03/04}{can be used after document preamble} +% \changes{v3.14}{2014/10/17}{third argument is \cs{long}} +% \begin{macro}{\@FamilyExecuteOptions} +% \changes{v3.14}{2014/10/17}{new} +% \changes{v3.23}{2017/02/16}{fix: hook after uses family instead of member} +% \changes{v3.27}{2019/10/02}{improved error message} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% Similar to \cs{ExecuteOptions} but with \pkg{keyval} options. The command +% also is re-entrant. Note: The hooks are local to every usage. +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyExecuteOptions}[2][.\@currname.\@currext]{% + \@FamilyExecuteOptions[{#1}]{#2}% +} +\newcommand{\@FamilyExecuteOptions}[3][.\@currname.\@currext]{% + \scr@ifundefinedorrelax{scr@after@options@#2@hook}{% + \@namedef{scr@after@options@#2@hook}{% + \@namedef{scr@after@options@#2@hook}{}% + }% + }{% + \expandafter\edef\csname scr@after@options@#2@hook\endcsname{% + \noexpand\@namedef{scr@after@options@#2@hook}{% + \unexpanded\expandafter\expandafter\expandafter + {\csname scr@after@options@#2@hook\endcsname}% + }% + }% + }% + \@for\scr@key@atlist:=#3\do{% + \expandafter\scr@key@split@name@value\scr@key@atlist==\@nil + \ifx\scr@key@name\@empty\else + \ifx\scr@key@name\space\else + \scr@ifundefinedorrelax{KV@#2@\scr@key@name}{% + \scr@ifundefinedorrelax{KV@#2#1@\scr@key@name}{% +% \end{macrocode} +% \changes{v3.20}{2015/11/18}{special treatment of \opt{@else@} option} +% Neither family nor member option found. But maybe special option +% \opt{@else@} exists. In this case the current option is set as value of +% \opt{@else@}. +% \begin{macrocode} + \scr@ifundefinedorrelax{KV@#2#1@@else@}{% + \PackageError{scrbase}{% + unknown option + `\expandafter\detokenize\expandafter{\scr@key@atlist}'% + }{% + Member `#1' of family `#2'\MessageBreak + cannot handle option `\scr@key@name'.\MessageBreak + So it cannot be set% + \ifx\scr@key@value\@empty\else + \space to value + `\expandafter\detokenize\expandafter{\scr@key@value}'% + \fi.% + }% + }{% + \scr@execute@elseoption{#2#1}% +% \end{macrocode} +% In difference to other options, for \opt{@else@} all states different from +% \cs{FamilyKeyStateProcessed} have to be reported as error of the +% current/original option. +% \begin{macrocode} + \ifx\FamilyKeyState\FamilyKeyStateProcessed\else + \PackageError{scrbase}{% + unknown option + \ifx\FamilyKeyState\FamilyKeyStateUnknownValue + value at + \fi + `\expandafter\detokenize\expandafter{\scr@key@atlist}'% + }{% + Member `#1' of family `#2'\MessageBreak + cannot handle option `\scr@key@name'.\MessageBreak + So it cannot be set% + \ifx\scr@key@value\@empty\else + \space to value + `\expandafter\detokenize\expandafter{\scr@key@value}'% + \fi.% + }% + \fi + }% + }{% + \scr@execute@option{#2#1}% + }% + }{% + \scr@execute@option{#2}% + \Ifstr{#1}{}{}{% +% \end{macrocode} +% \changes{v3.20}{2015/11/18}{member option test after execution of family +% option fixed} +% If a family option has been found and executed an existing member option +% still has to be executed. If no member option exists, also an existing +% \opt{@else@} option of the member has to been used. But in this case, the +% states different from \cs{FamilyKeyStateProcessed} are not errors. +% \begin{macrocode} + \scr@ifundefinedorrelax{KV@#2#1@\scr@key@name}{% + \scr@ifundefinedorrelax{KV@#2#1@@else@}{}{% + \scr@execute@elseoption{#2#1}% + }% + }{% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \scr@execute@option{#2#1}% + \FamilyKeyStateProcessed + \else + \scr@execute@option{#2#1}% + \fi + }% + }% + }% + \scr@show@key@state@error + \fi + \fi + }% + \@nameuse{scr@after@options@#2@hook}% +} +%</base> +% \end{macrocode} +% \begin{macro}{\scr@show@key@state@error} +% \changes{v3.12}{2013/03/04}{added} +% \changes{v3.27}{2019/10/02}{improved error message} +% Show depending on \cs{FamilyKeyState} a error message. All information to +% the error has to be set to \cs{FamilyMemberOfKey} (member or \cs{@empty}), +% \cs{FamilyOfKey} (family or \cs{@empty}), \cs{scr@key@atlest} (option as it +% was in the option list), \cs{scr@key@name} (\meta{key} of the option), and +% \cs{scr@key@value} (\meta{value} of the option). Note: \cs{scr@key@atlist} +% and \cs{scr@key@value} can contain macros and will be output using +% \cs{detokenize}. +% \begin{macrocode} +%<*base> +\newcommand*{\scr@show@key@state@error}{% + \ifx\FamilyKeyState\FamilyKeyStateProcessed\else + \PackageError{scrbase}{% + \ifx\FamilyKeyState\FamilyKeyStateNeedValue + missing option value at + \else + unknown option + \ifx\FamilyKeyState\FamilyKeyStateUnknownValue + value at + \fi + \fi + `\expandafter\detokenize\expandafter{\scr@key@atlist}'% + }{% + Option + `\expandafter\detokenize\expandafter{\scr@key@name}'\MessageBreak + \ifx\FamilyMemberOfKey\@empty\else + of member `\FamilyMemberOfKey'\MessageBreak + \fi + \ifx\FamilyOfKey\@empty\else + of family `\FamilyOfKey'\MessageBreak + \fi + \ifx\FamilyKeyState\FamilyKeyStateNeedValue + expects a value, but has been used without any value.% + \else + cannot handle value\MessageBreak + `\expandafter\detokenize\expandafter{\scr@key@value}',% + \MessageBreak + \ifx\FamilyKeyState\FamilyKeyStateUnknownValue + because this is an unsupported value.% + \else + because \FamilyKeyState. + \fi + \fi + }% + \fi +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@show@key@state@error +% \end{macro}^^A \@FamilyExecuteOptions +% \end{command}^^A \FamilyExecuteOptions +% +% \begin{command}{\KOMAExecuteOptions} +% \changes{v2.97c}{2007/04/19}{added} +% \changes{v3.00}{2008/04/30}{no optional argument} +% \changes{v3.12}{2013/03/04}{can be used after the document preamble} +% Executes a \meta{list of options} (\texttt{\#3}) of a \meta{member} (optional +% \texttt{\#1}) of a \meta{family} (\texttt{\#2}). The default for the +% \meta{member} is \file{.\cs{@currname}.\cs{@currext}}. Note: If +% \cs{KOMAExcuteOptions} is not used while loading a class or package, the +% optional first argument is not optional, but has to be set correctly! And +% because filenames can be changed, it is recommended to \emph{always} use the +% optional argument to set a definite \meta{member}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMAExecuteOptions}[1][.\@currname.\@currext]{% + \FamilyExecuteOptions[#1]{KOMA}% +} +%</koma> +% \end{macrocode} +% \end{command} +% +% \begin{command}{\FamilyOptions} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.12}{2013/03/02}{re-implemented} +% \changes{v3.12}{2013/03/02}{\cs{scr@after@options@\#1@hook}} +% \changes{v3.14}{2014/10/17}{second argument is \cs{long}} +% \begin{macro}{\@FamilyOptions} +% \changes{v3.14}[2014/10/17]{added} +% \changes{v3.27}{2019/10/02}{improved error message} +% \begin{macro}{\Family@Options} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.12}{2013/03/04}{removed} +% \end{macro}^^A \Family@Options +% Used to set the options of a family. The first argument (\texttt{\#1}) is +% the \meta{family} and the second (\texttt{\#2}) a \meta{list of options}. If +% a \meta{key} or a \meta{value} to a \meta{key} in the \meta{list of options} +% does not exist, an error is reported. The command itself is re-entrant, so +% it can be used inside the definition of an option. But in this case the hook +% is local to the local usage of the command. +% \begin{macrocode} +%<*base> +\newcommand{\FamilyOptions}[1]{\@FamilyOptions{#1}} +\newcommand{\@FamilyOptions}[2]{% + \scr@ifundefinedorrelax{scr@after@options@#1@hook}{% + \@namedef{scr@after@options@#1@hook}{% + \@namedef{scr@after@options@#1@hook}{}% + }% + }{% + \expandafter\edef\csname scr@after@options@#1@hook\endcsname{% + \noexpand\@namedef{scr@after@options@#1@hook}{% + \unexpanded\expandafter\expandafter\expandafter + {\csname scr@after@options@#1@hook\endcsname}% + }% + }% + }% +% \end{macrocode} +% \changes{v3.23}{2017/02/16}{\cs{AtEndOfFamilyOptions*} hook added} +% From version 3.23 the new hook before \cs{AtEndOfFamilyOptions*} has to be +% initialized. First step is a kind of pre-initialization: The hook is +% defined empty, if it does not already exist. So if the hook exists empty we +% can now recognize the top level of using \cs{FamilyOptions}. +% \begin{macrocode} + \scr@ifundefinedorrelax{scr@after@options@#1@hook@topmost}{% + \@namedef{scr@after@options@#1@hook@topmost}{}% + }{}% +% \end{macrocode} +% Now, if we recognize the top level, because of an empty hook, the execution +% of the hook to the normal level hook (which is the top level hook in this +% case) is added. Additionally the self destruction code is added to the very +% beginning of the hook. Because of the self destruction hook the hook itself +% it no longer empty. So deeper levels distinguish from the top level. Because +% the hook is not empty any longer. +% \begin{macrocode} + \expandafter\ifx\csname scr@after@options@#1@hook@topmost\endcsname\@empty + \expandafter\l@addto@macro\csname scr@after@options@#1@hook\endcsname{% + \@nameuse{scr@after@options@#1@hook@topmost}% + }% + \@namedef{scr@after@options@#1@hook@topmost}{% + \@namedef{scr@after@options@#1@hook@topmost}{}% + }% + \fi +% \end{macrocode} +% \begin{description} +% \item[Note:] We do not use \pkg{xkeyval} and its \cs{setkeys+}, because this +% would not execute the options in the order of the options but in the order +% of the families, which is not intuitive and therefore not what we want. +% \end{description} +% We use a loop over all \meta{option}s in the \meta{list of options} to +% split each \meta{option} into \meta{key} and \meta{value}. +% \begin{macrocode} + \@for\scr@key@atlist:=#2\do{% +% \end{macrocode} +% \changes{v3.08}{2010/11/05}{empty options in the list are ignored} +% Despite they do not make any sense empty \emph{options} are allowed and +% ignored. This would at first mean two consecutive commas. +% \begin{macrocode} + \ifx\scr@key@atlist\@empty\else +% \end{macrocode} +% But there also can be white spaces between the commas. +% \begin{macrocode} + \ifx\scr@key@atlist\space\else + \expandafter\scr@key@split@name@value\scr@key@atlist==\@nil +% \end{macrocode} +% The third possibility would be a single equal sign. But in my opinion this +% would be a mistake and therefore an error. So now, we have an \opt{option} +% splitted into a \meta{key} and a \meta{value} (which can be empty). +% \changes{v3.12}{2013/03/04}{storing the overall state} +% Now, we are storing the overall state by emptying the error storage. If the +% error storage is \cs{relax} it is not needed any longer. Both, \cs{relax} +% and \cs{@empty} means no error. All other cases the error storage contains +% all the errors to be reported. +% \begin{macrocode} + \let\scr@key@run@errors\@empty +% \end{macrocode} +% \changes{v3.04b}{2010/01/29}{\cs{edef} replaced by \cs{protected@edef}} +% \changes{v3.09a}{2011/06/07}{less number of expansions by improved usage of +% \cs{unexpanded}} +% Next a loop over the members is used, to detect members, that have the +% \meta{key}. In this case the member option is executed. Note: The execution +% of an option must not change any of the internal macros with the \meta{key}, +% \meta{value}, \meta{option} or \meta{list of options} +% information. Additionally the states and the resulting messages have to been +% collected. Here it is useful to have \cs{\meta{family}@key@familylist}, a +% list of family + member and not only of members. +% \changes{v3.27}{2019/07/19}{family options are executed first} +% \begin{macrocode} + \scr@key@found@false + \edef\reserved@a{#1,\csname #1@key@familylist\endcsname}% + \@for\reserved@a:=\reserved@a\do{% + \scr@ifundefinedorrelax{KV@\reserved@a @\scr@key@name}{% +% \end{macrocode} +% \changes{v3.27}{2019/07/19}{treatment of \opt{@else@} options} +% If a family member does not have the current option, there still may be a +% \opt{@else@} option. In this case the \opt{@else@} option gets the current +% \meta{option} as value and is executed. But this changes the error storage +% only, if it was successful. In this case, the error storage has to become +% empty. But the \opt{@else@} must not be executed here, if the current member +% is the empty one, which represents the family itself. This will be done +% later and only, if no one of the members have had the option itself or a +% \opt{@else@} option. So the family \opt{@else@} option is only used, if the +% option has not been successfully processed by any member in any kind. +% \begin{macrocode} + \Ifstr{\reserved@a}{#1}{}{% + \scr@ifundefinedorrelax{KV@\reserved@a @@else@}{}{% + \expandafter\scr@execute@elseoption\expandafter{\reserved@a}% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \scr@key@found@true + \let\scr@key@run@errors\relax + \fi + }% + }% + }{% +% \end{macrocode} +% If the option has been found for a member, it is executed and the error +% storage is updated. +% \begin{macrocode} + \expandafter\scr@execute@option\expandafter{\reserved@a}% + \scr@key@found@true + \ifx\scr@key@run@errors\relax\else + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \let\scr@key@run@errors\relax + \else + \ifx\FamilyKeyState\FamilyKeyStateUnknownValue + \edef\scr@key@run@errors{% + \unexpanded\expandafter{\scr@key@run@errors}% + \noexpand\MessageBreak + \space\space- `\FamilyMemberOfKey': unkown value + `\expandafter\detokenize\expandafter{\scr@key@value}'% + }% + \else + \ifx\FamilyKeyState\FamilyKeyStateNeedValue + \edef\scr@key@run@errors{% + \unexpanded\expandafter{\scr@key@run@errors}% + \noexpand\MessageBreak + \space\space- `\FamilyMemberOfKey': value expected + }% + \else + \edef\scr@key@run@errors{% + \unexpanded\expandafter{\scr@key@run@errors}% + \noexpand\MessageBreak + \space\space- `\FamilyMemberOfKey': \FamilyKeyState + }% + \fi + \fi + \fi + \fi + }% + }% + \ifscr@key@found@ + \ifx\scr@key@run@errors\relax\else + \ifx\scr@key@run@errors\@empty\else +% \end{macrocode} +% \changes{v3.28}{2019/11/23}{error messages and info fixed} +% Now, an existing \opt{@else@} option has to be used and either an error or +% info has to be shown. +% \begin{macrocode} + \scr@ifundefinedorrelax{KV@#1@@else@}{% + \PackageError{scrbase}{% + unknown option + `\expandafter\detokenize\expandafter{\scr@key@atlist}'% + }{% + The members of family `#1' cannot set option + `\scr@key@name' + \ifx\scr@key@value\@empty\else + \MessageBreak + to value + `\expandafter\detokenize\expandafter{\scr@key@value}'% + \fi.\MessageBreak + Here's what each member says: + \scr@key@run@errors + }% + }{% + \scr@execute@elseoption{#1}% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \PackageInfo{scrbase}{% + option + `\expandafter\detokenize\expandafter{\scr@key@atlist}'% + \MessageBreak + processed by `@else@' option of family\MessageBreak + `#1', after the members said: + \scr@key@run@errors\MessageBreak + o\expandafter\@gobble + }% + \let\scr@key@run@errors\relax + \else + \PackageError{scrbase}{% + unknown option + \ifx\FamilyKeyState\FamilyKeyStateUnknownValue + value at + \fi + `\expandafter\detokenize\expandafter{\scr@key@atlist}'% + }{% + The members of family `#1' cannot set option + `\scr@key@name' + \ifx\scr@key@value\@empty\else + \MessageBreak + to value + `\expandafter\detokenize\expandafter{\scr@key@value}'% + \fi.\MessageBreak + Here's what each member says: + \scr@key@run@errors + }% + \fi + }% + \fi + \fi + \else + \scr@ifundefinedorrelax{KV@#1@@else@}{% + \PackageError{scrbase}{% + unknown option + `\expandafter\detokenize\expandafter{\scr@key@atlist}'% + }{% + No one of the members of family `#1'\MessageBreak + can handle option `\scr@key@name'.\MessageBreak + So it cannot be set% + \ifx\scr@key@value\@empty\else + \space to value + `\expandafter\detokenize\expandafter{\scr@key@value}'% + \fi.% + }% + }{% + \scr@execute@elseoption{#1}% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \else + \PackageError{scrbase}{% + unknown option + \ifx\FamilyKeyState\FamilyKeyStateUnknownValue + value at + \fi + `\expandafter\detokenize\expandafter{\scr@key@atlist}'% + }{% + No one of the members of family `#1'\MessageBreak + can handle option `\scr@key@name'.\MessageBreak + So it cannot be set% + \ifx\scr@key@value\@empty\else + \space to value + `\expandafter\detokenize\expandafter{\scr@key@value}'% + \fi.% + }% + \fi + }% + \fi + \fi + \fi + }% + \@nameuse{scr@after@options@#1@hook}% +} +% \end{macrocode} +% \begin{macro}{\scr@execute@option} +% \changes{v3.12}{2013/03/04}{added} +% \changes{v3.13}{2014/06/30}{missing \cs{expandafter} in \cs{PackageInfo} added} +% \changes{v3.13a}{2014/08/13}{white spaces removed} +% \changes{v3.23}{2017/02/16}{it does not help to save the +% \cs{AtEndOfFamilyOptions} hook} +% A split \opt{option} is executed, without changing any relevant macros (but +% \cs{reserved@a}). The first argument is the complete set in \pkg{keyval} syntax. +% \begin{macrocode} +\newcommand*{\scr@execute@option}[1]{% + \protected@edef\reserved@a{% + \noexpand\let\noexpand\KV@err\noexpand\scr@KV@err + \noexpand\setkeys{#1}{% + \unexpanded\expandafter{\scr@key@atlist}}% + \noexpand\def\noexpand\scr@key@atlist{% + \unexpanded\expandafter{\scr@key@atlist}}% + \noexpand\def\noexpand\scr@key@name{% + \unexpanded\expandafter{\scr@key@name}}% + \noexpand\def\noexpand\scr@key@value{% + \unexpanded\expandafter{\scr@key@value}}% + \ifx\scr@key@run@errors\relax + \noexpand\let\noexpand\scr@key@run@errors\relax + \else + \noexpand\def\noexpand\scr@key@run@errors{% + \unexpanded\expandafter{\scr@key@run@errors}}% + \fi + \ifx\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions@immediate + \noexpand\let\noexpand\AtEndOfFamilyOptions + \noexpand\scr@AtEndOfFamilyOptions@immediate + \fi + }% + \let\AtEndOfFamilyOptions\scr@AtEndOfFamilyOptions + \reserved@a + \ifx\FamilyKeyState\FamilyKeyStateUnknown + \PackageInfo{scrbase}{Unknown processing state.\MessageBreak + Processing option + `\expandafter\detokenize\expandafter{\scr@key@atlist}'\MessageBreak + \ifx\FamilyMemberOfKey\@empty\else + of member `\FamilyMemberOfKey'\MessageBreak + \fi + of family `\FamilyOfKey'\MessageBreak + doesn't set a valid state.\MessageBreak + This will be interpreted\MessageBreak + as \string\FamilyKeyStateProcessed + }% + \FamilyKeyStateProcessed + \fi +} +% \end{macrocode} +% \begin{macro}{\scr@KV@err} +% \changes{v3.12a}{2013/03/04}{missing internal command added} +% We just have to signal, that the option needs a value, that is missing. +% \begin{macrocode} +\newcommand*{\scr@KV@err}[1]{% + \FamilyKeyStateNeedValue +} +% \end{macrocode} +% \end{macro}^^A \scr@KV@err +% \begin{macro}{\scr@key@run@errors} +% \changes{v3.12}{2013/03/04}{added} +% Needed by \cs{FamilyOptions} to collect the error messages, but report the +% error only, if no member has successfully processed the option. We define it +% here to make the re-definition in the previous code does work without error. +% \begin{macrocode} +\newcommand*{\scr@key@run@errors}{} +% \end{macrocode} +% \end{macro}^^A \scr@key@run@errors} +% \end{macro}^^A \scr@execute@option +% \begin{macro}{\scr@execute@elseoption} +% \changes{v3.20}{2015/11/18}{added} +% \changes{v3.25}{2017/11/16}{group added} +% \changes{v3.25}{2017/11/16}{\cs{scr@key@name@else} and +% \cs{scr@key@value@else} added} +% \changes{v3.27}{2019/03/10}{missing percent added to avoid spaces} +% If a special option \opt{@else@} has been defined, it is executed by +% \cs{FamilyExecuteOptions} if and only if no other suitable option has been +% found. This is done by \cs{scr@execute@elseoption}. The argument and +% resulting state are exactly the same as with \cs{scr@execute@option}. It +% also have to do the same, but it does not call the option, but the +% \opt{@else@} option. The option itself is used as \meta{value} of the +% \opt{@else@} option. So temporary \cs{scr@key@atlist}, \cs{scr@key@name} and +% \cs{scr@key@value} have to be changed, before calling +% \cs{scr@execute@option}. To avoid once again splitting the \meta{value} into +% an internal \meta{key} and \meta{value} the original \cs{scr@key@name} and +% \cs{scr@key@value} are copied to \cs{scr@key@name@else} and +% \cs{scr@key@value@else}. These can be used inside the code of the +% \opt{@else@} option. +% \begin{macrocode} +\newcommand*{\scr@execute@elseoption}[1]{% + \begingroup + \protected@edef\reserved@a{% + \unexpanded{% + \endgroup + \let\scr@key@name@else\scr@key@name + \let\scr@key@value@else\scr@key@value + \def\scr@key@name{@else@}% + }% + \noexpand\def\noexpand\scr@key@value{% + \unexpanded\expandafter{\scr@key@atlist}}% + \noexpand\def\noexpand\scr@key@atlist{% + @else@={\unexpanded\expandafter{\scr@key@atlist}}}% + \noexpand\scr@execute@option{#1}% + \noexpand\def\noexpand\scr@key@atlist{% + \unexpanded\expandafter{\scr@key@atlist}}% + \noexpand\def\noexpand\scr@key@name{% + \unexpanded\expandafter{\scr@key@name}}% + \noexpand\def\noexpand\scr@key@value{% + \unexpanded\expandafter{\scr@key@value}}% + \scr@ifundefinedorrelax{scr@key@name@else}{% + \unexpanded{\let\scr@key@name@else\relax}% + }{% + \noexpand\def\noexpand\scr@key@name@else{% + \unexpanded\expandafter{\scr@key@name@else}% + }% + }% + \scr@ifundefinedorrelax{scr@key@value@else}{% + \unexpanded{\let\scr@key@value@else\relax}% + }{% + \noexpand\def\noexpand\scr@key@value@else{% + \unexpanded\expandafter{\scr@key@value@else}% + }% + }% + }\reserved@a +} +% \end{macrocode} +% \end{macro}^^A \scr@execute@elseoption +% \begin{macro}{\KOMA@key@foundtrue,\KOMA@key@foundfalse,\ifKOMA@key@found, +% \scr@key@found@true,\scr@key@found@false,\ifscr@key@found@} +% \changes{v2.97c}{2007/04/19}{added} +% \changes{v3.00}{2008/04/30}{\cs{ifKOMA@key@found} renamed to \cs{ifscr@key@found}} +% \begin{macro}{\KOMA@key@at@list,\scr@key@atlist} +% \changes{v2.97c}{2007/04/19}{added} +% \changes{v3.00}{2008/04/30}{\cs{KOMA@key@atlist} renamed to \cs{scr@key@atlist}} +% \begin{macro}{\KOMA@key@name,\scr@key@name} +% \changes{v2.97c}{2007/04/19}{added} +% \changes{v3.00}{2008/04/30}{\cs{KOMA@key@name} renamed to \cs{scr@key@name}} +% \begin{macro}{\KOMA@key@value,\scr@key@value} +% \changes{v2.97c}{2007/04/19}{added} +% \changes{v3.00}{2008/04/30}{\cs{KOMA@key@value} renamed to \cs{scr@key@value}} +% \begin{macro}{\KOMA@key@split@name@value,\scr@key@split@name@value} +% \changes{v2.97c}{2007/04/19}{added} +% \changes{v2.97e}{2007/11/10}{using \cs{KV@@sp@def} to remove white spaces} +% \changes{v3.00}{2008/04/30}{\cs{KOMA@key@split@name@value} renamed to +% \cs{scr@key@split@name@value}} +% \changes{v3.13}{2014/10/17}{\cs{long}} +% \changes{v3.26}{2018/08/29}{using \cs{scr@sp@def} instead of \cs{KV@@sp@def}} +% \begin{macrocode} +\newif\ifscr@key@found@ +\newcommand*{\scr@key@atlist}{} +\newcommand*{\scr@key@name}{} +\newcommand*{\scr@key@value}{} +\newcommand*{\scr@key@split@name@value}{} +\long\def\scr@key@split@name@value#1=#2=#3\@nil{% + \scr@sp@def\scr@key@name{#1}% + \scr@sp@def\scr@key@value{#2}% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \scr@key@split@name@value +% \end{macro}^^A \scr@key@value +% \end{macro}^^A \scr@key@name +% \end{macro}^^A \scr@key@atlist +% \end{macro}^^A \@FamilyOptions +% \end{macro}^^A \ifscr@key@found@ +% \end{command}^^A \FamilyOptions +% +% \begin{command}{\FamilyOption} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.26b}{2019/01/09}{handling of typical user mistakes} +% \begin{macro}{\@FamilyOptions} +% \changes{v3.14}[2014/10/17]{added} +% \changes{v3.26}{2018/08/29}{using \cs{scr@sp@def} instead of \cs{KV@@sp@def}} +% \begin{macro}{\Family@Option} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.12}{2013/03/04}{removed} +% \end{macro}^^A \Family@Option +% \changes{v3.04b}{2010/01/29}{\cs{edef} replaced by \cs{protected@edef}} +% In opposite to \cs{FamilyOptions} this command sets only one \meta{option} +% (\texttt{\#2}) of a \meta{family} (\texttt{\#1}). But you can set it to a +% \meta{list of values} (\texttt{\#3}). The values are set in the order of the +% \meta{list of values}. +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyOption}[2]{% + \begingroup + \def\reserved@a##1,##2\@nil{\IfArgIsEmpty{##2}{}{\@tempswatrue}}% + \@tempswafalse\expandafter\reserved@a#2,\@nil + \if@tempswa + \PackageError{scrbase}{% + syntax error in key `\detokenize{#2}'% + }{% + You've used `\string\...Option' to set the key + `\detokenize{#2}'\MessageBreak + to new value(s), but `,' is not allowed in the key of + an option\MessageBreak + (and `\string\...Option' does not use `,' to separate several + keys).\MessageBreak + Maybe you've meant \string\...Options\space instead of + \string\...Option.\MessageBreak + If you'll continue, I'll give it a try, but you should expect + further\MessageBreak + and even strange error messages.% + }% + \else + \def\reserved@a##1=##2\@nil{% + \IfArgIsEmpty{##2}{}{\@tempswatrue\def\reserved@a{=}}}% + \expandafter\reserved@a#2=\@nil + \if@tempswa + \PackageError{scrbase}{% + syntax error in key `\detokenize{#2}'% + }{% + You've used `\string\...Option' to set the key + `\detokenize{#2}'\MessageBreak + to new value(s), but `=' is not allowed in the key of + an option\MessageBreak + (and `\string\...Option' does not use `=' to separate key and + value).\MessageBreak + Maybe you've meant \string\...Options\space instead of + \string\...Option.\MessageBreak + If you'll continue, I'll give it a try, but you should expect + further\MessageBreak + and even strange error messages.% + }% + \fi + \fi + \endgroup + \@FamilyOption{#1}{#2}% +} +\newcommand{\@FamilyOption}[3]{% + \expandafter\scr@sp@def\expandafter\scr@key@name\expandafter{#2}% +% \end{macrocode} +% The most simply solution is to walk through the \meta{list of values} and +% generate a \meta{list of options} for \cs{FamilyOptions}. +% \begin{macrocode} + \let\reserved@a\@empty + \@for\reserved@b:=#3\do{% +% \end{macrocode} +% \changes{v3.08}{2010/11/05}{allow empty values} +% Empty elements in the \meta{list of values} are ignored. Note: This is not +% really the correct solution but several users expect it. So for a real empty +% value you need to use |{}|. +% \begin{macrocode} + \ifx\reserved@b\@empty\else +% \end{macrocode} +% \changes{v3.12}{2012/03/04}{ignore white space values} +% The same for white space values. +% \begin{macrocode} + \ifx\reserved@b\space\else + \edef\reserved@a{\unexpanded\expandafter{\reserved@a},% + \scr@key@name=\unexpanded\expandafter{\reserved@b}}% + \fi + \fi + }% + \def\reserved@b{\FamilyOptions{#1}}% + \expandafter\reserved@b\expandafter{\reserved@a}% +} +%</base> +% \end{macrocode} +% \end{macro} +% \end{command} +% +% \begin{command}{\KOMAoptions} +% \changes{v2.96}{2006/08/20}{hook after options added} +% \changes{v2.97c}{2007/04/19}{process options of all members} +% \changes{v3.12}{2013/03/04}{using hooks of \cs{FamilyOptions}} +% Nice little shortcut. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMAoptions}{\FamilyOptions{KOMA}} +%</koma> +% \end{macrocode} +% \begin{macro}{\KOMA@options} +% \changes{v2.97c}{2007/04/19}{added} +% \changes{v3.12}{2013/03/04}{removed} +% \end{macro}^^A \KOMA@options +% \end{command}^^A \KOMAoptions +% +% \begin{command}{\KOMAoptionsOf} +% \changes{v3.17}{2015/02/25}{added} +% Ask for the currently set options of a supporting \KOMAScript{} class or +% package. The optional first argument (\texttt{\#1}) is a command or macro, +% that will be execute with the list of options as an argument. The second +% argument (\texttt{\#2}) is the filename of a \KOMAScript{} class or package +% (with extension). Without optional argument, the \meta{list of options} are +% be printed. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMAoptionsOf}[2][\@firstofone]{% + \scr@ifundefinedorrelax{scr@kav@KOMA.#2}{% + \PackageError{scrkbase}{\string\KOMAoptionsOf\space not supported}{% + #2 is not the name of a KOMA-Script package or\MessageBreak + KOMA-Script class, that supports \string\KOMAoptionsOf.}% + }{% + \begingroup + \def\reserved@a{#1}% + \KOMA@kav@defall\reserved@b{.#2}% + \expandafter\expandafter\expandafter\endgroup + \expandafter\reserved@a\expandafter{\reserved@b}% + }% +} +%</koma> +% \end{macrocode} +% \end{command}^^A \KOMAoptionsOf +% +% \begin{command}{\KOMAoptionOf} +% \changes{v3.17}{2015/02/26}{added} +% Ask for the current values of one option of a supporting \KOMAScript{} class +% or package. Again the optional first argument (\texttt{\#1}) is a command or +% macro, that will be execute with the list of values as an argument. The second +% argument (\texttt{\#2}) is the filename of a \KOMAScript{} class or package +% (with extension). The third argument (\texttt{\#3}) is the name of an +% option of the class resp. package. Without optional argument, the \meta{list of +% values} are be printed. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMAoptionOf}[3][\@firstofone]{% + \scr@ifundefinedorrelax{scr@kav@KOMA.#2}{% + \PackageError{scrkbase}{\string\KOMAoptionOf\space not supported}{% + #2 is not the name of a KOMA-Script package or\MessageBreak + KOMA-Script class, that supports \string\KOMAoptionOf.}% + }{% + \begingroup + \def\reserved@a{#1}% + \KOMA@kav@defone\reserved@b{.#2}{#3}% + \ifx\reserved@b\@empty + \PackageWarning{scrkbase}{option `#3' for `#2' unset}% + \endgroup + \else + \expandafter\expandafter\expandafter\endgroup + \expandafter\reserved@a\expandafter{\reserved@b}% + \fi + }% +} +%</koma> +% \end{macrocode} +% \end{command} +% +% \begin{macro}{\post@kopt@hook} +% \changes{v3.12}{2013/03/04}{removed} +% \end{macro}^^A \post@kopt@hook +% \begin{command}{\AfterKOMAoptions} +% \changes{v3.12}{2013/03/04}{using \cs{AtEndOfFamilyOptions}} +% \changes{v3.23}{2017/02/16}{\cs{newcommand} instead of \cs{let}} +% An option can process code after executing all options of the current +% \cs{KOMAoptions}. +% \begin{macrocode} +%<*koma> +\newcommand*{\AfterKOMAoptions}{\AtEndOfFamilyOptions} +%</koma> +% \end{macrocode} +% \end{command}^^A \AfterKOMAoptions +% +% \begin{macro}{\l@addto@macro} +% \changes{v2.8p}{2001/09/22}{added} +% \changes{v2.95}{2006/06/02}{changed to handle macros with arguments same +% like \cs{g@addto@macro}} +% \changes{v3.12}{2013/04/20}{removed non-\eTeX{} implementation} +% \changes{v3.12}{2013/04/20}{warn, if \cs{l@addto@macro} is already defined +% different from our definition} +% \changes{v3.23}{2017/02/16}{moved to \texttt{prepare}} +% We need a local variant of \cs{g@addto@macro}. +% \begin{macrocode} +%</body> +%<*base&prepare> +\@ifundefined{l@addto@macro}{}{% + \begingroup + \long\def\reserved@a#1#2{% + \edef#1{\unexpanded\expandafter{#1#2}}% + }% + \ifx\reserved@a\l@addto@macro\else + \PackageWarning{scrbase}{% + Someone also uses macro name \string\l@addto@macro.\MessageBreak + When KOMA-Script author decided to use macro name\MessageBreak + \string\l@addto@macro\space first, there was no other + free\MessageBreak + LaTeX package using this macro name.\MessageBreak + In the meantime other package authers decided to use\MessageBreak + same macro name, but unfortunatly not all of those\MessageBreak + are compatible with KOMA-Script's definition, e.g.,\MessageBreak + while adding definitions with arguments to macros.\MessageBreak + Because of such potentially incompatible definitions,\MessageBreak + KOMA-Script will redefine the command now.\MessageBreak + Please ask the author of the other package to\MessageBreak + rename his macro, if a problem results in the\MessageBreak + redefinition% + }% + \fi + \endgroup +} +\long\def\l@addto@macro#1#2{% + \edef#1{\unexpanded\expandafter{#1#2}}% +}% +%</base&prepare> +%<*body> +% \end{macrocode} +% \end{macro}^^A \l@addto@macro +% +% \begin{macro}{\l@addto@macro@a} +% \changes{v3.20}{2015/11/20}{added} +% I also need a version for macros with exactly one argument. Note: This macro +% is dangerous. Sometimes it does not work correctly, so there is not an will +% not be an official documentation. +% \begin{macrocode} +%<*base> +\begingroup + \catcode`\^^A=\catcode`\# + \@makeother\# + \gdef\l@addto@macro@a^^A1{% + \begingroup + \@makeother\# + \def\l@addto@macro@a@cmd{^^A1}% + \l@addto@macro@a@ + } + \gdef\l@addto@macro@a@^^A1{% + \def\l@addto@macro@a@add{^^A1}% + \l@addto@macro@a@@ + } +\endgroup +\begingroup + \@makeother\# + \gdef\l@addto@macro@a@@{% + \@makeother\# + \edef\reserved@a{% + \detokenize{\endgroup\def}% + \detokenize\expandafter{\l@addto@macro@a@cmd#1}% + {% + \expandafter\detokenize% + \expandafter\expandafter\expandafter{\l@addto@macro@a@cmd{#1}}% + \expandafter\detokenize\expandafter{\l@addto@macro@a@add}% + }% + }% + \expandafter\scantokens\expandafter{\reserved@a}% + }% +\endgroup +%</base> +% \end{macrocode} +% \end{macro}^^A \l@addto@macro@a +% +% \begin{macro}{\l@preto@macro} +% \changes{v3.20}{2015/11/25}{added} +% Similar to \cs{l@addto@macro} but adds code at the very beginning instead of +% appending it a the end. +% \begin{macrocode} +%<*base> +\newcommand\l@preto@macro[2]{% + \edef#1{\unexpanded{#2}\unexpanded\expandafter{#1}}% +}% +%</base> +% \end{macrocode} +% \end{macro}^^A \l@preto@macro +% +% \begin{macro}{\l@preto@macro@a} +% \changes{v3.20}{2015/11/25}{added} +% I also need a version for macros with exactly one argument. Note: This macro +% is dangerous. Sometimes it does not work correctly, so there is not an will +% not be an official documentation. +% \begin{macrocode} +%<*base> +\begingroup + \catcode`\^^A=\catcode`\# + \@makeother\# + \gdef\l@preto@macro@a^^A1{% + \begingroup + \@makeother\# + \def\l@preto@macro@a@cmd{^^A1}% + \l@preto@macro@a@ + } + \gdef\l@preto@macro@a@^^A1{% + \def\l@preto@macro@a@add{^^A1}% + \l@preto@macro@a@@ + } +\endgroup +\begingroup + \@makeother\# + \gdef\l@preto@macro@a@@{% + \@makeother\# + \edef\reserved@a{% + \detokenize{\endgroup\def}% + \detokenize\expandafter{\l@preto@macro@a@cmd#1}% + {% + \expandafter\detokenize\expandafter{\l@preto@macro@a@add}% + \expandafter\detokenize% + \expandafter\expandafter\expandafter{\l@preto@macro@a@cmd{#1}}% + }% + }% + \expandafter\scantokens\expandafter{\reserved@a}% + }% +\endgroup +%</base> +% \end{macrocode} +% \end{macro}^^A \l@preto@macro@a +% +% \begin{command}{\KOMAoption} +% \changes{v2.98c}{2008/03/12}{added} +% \changes{v3.12}{2013/03/04}{using \cs{FamilyOption}} +% Simple little shortcut. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMAoption}{\FamilyOption{KOMA}} +%</koma> +% \end{macrocode} +% \end{command} +% +% \begin{command}{\FamilyUnknownKeyValue} +% \changes{v3.10}{2011/09/12}{no error while processing global options} +% \changes{v3.11a}{2012/05/28}{prevent remove from list of unused global +% options globally} +% \changes{v3.14}{2014/10/17}{\cs{long}} +% \changes{v3.30}{2020/02/25}{spurious space in warning message removed} +% Used to report an error because of unknown values. Arguments are +% \marg{family}\marg{key}\marg{valid values}. +% \begin{macrocode} +%<*base> +\newcommand{\FamilyUnknownKeyValue}[4]{% + \FamilyKeyStateUnknownValue + \ifx\FamilyElseValues\@empty\else + \PackageWarning{scrbase}{non empty \string\FamilyElseValue + ignored.\MessageBreak + Setting this command to a non empty\MessageBreak + value for option `#2' of\MessageBreak + family `#1' is deprecated,\MessageBreak + but has been found% + }% + \fi +} +%</base> +% \end{macrocode} +% \begin{command}{\FamilyElseValues} +% \changes{v3.00}{2008/05/02}{added} +% \changes{v3.12}{2013/03/04}{deprecated and not used internally} +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyElseValues}{} +%</base> +% \end{macrocode} +% \end{command}^^A \FamilyUnknownKeyValue +% \end{command}^^A \FamilyElseValue +% +% \begin{command}{\FamilyBoolKey} +% \changes{v3.00}{2008/04/30}{added} +% Defining a new boolean key: +% \begin{quote} +% \cs{FamilyBoolKey}\oarg{member}\marg{family}\marg{key}\marg{switch} +% \end{quote} +% The default \meta{member} is (once again) +% \file{.\cs{@currname}.\cs{@currext}} and it is recommended to always use it! +% \cs{if\meta{switch}} is automatically defined, if it was undefined. In this +% case the initial value is \opt{false}. The default for using the \meta{key} +% without argument would be \opt{true}. For other allowed values see +% \cs{FamilySetBool}. +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyBoolKey}[4][.\@currname.\@currext]{% + \@ifundefined{if#4}{% + \expandafter\newif\csname if#4\endcsname + }{}% + \DefineFamilyKey[{#1}]{#2}{#3}[true]{\FamilySetBool{#2}{#3}{#4}{##1}}% +} +% \end{macrocode} +% \begin{command}{\FamilySetBool} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.11a}{2012/05/25}{error message fixed} +% \changes{v3.27}{2019/07/08}{empty argument is \texttt{true}} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% Setting a boolean key: +% \begin{quote} +% \cs{FamilySetBool}\marg{family}\marg{key}\marg{switch}\marg{value} +% \end{quote} +% The \meta{family} and the \meta{key} are used for reporting unknown values using +% \cs{FamilyUnknownKeyValue}. The \meta{switch} is used to use either +% \cs{\meta{switch}true} or \cs{\meta{switch}false}. It is ignored, if these +% are not defined, so have to take care, that \cs{if\meta{switch}} already has +% been defined, e.g., using \cs{FamilyBoolKey}. The \meta{value} can either be +% \opt{true}, \opt{on} or \opt{yes} for \cs{\meta{switch}true} or +% \opt{false}, \opt{off} or \opt{no} for \cs{\meta{switch}false}. +% \begin{macrocode} +\newcommand*{\FamilySetBool}[4]{% + \Ifstr{#4}{}{\@nameuse{#3true}\FamilyKeyStateProcessed}{% + \Ifstr{#4}{true}{\@nameuse{#3true}\FamilyKeyStateProcessed}{% + \Ifstr{#4}{on}{\@nameuse{#3true}\FamilyKeyStateProcessed}{% + \Ifstr{#4}{yes}{\@nameuse{#3true}\FamilyKeyStateProcessed}{% + \Ifstr{#4}{false}{\@nameuse{#3false}\FamilyKeyStateProcessed}{% + \Ifstr{#4}{off}{\@nameuse{#3false}\FamilyKeyStateProcessed}{% + \Ifstr{#4}{no}{\@nameuse{#3false}\FamilyKeyStateProcessed}{% + \FamilyUnknownKeyValue{#1}{#2}{#4}{% + `true', `on', `yes', `false', `off', `no'% + }% + }% + }% + }% + }% + }% + }% + }% + \let\FamilyElseValues\@empty +} +%</base> +% \end{macrocode} +% \end{command} +% \end{command} +% \begin{command}{\FamilyInverseBoolKey,\FamilySetInverseBool} +% \changes{3.27}{2019/07/08}{added} +% These are similar to \cs{FamilyBoolKey} and \cs{FamilySetBoolKey} but use +% inverse logic (true sets false and false sets true). +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyInverseBoolKey}[4][.\@currname.\@currext]{% + \@ifundefined{if#4}{% + \expandafter\newif\csname if#4\endcsname + \@nameuse{#4true}% + }{}% + \DefineFamilyKey[{#1}]{#2}{#3}[true]{\FamilySetInverseBool{#2}{#3}{#4}{##1}}% +} +\newcommand*{\FamilySetInverseBool}[4]{% + \FamilySetBool{#1}{#2}{#3}{#4}% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \expandafter\ifx\csname if#3\expandafter\endcsname\csname iftrue\endcsname + \@nameuse{#3false}% + \else + \@nameuse{#3true}% + \fi + \fi +} +%</base> +% \end{macrocode} +% \end{command}^^A \FamilyInverseBoolKey,\FamilySetInverseBool +% +% \begin{macro}{\KOMA@unknown@keyval} +% Version of \cs{FamilyUnknownKeyValue} with static family |KOMA|. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@unknown@keyval}{\FamilyUnknownKeyValue{KOMA}} +%</koma> +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KOMA@ifkey} +% \changes{v3.02c}{2009/02/04}{defines the member if needed} +% \changes{v3.17}{2015/03/02}{replaces the value in the storage} +% This is an extended version of \cs{FamilyBoolKey} with static family +% |KOMA|. So the syntax is: +% \begin{quote} +% \cs{KOMA@ifkey}\oarg{member}\marg{key}\marg{switch} +% \end{quote} +% The default \meta{member} is (once again) +% \file{.\cs{@currname}.\cs{@currext}} and it is recommended to always use it! +% \cs{if\meta{switch}} is automatically defined, if it was undefined. The +% default for using the \meta{key} without argument would be \opt{true}. Note: +% \meta{member} and \meta{key} are always fully expanded. Depending on a +% already existing \cs{if\meta{key}} either \opt{\meta{key}=true} or +% \opt{\meta{key}=false} is added to the value storage. If \cs{if\meta{key}} +% was not defined, the initialized value is \opt{false}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@ifkey}[2][.\@currname.\@currext]{% + \begingroup\edef\reserved@a{\noexpand\KOMA@@ifkey{#1}{#2}}% + \expandafter\endgroup\reserved@a +} +\newcommand*{\KOMA@@ifkey}[3]{% + \@ifundefined{if#3}{% + \expandafter\newif\csname if#3\endcsname + }{}% + \KOMA@key[{#1}]{#2}[true]{% + \KOMA@set@ifkey{#2}{#3}{##1}% + \KOMA@kav@replacebool{#1}{#2}{#3}% + }% + \csname if#3\endcsname + \KOMA@kav@xadd{#1}{#2}{true}% + \else + \KOMA@kav@xadd{#1}{#2}{false}% + \fi +} +%</koma> +% \end{macrocode} +% \begin{macro}{\KOMA@set@ifkey} +% Simple a shortcut for |\FamilySetBool{KOMA}|. So the syntax is: +% \begin{quote} +% \cs{KOMA@set@ifkey}\marg{key}\marg{switch}\marg{value} +% \end{quote} +% But all arguments are delegated. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@set@ifkey}{\FamilySetBool{KOMA}} +%</koma> +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{command}{\FamilyCounterKey} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.15}{2014/12/03}{optional default value} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by +% \cs{kernel@ifnextchar}} +% Defining a \meta{key} that sets a \LaTeX{} counter to a \meta{value}. +% \begin{quote} +% \cs{FamilyCounterKey}\oarg{member}\marg{family}\marg{key}\oarg{default}\marg{\LaTeX{} counter} +% \end{quote} +% \meta{default} and the \meta{value} of the option has to be (almost) any +% kind of value, that can be assigned to a \LaTeX{} counter. The +% \meta{counter} is automatically defined, if it was undefined. In this case +% the initial value is 0. +% \begin{macro}{\Family@@Counter@@Key,\Family@Counter@Key} +% \changes{v3.15}{2014/12/03}{added} +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyCounterKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar [%] + {\Family@@Counter@@Key{#1}{#2}{#3}}% + {\Family@Counter@Key{#1}{#2}{#3}}% +} +\newcommand*{\Family@@Counter@@Key}{} +\def\Family@@Counter@@Key#1#2#3[#4]#5{% + \@ifundefined{c@#5}{\newcounter{#5}}{}% + \DefineFamilyKey[{#1}]{#2}{#3}[{#4}]{\FamilySetCounter{#2}{#3}{#5}{##1}}% +} +\newcommand*{\Family@Counter@Key}[4]{% + \@ifundefined{c@#4}{\newcounter{#4}}{}% + \DefineFamilyKey[{#1}]{#2}{#3}{\FamilySetCounter{#2}{#3}{#4}{##1}}% +} +% \end{macrocode} +% \end{macro} +% \begin{command}{\FamilySetCounter} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.18a}{2015/07/06}{using \cs{FamilyKeyStateProcessed}} +% \changes{v3.23}{2017/02/23}{white space replaced by \cs{relax}} +% Set the value of a \meta{key} defined by \cs{FamilyCounterKey}: +% \begin{quote} +% \cs{FamilySetCounter}\marg{family}\marg{key}\marg{counter}\marg{value} +% \end{quote} +% Note: Before assigning the \meta{value} to the \meta{counter} tests are +% done, if the \meta{value} can be used to be assigned to a \LaTeX{} +% counter. If this fails a unknown value is reported. +% \begin{macrocode} +\newcommand*{\FamilySetCounter}[4]{% + \begingroup + \protected@edef\reserved@a{#4}% + \def\reserved@b{\endgroup\value{#3}=#4\relax\FamilyKeyStateProcessed}% + \expandafter\Ifiscount\expandafter{\reserved@a}{}{% + \expandafter\Ifisdimen\expandafter{\reserved@a}{}{% + \expandafter\Ifisskip\expandafter{\reserved@a}{}{% + \expandafter\Ifisnumexpr\expandafter{\reserved@a}{}{% + \expandafter\Ifisdimexpr\expandafter{\reserved@a}{}{% + \expandafter\Ifisinteger\expandafter{\reserved@a}{}{% + \expandafter\Ifiscounter\expandafter{\reserved@a}{% + \def\reserved@b{% + \endgroup\value{#3}=\value{#4}\FamilyKeyStateProcessed + }% + }{% + \def\reserved@b{% + \endgroup + \FamilyUnknownKeyValue{#1}{#2}{#4}{% + integer numbers, counters, lengths, skips, dimens + }% + }% + }% + }% + }% + }% + }% + }% + }% + \reserved@b +} +%</base> +% \end{macrocode} +% \end{command} +% \end{command} +% +% \begin{command}{\FamilyCounterMacroKey} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.15}{2014/12/03}{support for optional default} +% Similar to \cs{FamilyCounterKey}, but it does not use a \LaTeX{} counter to +% store the value but a macro (or command): +% \begin{quote} +% \cs{FamilyCounterMacroKey}\oarg{member}\marg{family}\marg{key}\oarg{default}\marg{macro} +% \end{quote} +% The \meta{value} will be assigned to a counter (\cnt{page}) locally and the +% \meta{macro} is defined using the value of the counter. The \meta{macro} +% is automatically set to \cs{z@} if it was not already defined. If it was +% defined, the user is responsible for that it has to be a number. +% \begin{macro}{\Family@@Counter@@Macro@@Key,\Family@Counter@Macro@Key} +% \changes{v3.15}{2014/12/03}{added} +% \changes{v3.37}{2022/06/28}{existence test fixed} +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyCounterMacroKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar [%] + {\Family@@Counter@@Macro@@Key{#1}{#2}{#3}}% + {\Family@Counter@Macro@Key{#1}{#2}{#3}}% +} +\newcommand*{\Family@@Counter@@Macro@@Key}{} +\def\Family@@Counter@@Macro@@Key#1#2#3[#4]#5{% + \ifdefined#5\else\let#5\z@\fi + \DefineFamilyKey[{#1}]{#2}{#3}[{#4}]{\FamilySetCounterMacro{#2}{#3}{#5}{##1}}% +} +\newcommand*{\Family@Counter@Macro@Key}[4]{% + \ifdefined#4\else\let#4\z@\fi + \DefineFamilyKey[{#1}]{#2}{#3}{\FamilySetCounterMacro{#2}{#3}{#4}{##1}}% +} +% \end{macrocode} +% \end{macro}^^A \Family@@Counter@@Macro@@Key,\Family@Counter@Macro@Key +% \begin{command}{\FamilySetCounterMacro} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.15}{2014/12/17}{\cs{aftergroup} before \cs{FamilyKeyStateProcessed}} +% \changes{v3.18a}{2015/07/06}{fixed usage of \cs{FamilyKeyStateProcessed}} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by +% \cs{kernel@ifnextchar}} +% Similar to \cs{FamilySetCounter} but using a macro (or command) instead of a +% \LaTeX{} counter: +% \begin{quote} +% \cs{FamilySetCounterMacro}\marg{family}\marg{key}\marg{macro}\marg{value} +% \end{quote} +% Note, that the \meta{value} is locally assigned to a counter (\cnt{page}) +% before defining the \meta{macro} using the value of the counter. +% \begin{macrocode} +\newcommand*{\FamilySetCounterMacro}[4]{% + \begingroup + \FamilySetCounter{#1}{#2}{page}{#4}% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \edef\reserved@a{% + \unexpanded{\endgroup\def#3}% + {\the\value{page}}% + \noexpand\FamilyKeyStateProcessed + }% + \else + \def\reserved@a{% + \endgroup + \FamilyUnknownKeyValue{#1}{#2}{#4}{% + integer numbers, counters, lengths, skips, dimens + }% + }% + \fi + \reserved@a +} +%</base> +% \end{macrocode} +% \end{command}^^A \FamilySetCounterMacro +% \end{command}^^A \FamilyCounterMacroKey +% +% \begin{command}{\FamilyLengthKey} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.15}{2014/12/03}{optional default value} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by +% \cs{kernel@ifnextchar}} +% Defining a \meta{key} that sets a \LaTeX{} length to a \meta{value}. +% \begin{quote} +% \cs{FamilyLengthKey}\oarg{member}\marg{family}\marg{key}\oarg{default}\marg{\LaTeX{} length} +% \end{quote} +% \meta{default} and the \meta{value} of the option has to be (almost) any +% kind of value, that can be assigned to a \LaTeX{} length, a \TeX{} dimension +% or a \TeX{} skip. The \meta{\LaTeX{} length} is automatically defined, if it +% was undefined. In this case the initial value is 0. +% \begin{macro}{\Family@@Length@@Key,\Family@Length@Key} +% \changes{v3.15}{2014/12/03}{added} +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyLengthKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar [%] + {\Family@@Length@@Key{#1}{#2}{#3}}% + {\Family@Length@Key{#1}{#2}{#3}}% +} +\newcommand*{\Family@@Length@@Key}{} +\def\Family@@Length@@Key#1#2#3[#4]#5{% + \ifdefined#5\else\newlength{#5}\fi + \DefineFamilyKey[{#1}]{#2}{#3}[{#4}]{\FamilySetLength{#2}{#3}{#5}{##1}}% +} +\newcommand*{\Family@Length@Key}[4]{% + \ifdefined#4\else\newlength{#4}\fi + \DefineFamilyKey[{#1}]{#2}{#3}{\FamilySetLength{#2}{#3}{#4}{##1}}% +} +% \end{macrocode} +% \begin{command}{\FamilySetLength} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.15}{2015/01/02}{\cs{ifglueexpr} added} +% \changes{v3.18a}{2015/07/06}{usage of \cs{FamilyKeyStateProcessed} fixed} +% \changes{v3.20}{2016/04/27}{expansion before testing} +% Set the value of a \meta{key} defined by \cs{FamilyLengthKey}: +% \begin{quote} +% \cs{FamilySetLength}\marg{family}\marg{key}\marg{\LaTeX{} length}\marg{value} +% \end{quote} +% Note: Before assigning the \meta{value} to the \meta{\LaTeX{} length} it is +% fully expanded and tests are done, if the \meta{value} can be used to be +% assigned to a \LaTeX{} length. If this fails a unknown value is reported. If +% the expansion or the assignment fails a \TeX{} error happens. +% \begin{macrocode} +\newcommand*{\FamilySetLength}[4]{% + \begingroup + \protected@edef\reserved@a{#4}% +% \end{macrocode} +% Together with \cs{@defaultsunits} (see below) following code, could be used: +% \begin{macrocode} +%<*neveruse> + \expandafter\Ifiscount\expandafter{\reserved@a}{% + \aftergroup\@firstoftwo + }{% +%</neveruse> +% \end{macrocode} +% But currently we don't use it! +% \begin{macrocode} + \expandafter\Ifisdimen\expandafter{\reserved@a}{% + \aftergroup\@firstoftwo + }{% + \expandafter\Ifisskip\expandafter{\reserved@a}{% + \aftergroup\@firstoftwo + }{% +% \end{macrocode} +% Together with \cs{@defaultsunits} (see below) following code, could be used: +% \begin{macrocode} +%<*neveruse> + \expandafter\Ifisnumexpr\expandafter{\reserved@a}{% + \aftergroup\@firstoftwo + }{% +%</neveruse> +% \end{macrocode} +% But currently we don't use it! +% \begin{macrocode} + \expandafter\Ifisdimexpr\expandafter{\reserved@a}{% + \aftergroup\@firstoftwo + }{% + \expandafter\Ifisglueexpr\expandafter{\reserved@a}{% + \aftergroup\@firstoftwo + }{% + \expandafter\Ifisglue\expandafter{\reserved@a}{% + \aftergroup\@firstoftwo + }{% + \aftergroup\@secondoftwo + }% + }% + }% +%<*neveruse> + }% +%</neveruse> + }% + }% +%<*neveruse> + }% +%</neveruse> + \endgroup +% \end{macrocode} +% \begin{description} +% \item[ToDo:] Maybe something like: +% \begin{macrocode} +%<*neveruse> + {\@defaultunits#3=#4pt\relax\@nnil\FamilyKeyStateProcessed} +%</neveruse> +% \end{macrocode} +% would be nice. But there are reasons I've decided not to use +% this. Unfortunately I cannot remember the reason (and because of this I've +% added the code as \texttt{neveruse}). So the simple assignment is used +% instead: +% \end{description} +% \begin{macrocode} + {#3=#4\FamilyKeyStateProcessed}% + {% + \FamilyUnknownKeyValue{#1}{#2}{#4}{% + length values, +%<*neveruse> + counters, +%</neveruse> + lengths, skips, dimens + }% + }% +} +%</base> +% \end{macrocode} +% \end{command}^^A \FamilySetLength +% \end{macro}^^A \Family@@Leng{\FamilyLengthKey}th@@Key,\Family@Length@Key +% \end{command}^^A FamilyLengthKey +% +% \begin{command}{\FamilyLengthMacroKey} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.15}{2014/12/03}{support for optional default} +% \begin{command}{\FamilySetLengthMacro} +% \changes{v3.12}{2013/11/05}{added} +% \changes{v3.14a}{2014/11/24}{fix: \cs{@tempskipa} instead of \cs{@temskipa}} +% \changes{v3.15}{2014/12/17}{\cs{aftergroup} before +% \cs{FamilyKeyStateProcessed}} +% \changes{v3.15}{2015/01/02}{\cs{ifglueexpr} added} +% \changes{v3.18a}{2015/07/06}{usage of \cs{FamilyKeyStateProcessed} fixed} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by +% \cs{kernel@ifnextchar}} +% \changes{v3.20}{2016/04/27}{using \cs{FamilySetLength}} +% Similar to \cs{FamilyLengthKey}, but it does not use a \LaTeX{} counter to +% store the value but a macro (or command): +% \begin{quote} +% \cs{FamilyLength MacroKey}\oarg{member}\marg{family}\marg{key}\oarg{default}\marg{macro} +% \end{quote} +% The \meta{value} will be assigned to a length (\len{@tempskipa}) locally and +% the \meta{macro} is defined using the value of the length. The \meta{macro} +% is automatically set to \cs{z@} if it was not already defined. If it was +% defined, the user is responsible for that it has to be a valid length. Usage +% of \cs{dimexpr} is recommended for such a definition. +% \begin{macro}{\Family@@Length@@Macro@@Key,\Family@Length@Macro@Key} +% \changes{v3.15}{2014/12/03}{added} +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyLengthMacroKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar [%] + {\Family@@Length@@Macro@@Key{#1}{#2}{#3}}% + {\Family@Length@Macro@Key{#1}{#2}{#3}}% +} +\newcommand*{\Family@@Length@@Macro@@Key}{} +\def\Family@@Length@@Macro@@Key#1#2#3[#4]#5{% + \ifdefined#5\else\let#5\z@\fi + \DefineFamilyKey[{#1}]{#2}{#3}[{#4}]{\FamilySetLengthMacro{#2}{#3}{#5}{##1}}% +} +\newcommand*{\Family@Length@Macro@Key}[4]{% + \ifdefined#4\else\let#4\z@\fi + \DefineFamilyKey[{#1}]{#2}{#3}{\FamilySetLengthMacro{#2}{#3}{#4}{##1}}% +} +\newcommand*{\FamilySetLengthMacro}[4]{% + \begingroup + \FamilySetLength{#1}{#2}{\@tempskipa}{#4}% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \edef\reserved@a{% + \unexpanded{\endgroup\def#3}% + {\the\@tempskipa}% + \noexpand\FamilyKeyStateProcessed + }% + \else + \def\reserved@a{% + \endgroup + \FamilyUnknownKeyValue{#1}{#2}{#4}{% + length values, counters, lengths, skips, dimens + }% + }% + \fi + \reserved@a +} +%</base> +% \end{macrocode} +% \end{macro}^^A \Family@@Length@@Macro@@Key,\Family@Length@Macro@Key +% \end{command}^^A \FamilySetLengthMacro +% \end{command}^^A \FamilyLengthMacroKey +% +% +% \begin{command}{\FamilyUseLengthMacroKey,\FamilySetUseLengthMacro} +% \changes{v3.20}{2016/04/27}{added} +% These are almost the same like \cs{FamilyLengthMacroKey} and +% \cs{FamilySetLengthMacro}. But there is one important difference: Instead of +% setting the \meta{macro} to the value of the temporary length, that has been +% used for a test assignment, the \meta{macro} is defined as \meta{value}. So +% later changes valid for the expansion and value of \meta{value} will indeed +% change the value of \meta{macro}, when it is used. +% \begin{macro}{\Family@@UseLength@@Macro@@Key,\Family@USeLength@Macro@Key} +% \changes{v3.20}{2016/04/27}{added} +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyUseLengthMacroKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar [%] + {\Family@@UseLength@@Macro@@Key{#1}{#2}{#3}}% + {\Family@UseLength@Macro@Key{#1}{#2}{#3}}% +} +\newcommand*{\Family@@UseLength@@Macro@@Key}{} +\def\Family@@UseLength@@Macro@@Key#1#2#3[#4]#5{% + \ifdefined#5\else\let#5\z@\fi + \DefineFamilyKey[{#1}]{#2}{#3}[{#4}]{% + \FamilySetUseLengthMacro{#2}{#3}{#5}{##1}% + }% +} +\newcommand*{\Family@UseLength@Macro@Key}[4]{% + \ifdefined#4\else\let#4\z@\fi + \DefineFamilyKey[{#1}]{#2}{#3}{\FamilySetUseLengthMacro{#2}{#3}{#4}{##1}}% +} +\newcommand*{\FamilySetUseLengthMacro}[4]{% + \begingroup + \FamilySetLength{#1}{#2}{\@tempskipa}{#4}% + \ifx\FamilyKeyState\FamilyKeyStateProcessed + \def\reserved@a{% + \endgroup\def#3{#4}% + \FamilyKeyStateProcessed + }% + \else + \def\reserved@a{% + \endgroup + \FamilyUnknownKeyValue{#1}{#2}{#4}{% + length values, counters, lengths, skips, dimens + }% + }% + \fi + \reserved@a +} +%</base> +% \end{macrocode} +% \end{macro}^^A \Family@@UseLength@@Macro@@Key,\Family@USeLength@Macro@Key +% \end{command}^^A \FamilyUseLengthMacroKey,\FamilySetUseLengthMacro +% +% +% \begin{command}{\FamilyNumericalKey} +% \changes{v3.00}{2008/04/30}{added} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by +% \cs{kernel@ifnextchar}} +% This is a mapping of symbolic values to numerical values: +% \begin{quote} +% \cs{FamilyNumericalKey}\oarg{member}\marg{family}\marg{key}\oarg{default}\marg{macro}\marg{mapping list} +% \end{quote} +% The \meta{mapping list} is: +% \begin{quote} +% \texttt{\marg{symbol$_1$}\marg{value$_1$},\marg{symbol$_2$}\marg{value$_2$}\dots} +% \end{quote} +% There is no need for \meta{value$_n$} and \meta{value$_m$} to be mutual +% exclusive. So several symbols can be mapped to the same value. +% \begin{macro}{\Family@Numerical@Key} +% \changes{v3.00}{2008/05/28}{added} +% \changes{v3.08b}{2011/03/31}{fixed: missing argument to \cs{ifundefined}} +% The internal macro is used to handle the optional \meta{default} (because +% currently we are not using \pkg{xparse}). +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyNumericalKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar [%] + {\Family@Numerical@Key{#1}{#2}{#3}}{\Family@Numerical@Key{#1}{#2}{#3}[]}% +} +\newcommand*{\Family@Numerical@Key}{} +\def\Family@Numerical@Key#1#2#3[#4]#5#6{% + \@ifundefined{#5}{\@namedef{#5}{0}}{}% + \ifx\relax#4\relax + \DefineFamilyKey[{#1}]{#2}{#3}{\FamilySetNumerical{#2}{#3}{#5}{#6}{##1}}% + \else + \DefineFamilyKey[{#1}]{#2}{#3}[{#4}]{% + \FamilySetNumerical{#2}{#3}{#5}{#6}{##1}}% + \fi +} +% \end{macrocode} +% \end{macro} +% \begin{command}{\FamilySetNumerical} +% \changes{v3.11a}{2012/05/28}{call of \cs{FamilyUnknownKeyValue} outside of +% local group} +% \changes{v3.25}{2017/12/04}{handling of completely empty list elements} +% Set the value of \meta{key} defined by \cs{FamilyNumericalKey}: +% \begin{quote} +% \cs{FamilySetNumerical}\marg{family}\marg{key}\marg{macro}\marg{mapping list}\marg{value} +% \end{quote} +% \begin{macrocode} +\newcommand*{\FamilySetNumerical}[5]{% + \begingroup + \edef\@searched{#5}% + \let\reserved@a=\@empty + \let\reserved@b=\@empty + \@tempswafalse + \@for\@valuelist:=#4\do{% + \ifx\@valuelist\@empty\else + \if@tempswa\else + \edef\reserved@c{\expandafter\@firstoftwo\@valuelist}% + \edef\reserved@a{\reserved@a\reserved@b`\reserved@c'}% + \edef\reserved@b{, }% + \ifx\reserved@c\@searched + \@tempswatrue + \edef\reserved@a{\expandafter\@secondoftwo\@valuelist}% + \fi + \fi + \fi + }% + \if@tempswa + \edef\reserved@a{\endgroup + \noexpand\@namedef{#3}{\reserved@a}% + \noexpand\FamilyKeyStateProcessed + }% + \else + \edef\reserved@a{\endgroup + \noexpand\FamilyUnknownKeyValue{#1}{#2}{#5}{\reserved@a}% + }% + \fi + \reserved@a + \let\FamilyElseValues\@empty +} +%</base> +% \end{macrocode} +% \end{command}^^A \FamilySetNumerical +% \end{command}^^A \FamilyNumericalKey +% +% \begin{macro}{\KOMA@ncmdkey} +% \changes{v3.02c}{2009/02/04}{defining the member (if needed)} +% \changes{v3.17}{2015/03/16}{re-implemented with value storage and optional default} +% \begin{macro}{\KOMA@@@ncmdkey,\KOMA@@ncmdkey} +% \changes{v3.17}{2015/03/16}{added} +% Like \cs{FamilyNumericalKey} with two important differences: +% \begin{itemize} +% \item The family is not an argument but always |KOMA|. +% \item The values will in the internal value storage is replaced (on success). +% \end{itemize} +% Important: Don't forget to add the default to the internal value storage, +% e.g., using \cs{KOMA@kav@add}. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@ncmdkey}[2][.\@currname.\@currext]{% + \begingroup\edef\reserved@a{\noexpand\KOMA@@ncmdkey{#1}{#2}}% + \expandafter\endgroup\reserved@a +} +\newcommand*{\KOMA@@ncmdkey}[2]{% + \kernel@ifnextchar [%] + {\KOMA@@@ncmdkey{#1}{#2}}{\KOMA@@@ncmdkey{#1}{#2}[]} +} +\newcommand*{\KOMA@@@ncmdkey}{} +\def\KOMA@@@ncmdkey#1#2[#3]#4#5{% + \@ifundefined{#4}{\@namedef{#4}{0}}{}% + \ifx\relax#3\relax + \KOMA@key[{#1}]{#2}{% + \KOMA@set@ncmdkey{#2}{#4}{#5}{##1}% + \KOMA@kav@replacevalue{#1}{#2}{##1}% + }% + \else + \KOMA@key[{#1}]{#2}[{#3}]{% + \KOMA@set@ncmdkey{#2}{#4}{#5}{##1}% + \KOMA@kav@replacevalue{#1}{#2}{##1}% + }% + \fi +} +%</koma> +% \end{macrocode} +% \begin{macro}{\KOMA@set@ncmdkey} +% The corresponding set command similar to \cs{FamilySetNumerical} but again +% the family is not an argument but always |KOMA|. +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@set@ncmdkey}{\FamilySetNumerical{KOMA}} +%</koma> +% \end{macrocode} +% \end{macro}^^A \KOMA@set@ncmdkey +% \end{macro}^^A \KOMA@@@ncmdkey,\KOMA@@ncmdkey +% \end{macro}^^A \KOMA@ncmdkey +% +% +% \begin{command}{\FamilyStringKey} +% \changes{v3.08}{2010/11/05}{added} +% \changes{v3.08b}{2011/03/31}{\cs{Family@String@Key} and +% \cs{Family@@String@@Key} switched} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by +% \cs{kernel@ifnextchar}} +% Defining a \meta{key} that defines a \meta{macro} to be a \meta{value}. +% \begin{quote} +% \cs{FamilyStringKey}\oarg{member}\marg{family}\marg{key}\oarg{default}\marg{macro} +% \end{quote} +% \meta{default} and the \meta{value} of the option should be a string (but +% currently every value is accepted). The definition is done using +% \cs{def}. So it doesn't matter whether the \meta{macro} is already defined. +% \begin{macro}{\Family@String@Key,\Family@@String@@Key} +% \changes{v3.08}{2010/11/05}{added} +% \changes{v3.37}{2022/06/28}{state signaling fixed} +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyStringKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar [%] + {\Family@@String@@Key{#1}{#2}{#3}}{\Family@String@Key{#1}{#2}{#3}}% +} +\newcommand*{\Family@@String@@Key}{} +\long\def\Family@@String@@Key#1#2#3[#4]#5{% + \DefineFamilyKey[{#1}]{#2}{#3}[{#4}]{\def#5{##1}\FamilyKeyStateProcessed}% +} +\newcommand{\Family@String@Key}[4]{% + \DefineFamilyKey[{#1}]{#2}{#3}{\def#4{##1}\FamilyKeyStateProcessed}% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \Family@String@Key,\Family@@String@@Key +% \end{command}^^A \FamilyStringKey +% +% +% \begin{command}{\FamilyCSKey} +% \changes{v3.25}{2017/12/08}{added} +% This is similar to \cs{FamilyStringKey} but instead of a \meta{macro} a +% \meta{command sequence} is used: +% \begin{quote} +% \cs{FamilyCSKey}\oarg{member}\marg{family}\marg{key}\oarg{default}\marg{command sequence} +% \end{quote} +% Because of this, \cs{@namedef} instead of \cs{def} is used to define the +% corresponding \cs{\meta{command sequence}}. +% \begin{macro}{\Family@CS@Key} +% \changes{v3.25}{2017/12/08}{added} +% \begin{macro}{\Family@@CS@@Key} +% \changes{v3.25}{2017/12/08}{added} +% \changes{v3.26}{2018/11/06}{fix: don't overwrite \cs{Family@@String@@Key}} +% \changes{v3.37}{2022/06/28}{state signaling fixed} +% \begin{macrocode} +%<*base> +\newcommand*{\FamilyCSKey}[3][.\@currname.\@currext]{% + \kernel@ifnextchar [%] + {\Family@@CS@@Key{#1}{#2}{#3}}{\Family@CS@Key{#1}{#2}{#3}}% +} +\newcommand*{\Family@@CS@@Key}{} +\long\def\Family@@CS@@Key#1#2#3[#4]#5{% + \DefineFamilyKey[{#1}]{#2}{#3}[{#4}]{\@namedef{#5}{##1}\FamilyKeyStateProcessed}% +} +\newcommand{\Family@CS@Key}[4]{% + \DefineFamilyKey[{#1}]{#2}{#3}{\@namedef{#4}{##1}\FamilyKeyStateProcessed}% +} +%</base> +% \end{macrocode} +% \end{macro}^^A \Family@@CS@@Key +% \end{macro}^^A \Family@CS@Key +% \end{command}^^A \FamilyCSKey +% +% +% \begin{macro}{\KOMA@DeclareDeprecatedOption} +% \changes{v3.01a}{2008/11/20}{added} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by +% \cs{kernel@ifnextchar}} +% Used to define a deprecated \meta{classic option} by an up-to-date +% \meta{\pkg*{keyval} option}. +% \begin{quote} +% \cs{KOMA@DeclareDeprecatedOption}\oarg{package name}\marg{classic +% option}\marg{\pkg*{keyval} option} +% \end{quote} +% If the \meta{package name} is omitted, \cs{KOMAClassName} is used to report +% a class warning instead of a package warning. +% \begin{macro}{\KOMA@@DeclareDeprecatedOption,\KOMA@@@DeclareDeprecatedOption} +% \changes{v3.01a}{2008/11/20}{added} +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@DeclareDeprecatedOption}{% + \kernel@ifnextchar [%] + {\KOMA@@DeclareDeprecatedOption}% + {\KOMA@@@DeclareDeprecatedOption{\ClassWarningNoLine{\KOMAClassName}}}% +} +\newcommand*{\KOMA@@DeclareDeprecatedOption}[1][]{% + \KOMA@@@DeclareDeprecatedOption{\PackageWarningNoLine{#1}}% +} +\newcommand*{\KOMA@@@DeclareDeprecatedOption}[3]{% + \DeclareOption{#2}{\KOMA@UseDeprecatedOption{#1}{#2}{#3}}% +} +% \end{macrocode} +% \begin{macro}{\KOMA@UseDeprecatedOption} +% \changes{v3.01a}{2008/11/20}{added} +% \changes{v3.12}{2013/03/04}{test to use \opt{version\quotechar=first}} +% \changes{v3.12a}{2014/01/22}{test fixed} +% \changes{v3.22}{2016/07/29}{added several \cs{detokenize}} +% \changes{v3.37}{2022/06/21}{message text ``obsolete'' replaced by +% ``deprecated''} +% One more helper: +% \begin{quote} +% \cs{KOMA@UseDeprecatedOption}\marg{warning command}\marg{classic +% option}\marg{\pkg*{keyval} option} +% \end{quote} +% Note: \meta{warning command} should either be +% |\ClassWarningNoLine{\KOMAClassName}| or +% \cs{PackageWarningNoLine}\marg{package name}. But you could also use +% \cs{ClassInfoNoLine} or \cs{PackageInfoNoLine}. +% \begin{macrocode} +\newcommand*{\KOMA@UseDeprecatedOption}[3]{% + \begingroup + \scr@ifundefinedorrelax{KV@KOMA.\@currname.\@currext @version}{% + \edef\reserved@a{\noexpand\endgroup + \noexpand#1{% + You've used deprecated option `\detokenize{#2}'.\noexpand\MessageBreak + Usage of this option is deprecated.\noexpand\MessageBreak + You should simply replace `\detokenize{#2}'\noexpand\MessageBreak + by `\detokenize{#3}'% + }% + \noexpand\KOMAExecuteOptions{#3}% + \noexpand\def\noexpand\CurrentOption{\CurrentOption}% + }% + }{% + \edef\reserved@a{\noexpand\endgroup + \noexpand#1{% + You've used deprecated option `\detokenize{#2}'.\noexpand\MessageBreak + Usage of this option indicates an old document\noexpand\MessageBreak + and changes compatibility level using\noexpand\MessageBreak + `\detokenize{#3},version=first,\noexpand\MessageBreak + enabledeprecatedfontcommands' that may result\noexpand\MessageBreak + in further warnings.\noexpand\MessageBreak + If you don't want this, you should simply\noexpand\MessageBreak + replace option `\detokenize{#2}' by `\detokenize{#3}'% + }% + \noexpand\KOMAExecuteOptions{% + #3,version=first}% + \noexpand\ExecuteOptions{enabledeprecatedfontcommands}% + \noexpand\def\noexpand\CurrentOption{\CurrentOption}% + }% + }% + \reserved@a +} +%</koma> +% \end{macrocode} +% \end{macro}^^A \KOMA@UseDeprecatedOption +% \end{macro}^^A \KOMA@@DeclareDeprecatedOption,\KOMA@@@DeclareDeprecatedOption +% \end{macro}^^A \KOMA@DeclareDeprecatedOption +% +% +% \begin{macro}{\KOMA@DeclareStandardOption} +% \changes{v3.01a}{2008/11/21}{added} +% \changes{v3.20}{2016/04/12}{\cs{@ifnextchar} replaced by +% \cs{kernel@ifnextchar}} +% This is similar to \cs{KOMA@DeclareDeprecatedOption} but is used for +% standard options, which means options known by the standard classes. +% \begin{quote} +% \cs{KOMA@DeclareStandardOption}\oarg{package name}\marg{classic +% option}\marg{\pkg*{keyval} option} +% \end{quote} +% For compatibility these options are not reported as deprecated, but an info +% is added to the \file{log} file about the usage and how it could be replaced +% by a \pkg*{keyval} option. +% \begin{macro}{\KOMA@@DeclareStandardOption,\KOMA@@@DeclareStandardOption, +% \KOMA@UseStandardOption} +% \changes{v3.01a}{2008/11/21}{added} +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@DeclareStandardOption}{% + \kernel@ifnextchar [%] + {\KOMA@@DeclareStandardOption}% + {\KOMA@@@DeclareStandardOption{\ClassInfoNoLine{\KOMAClassName}}}% +} +\newcommand*{\KOMA@@DeclareStandardOption}[1][]{% + \KOMA@@@DeclareStandardOption{\PackageInfoNoLine{#1}}% +} +\newcommand*{\KOMA@@@DeclareStandardOption}[3]{% + \DeclareOption{#2}{\KOMA@UseStandardOption{#1}{#2}{#3}}% +} +\newcommand*{\KOMA@UseStandardOption}[3]{% + \begingroup + \edef\reserved@a{\noexpand\endgroup + \noexpand#1{% + You've used standard option `#2'.\noexpand\MessageBreak + This is correct!\noexpand\MessageBreak + Internally I'm using `#3'.\noexpand\MessageBreak + If you'd like to set the option with \string\KOMAoptions,% + \noexpand\MessageBreak + you'd have to use `#3' there\noexpand\MessageBreak + instead of `#2', too% + }% + \noexpand\KOMAExecuteOptions{#3}% + \noexpand\def\noexpand\CurrentOption{\CurrentOption}% + }% + \reserved@a +} +%</koma> +% \end{macrocode} +% \begin{macro}{\scr@sr@co} +% \changes{v2.96}{2006/08/20}{added} +% \changes{v3.12a}{2014/01/22}{removed} +% \end{macro}^^A \scr@sr@co +% \end{macro}^^A \KOMA@@@DeclareStandardOption … \KOMA@UseStandardOption +% \end{macro}^^A \KOMA@DeclareStandardOption +% +% +% \begin{macro}{\KOMA@DeclareObsoleteOption} +% \changes{v2.96}{2006/08/20}{\cs{CurrentOption} protected} +% \changes{v3.12}{2013/03/04}{removed} +% \begin{macro}{\KOMA@@DeclareObsoleteOption,\KOMA@@@DeclareObsoleteOption, +% \KOMA@iv@DeclareObsoleteOption,\KOMA@UseObsoleteOption} +% \changes{v2.98c}{2008/02/18}{added} +% \changes{v3.12}{2013/03/04}{removed} +% \end{macro}^^A \KOMA@@DeclareObsoleteOption … \KOMA@UseObsoleteOption +% \end{macro}^^A \KOMA@DeclareObsoleteOption +% +% +% \begin{macro}{\KOMA@newobsoletecommand,\KOMA@newdeprecatedcommand} +% \changes{v3.12}{2013/03/04}{\cs{KOMA@newobsoletecommand} renamed to +% \cs{KOMA@newdeprecatedcommand}} +% Defines a deprecated command or \meta{macro}, represented by a +% \meta{\pkg*{keyval} option}: +% \begin{quote} +% \cs{KOMA@newdeprecatedcommand}\oarg{warning +% command}\marg{macro}\marg{\pkg*{keyval} option} +% \end{quote} +% Note: This can be used only for macros and commands, that behave as a +% selector. Macros or commands with arguments are not supported. +% \begin{macro}{\KOMA@UseDeprecatedCommand,\KOMA@UseDeprecatedCommand} +% \changes{v2.97c}{2007/04/19}{added} +% \changes{v3.12}{2013/03/04}{\cs{KOMA@UseObsoleteCommand} renamed to +% \cs{KOMA@UseDeprecatedCommand}} +% \begin{macrocode} +%<*koma> +\newcommand*{\KOMA@newdeprecatedcommand}[3][\@gobbletwo]{% + \newcommand*{#2}{\KOMA@UseDeprecatedCommand{#1}{\string#2}{#3}}% +} +\newcommand*{\KOMA@UseDeprecatedCommand}[3]{% + #1{% + scrkbase% + }{% + You've used deprecated command `#2'.\MessageBreak + \protect\KOMAoptions{#3} will be used instead.\MessageBreak + You should also replace `#2' by `\protect\KOMAoptions{#3}'% + }% + \KOMAoptions{#3}% +} +%</koma> +% \end{macrocode} +% \end{macro}^^A \KOMA@UseDeprecatedCommand +% \end{macro}^^A \KOMA@newdeprecatedcommand +% +% +% \subsection{Do hook mechanism} +% \label{sec:dohook} +% +% \changes{v3.27}{2019/02/02}{Do hook mechanism added} +% From \KOMAScript~v3.27 there is a new general hook mechanism called ``do +% hook mechanism''. This mechanism is mentioned to provide extended hooks for +% package authors. All hooks newly implemented in \KOMAScript{} \emph{should} +% use this new mechanism. +% +% +% \begin{command}{\ForDoHook} +% \changes{v3.27}{2019/02/05}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% \changes{v3.30}{2020/03/07}{\cs{loop}\dots\cs{repeat} inside group} +% \changes{v3.30}{2020/03/07}{using \cs{rloop} instead of \cs{loop}} +% Arguments: +% \begin{description} +% \item[\meta{specificator}:] +% \meta{string} or \meta{string}\texttt{/}\meta{specificator} +% \item[\meta{code}:] \LaTeX{} code +% \end{description} +% Executes \meta{code} for earch level of a do-hook. This is a helper command +% normally not interesting for users or package authors. However, I define it +% in the user context to be consistent with the other do-hook commands. Note, +% there will be two arguments appended to the \meta{code}. The first one is +% the name of the hook, the second one the hook argument. +% See \cs{ExecuteDoHook} as an example. +% \begin{macrocode} +%<*base> +\newcommand*{\ForDoHook}[2]{% + \Ifstr{#1}{}{% + \PackageError{scrbase}{empty do-hook specificator}{% + You've tried to use an empty do-hook specificator,\MessageBreak + but do-hook specificators must not be empty.% + }% + }{% + \begingroup + \def\scr@hookrun{\endgroup}% + \let\scr@hookname\relax + \edef\scr@hookargument{#1}% + \rloop + \scr@hooksplit@specificator\scr@hookname\scr@hookargument + \scr@hookargument + \edef\scr@hookrun{% + \unexpanded\expandafter{\scr@hookrun}% + \unexpanded{#2}{\scr@hookname}{\scr@hookargument}% + }% + \ifx\scr@hookargument\@empty\else + \repeat + \scr@hookrun + }% +} +% \end{macrocode} +% \begin{command}{\SplitDoHook} +% \changes{v3.27}{2019/02/04}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% Arguments: +% \begin{description} +% \item[\meta{specificator}:] +% \meta{string} or \meta{string}\texttt{/}\meta{specificator} +% \item[\meta{prefix command}:] \LaTeX{} macro +% \item[\meta{postfix command}:] \LaTeX{} macro +% \end{description} +% Splits of the \emph{last} element of the \meta{specificator}. The +% \meta{postfix command} is defined to be that last element, the \meta{prefix +% command} is defined to be the rest. +% \begin{macrocode} +\newcommand*{\SplitDoHook}[3]{% + \Ifstr{#1}{}{% + \PackageWarning{scrbase}{empty do-hook specificator}% + \let#2\@empty\let#3\@empty + }{% + \let#2\relax + \edef\reserved@a{% + \unexpanded{\scr@hooksplit@specificator{#2}{#3}}{#1}% + }\reserved@a + }% +} +% \end{macrocode} +% \begin{macro}{\scr@hooksplit@specificator} +% \changes{v3.27}{2019/02/02}{added} +% Split of the first string of the specificator argument, append it to +% \cs{scr@hookname} and store the rest in \cs{scr@hookargument}. The argument +% must not be empty! +% \begin{macro}{\scr@@hooksplit@specificator} +% \changes{v3.27}{2019/02/02}{added} +% \begin{macrocode} +\newcommand*{\scr@hooksplit@specificator}[3]{% + \expandafter\scr@@hooksplit@specificator\expandafter#1\expandafter#2#3/\@nil +} +\newcommand*{\scr@@hooksplit@specificator}{} +\def\scr@@hooksplit@specificator#1#2#3/#4\@nil{% + \scr@ifundefinedorrelax{scr@hookname}{\def#1{#3}}{% + \edef#1{#1/#3}% + }% + \def#2{#4}% + \ifx#2\@empty\else \scr@@hookargument#2#4\@nil\fi +} +\newcommand*{\scr@@hookargument}{} +\def\scr@@hookargument#1#2/\@nil{\def#1{#2}}% +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{command} +% \end{command} +% +% \begin{command}{\ExecuteDoHook} +% \changes{v3.27}{2019/02/02}{added} +% Arguments: +% \begin{description} +% \item[\meta{specificator}:] +% \meta{string} or \meta{string}\texttt{/}\meta{specificator} +% \end{description} +% Each string of the \meta{specificator} defines a hook subgroup. The +% execution is done in a loop, first all hook elements of the first +% \meta{string} of the \meta{specificator} are executed with the rest of the +% \meta{specificator} as an argument. Then the hook elements of the +% composition of the first and the second \meta{string} are executed again +% with the rest of the \meta{specificator} as an agument and so on until the +% hook elements of the whole \meta{specificator} has been executed with an +% empty argument. So every hook element has to expect an argument that is +% itself a \meta{specificator}. At each loop level the one-time hooks +% are executed after the permanent hooks. +% \begin{macrocode} +\newcommand*{\ExecuteDoHook}[1]{% + \@ifundefined{scr@execute@dohook}{% + \def\scr@execute@dohook##1##2{% + \def\scr@hook@do####1{####1{##2}}% + \@nameuse{scr@dohook@##1}% + \@nameuse{scr@otdohook@##1}% + \expandafter\global\expandafter\let + \csname scr@otdohook@##1\endcsname\@empty + \let\scr@hook@do\relax + }% + \ForDoHook{#1}{\scr@execute@dohook}% + \let\scr@execute@dohook\relax + }{% + \PackageWarning{scrbase}{cascaded do-hook detected.\MessageBreak + It seems, that the do-hook `\detokenize{#1}'\MessageBreak + is be executed, while another do-hook is active.\MessageBreak + This is not allowed and therefore ignored% + }% + }% +} +% \end{macrocode} +% \end{command} +% +% \begin{command}{\AddtoDoHook} +% \changes{v3.27}{2019/02/02}{added} +% Arguments: +% \begin{description} +% \item[\meta{specificator}:] +% \meta{string} or \meta{string}\texttt{/}\meta{specificator} +% \item[\meta{element}:] +% a \LaTeX command, that expects exactly one argument. +% \end{description} +% For the \meta{specificator} see \cs{ExecuteDoHook}. Here you can add an +% \meta{element} to a hook defined by the \meta{specificator}. Adding a hook +% is local to the current group. +% \begin{macrocode} +\newcommand*{\AddtoDoHook}[2]{% + \Ifstr{#1}{}{% + \PackageError{scrbase}{empty hook specificator}{% + As hook specificators can never be empty, the first argument\MessageBreak + of \string\AddtoDoHook\space must expand to an not empty string.% + }% + }{% + \scr@ifundefinedorrelax{scr@dohook@#1}{\@namedef{scr@dohook@#1}{}}{}% + \expandafter\l@addto@macro\csname scr@dohook@#1\endcsname{% + \scr@hook@do{#2}% + }% + }% +} +% \end{macrocode} +% \end{command} +% +% \begin{command}{\AddtoOneTimeDoHook} +% \changes{v3.27}{2019/02/02}{added} +% \changes{v3.28}{2019/11/18}{\cs{ifstr} renamed to \cs{Ifstr}} +% Arguments: +% \begin{description} +% \item[\meta{specificator}:] +% \meta{string} or \meta{string}\texttt{/}\meta{specificator} +% \item[\meta{element}:] +% a \LaTeX command, that expects exactly one argument. +% \end{description} +% This is almost the same as \cs{AddtoDoHook} but a hook added by this command +% is executed only once. +% \begin{macrocode} +\newcommand*{\AddtoOneTimeDoHook}[2]{% + \Ifstr{#1}{}{% + \PackageError{scrbase}{empty hook specificator}{% + As hook specificators can never be empty, the first argument\MessageBreak + of \string\AddtoDoHook\space must expand to an not empty string.% + }% + }{% + \scr@ifundefinedorrelax{scr@otdohook@#1}{\@namedef{scr@otdohook@#1}{}}{}% + \expandafter\l@addto@macro\csname scr@otdohook@#1\endcsname{% + \scr@hook@do{#2}% + }% + }% +} +%</base> +%</body> +% \end{macrocode} +% \end{command} +% +% +% \Finale +% \PrintChanges +% +\endinput +% Local Variables: +% mode: doctex +% ispell-local-dictionary: "en_US" +% eval: (flyspell-mode 1) +% TeX-master: t +% TeX-engine: luatex-dev +% eval: (setcar (or (cl-member "Index" (setq-local TeX-command-list (copy-alist TeX-command-list)) :key #'car :test #'string-equal) (setq-local TeX-command-list (cons nil TeX-command-list))) '("Index" "mkindex %s" TeX-run-index nil t :help "makeindex for dtx")) +% End: |