% \iffalse meta-comment
% ======================================================================
% scrkernel-basics.dtx
% Copyright (c) Markus Kohm, 2002-2025
%
% 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 4146 2025-05-14 12:41:49Z kohm $
%<prepare>%%%            (run: prepare)
%<option>%%%            (run: option)
%<body>%%%            (run: body)
%<load>%%%            (run: load)
%<package&prepare>\NeedsTeXFormat{LaTeX2e}[2022/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: 2025-05-14 14:41:49 +0200 (Mi, 14. Mai 2025) $
  \def\filerevision$#1: #2 ${\def\filerevision{r#2}}
  \filerevision$Revision: 4146 $
  \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}
% \changes{v3.40}{2023/04/17}{guide names changed}
%
% \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-de.pdf} or the English
% \file{scrguide-en.pdf}.
% 
%
% \subsection{Features not yet in the user manuals}
%
% 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}
%
% \changes{v3.44}{2025/05/13}{at least \LaTeX{} 2022-06-01 required}
%    \begin{macrocode}
%<*koma>
\IfLTXAtLeastTF{2022/06/01}{}{%
  \@ifundefined{KOMAClassName}
    {\PackageError{scrkbase}}
    {\ClassError{\KOMAClassName}}
    {%
      LaTeX kernel too old!\MessageBreak
      This version of KOMA-Script requires at least\MessageBreak
      LaTeX 2022-06-01.\MessageBreak
      You need to either use an older version of\MessageBreak
      KOMA-Script or update your LaTeX kernel.\MessageBreak
      Sorry, but this error is fatal.\MessageBreak
      You cannot continue. Aborting LaTeX run%
    }
    {No further help available!}%
    \batchmode \immediate\read -1 to \@tempa
}
%</koma>
%    \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}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% \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}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% 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}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% 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}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% 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}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% 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}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% 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}}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% 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}
% \changes{v3.39}{2022/11/11}{bug report address changed}
% 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 
    <https://sf.net/p/koma-script/tickets/> (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
%    \end{macrocode}
% \changes{v3.41}{2023/04/26}{only one step expansion while classic option
% test}
% Because we are using the raw option list, we do only a one step expansion of
% \cs{CurrentOption} here, because a full expansion could break.
%    \begin{macrocode}
          \@ifundefined{ds@\expandafter\detokenize\expandafter{\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
%    \end{macrocode}
% \changes{v3.41}{2023/04/26}{only one step expansion while classic option
% test}
% Because we are using the raw option list, we do only a one step expansion of
% \cs{CurrentOption} here, because a full expansion could break.
%    \begin{macrocode}
    \@ifundefined{ds@\expandafter\detokenize\expandafter{\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
%    \end{macrocode}
% \changes{v3.41}{2023/04/26}{only one step expansion while classic option
% test}
% Because we are using the raw option list, we do only a one step expansion of
% \cs{CurrentOption} here, because a full expansion could break.
%    \begin{macrocode}
    \@ifundefined{ds@\expandafter\detokenize\expandafter{\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}.
% \changes{v3.42}{2023/07/14}{\cs{edef} replaced by \cs{protected@edef}}
%    \begin{macrocode}
  \let\ds@\@empty
  \protected@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}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% \changes{v3.99}{2022/11/16}{do not handle deprecated initial dot}
% 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]{%
%<*!v4>
  \Ifstrstart{#1}{.}{%
    \PackageWarning{scrkbase}{Deprecated initial dot of member
      argument\MessageBreak
      of \string\KOMAExecuteOptions\space detected%
    }%
    \expandafter\FamilyExecuteOptions[#1]%
  }{%
%</!v4>
    \FamilyExecuteOptions[.#1]%
%<!v4>  }%
  {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}
% \changes{v3.39}{2022/11/11}{initial dot removed from member argument of
%   \cs{KOMA@kac@defall}}
% 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}
% \changes{v3.39}{2022/11/11}{initial dot added automatically}
% 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}}
% \changes{v3.99}{2022/11/16}{not with \KOMAScript~4}
% 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&!v4>
\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&!v4>
%    \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}}
% \changes{v3.99}{2022/11/16}{not with \KOMAScript~4}
% 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&!v4>
\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&!v4>
%    \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:
