% \iffalse meta-comment % % File: expkv-opt.dtx Copyright (C) 2020-2023 Jonathan P. Spratte % % This work may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this license or % (at your option) any later version. The latest version of this license is in % the file: % % http://www.latex-project.org/lppl.txt % % ------------------------------------------------------------------------------ % %<*driver>^^A>>= \def\expkvDocNoGenerate{} \input expkv-bundle.ins \generate{\file{expkv-opt.sty}{\from{expkv-opt.dtx}{pkg}}} \endbatchfile %^^A=<< % \fi % % \section{\expkvo} % % \gobbledocstriptag %<*pkg> % % First we check whether the \LaTeXe\ kernel supports raw options. If it doesn't % we check whether a specific version was requested, and if that's not the case % we manually run |\pkgcls@parse@date@arg| with the last version that supported % non-raw options. % \begin{macrocode} \IfFormatAtLeastTF{2021/05/01} {} {% \ifx\pkgcls@targetlabel\@empty \ifnum\requestedLaTeXdate=\pkgcls@targetdate \pkgcls@parse@date@arg{=v0.1}% \fi \fi } % \end{macrocode} % Then we tell \LaTeXe\ where to find which release so that the package rollback % code of \LaTeXe\ can do its thing. % \begin{macrocode} \DeclareRelease{v0.1}{2020/10/10}{expkv-opt-2020-10-10.sty} \DeclareCurrentRelease{v0.2}{2021/04/04} % \end{macrocode} % % Start the package with the typical \LaTeX\ standards. % % \begin{macro}{\ekvoVersion,\ekvoDate} % Store the package's version and date in two macros. % \begin{macrocode} \newcommand*\ekvoVersion{1.0} \newcommand*\ekvoDate{2023-01-23} % \end{macrocode} % \end{macro} % And we report who we are and what we need. % \begin{macrocode} \ProvidesPackage{expkv-opt} [% \ekvoDate\space v\ekvoVersion\space parse class and package options with expkv% ] \RequirePackage{expkv} % \end{macrocode} % % % \subsection{Loop} % % \begin{macro}[internal] % {\ekvo@CurrentOption@loop,\ekvo@CurrentOption@loop@,\ekvo@end@loop} % We'll need some loop which can iterate over a comma separated list. The loop % is very basic and only works for commas of category~12. First we insert the % delimiters for the actual loop. The |\ekv@set@other| is necessary to get a % functional |\ekvmorekv| in this loop. % \begin{macrocode} \protected\long\def\ekvo@CurrentOption@loop#1#2% {% \ekvo@CurrentOption@loop@#2\ekv@set@other\ekv@mark#1,\ekv@stop,\ekvo@tail } % \end{macrocode} % The actual loop checks whether the final element has been read and if so % ends the loop. Else blank elements are ignored, |\CurrentOption| is set and % the macro which parses the list elements called. Then call the next % iteration. % \begin{macrocode} \long\def\ekvo@CurrentOption@loop@#1\ekv@set@other#2,% {% \ekv@gobble@from@mark@to@stop#2\ekvo@end@loop\ekv@stop \ekv@ifblank{#2}% {}% {% \edef\CurrentOption{\unexpanded\expandafter{\ekv@gobble@mark#2}}% #1{#2}% }% \ekvo@CurrentOption@loop@#1\ekv@set@other\ekv@mark } \long\def\ekvo@end@loop#1\ekvo@tail{} % \end{macrocode} % \end{macro} % % % \subsection{Tests} % % \begin{macro}[internal]{\ekvo@ifx@TF,\ekvo@ifx@T,\ekvo@ifx@F} % We'll need branching |\ifx| tests so that user input containing unbalanced % \TeX\ ifs doesn't break (at least not because of us, everything else is the % fault of \LaTeXe). % \begin{macrocode} \def\ekvo@ifx@TF#1#2{\ifx#1#2\ekv@fi@firstoftwo\fi\@secondoftwo} \def\ekvo@ifx@T#1#2{\ifx#1#2\ekv@fi@firstofone\fi\@gobble} \def\ekvo@ifx@F#1#2{\ifx#1#2\ekv@fi@gobble\fi\@firstofone} % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\ekvo@do@with@set,\ekvo@name,\ekvo@setname} % This test checks whether the \set\ is defined. If it is we store it in % |\ekvo@setname| and set |\ekvo@name| to a short cut to get the \key's % callback name. Next we execute the code in |#2|, if the \set\ isn't defined % |#2| is gobbled. % \begin{macrocode} \protected\def\ekvo@do@with@set#1#2% {% \ekvifdefinedset{#1}% {% \expandafter \let\expandafter\ekvo@name\csname\ekv@undefined@set{#1}\endcsname \def\ekvo@setname{#1}% #2% }% {\ekvo@err@undefined@set{#1}}% } % \end{macrocode} % \end{macro} % % % \subsection{Key handlers} % % \expkvo\ uses handlers specifying what happens if a parsed \key\ is defined or % undefined. % % \begin{macro}[internal] % {\ekvo@handle@undefined@k@pkg,\ekvo@handle@undefined@kv@pkg} % The case for undefined keys in a local list of a package is easy, just throw % appropriate errors. % \begin{macrocode} \protected\long\def\ekvo@handle@undefined@k@pkg#1% {% \ekv@ifdefined{\ekvo@name{#1}}% {\ekvo@err@value@required{#1}}% {\ekvo@err@undefined@key{#1}}% } \def\ekvo@handle@undefined@kv@pkg#1#2% {% \ekv@ifdefined{\ekvo@name{#1}N}% {\ekvo@err@value@forbidden{#1}}% {\ekvo@err@undefined@key{#1}}% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % { % \ekvo@addto@unused@one,\ekvo@addto@unused@two, % \ekvo@rmfrom@unused@one,\ekvo@rmfrom@unused@two % } % These macros will add or remove the |\CurrentOption| to or from the list of % unused global options. Since |\ekvo@do@unusedoptionlist| will have some % overhead before calling the list changing macro in filtering the current % option, we use an optimization here in that we check whether the list is % empty before calling the |rmfrom| function. % \begin{macrocode} \long\def\ekvo@addto@unused@one#1{\ekvo@do@unusedoptionlist\ekvo@addnewto@list} \long\def\ekvo@addto@unused@two#1#2{\ekvo@do@unusedoptionlist\ekvo@addnewto@list} \long\def\ekvo@rmfrom@unused@one#1% {% \ekvo@ifx@F\@unusedoptionlist\@empty {\ekvo@do@unusedoptionlist\ekvo@rmfrom@list}% } \long\def\ekvo@rmfrom@unused@two#1#2% {% \ekvo@ifx@F\@unusedoptionlist\@empty {\ekvo@do@unusedoptionlist\ekvo@rmfrom@list}% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % { % \ekvo@do@unusedoptionlist, % \ekvo@prepare@unusedoption, % \ekvo@prepare@unusedoption@a, % \ekvo@prepare@unusedoption@b, % \ekvo@prepare@unusedoption@c % } % The way the new \LaTeXe\ kernel handles the unused option list changed. Now % not the entire |\CurrentOption| is listed, but just everything up to the % first equals sign, and spaces got zapped, doesn't matter whether the raw % option list gets used or not. So we have to zap spaces and remove everything % from the first equals sign onwards. The code used here will fail if the % current option contains an |\ekv@mark| or |\ekv@stop| before the first % equals sign (this seems rather unlikely). % \begin{macrocode} \protected\def\ekvo@do@unusedoptionlist#1% {% \let\ekvo@unpreparedCurrentOption\CurrentOption \edef\CurrentOption {\expandafter\ekvo@prepare@unusedoption\CurrentOption=\ekv@mark}% #1\@unusedoptionlist \let\CurrentOption\ekvo@unpreparedCurrentOption } \def\ekvo@prepare@unusedoption{\ekvo@prepare@unusedoption@a\@empty} \def\ekvo@prepare@unusedoption@a#1% {% \long\def\ekvo@prepare@unusedoption@a##1=##2\ekv@mark {% \ekvo@prepare@unusedoption@b##1\ekv@stop \ekv@mark\ekvo@prepare@unusedoption@b #1\ekv@mark\ekvo@prepare@unusedoption@c }% } \ekvo@prepare@unusedoption@a{ } \long\def\ekvo@prepare@unusedoption@b#1 #2\ekv@mark#3{#3#1#2\ekv@mark#3} \long\def\ekvo@prepare@unusedoption@c #1\ekv@stop \ekv@mark\ekvo@prepare@unusedoption@b\ekv@mark\ekvo@prepare@unusedoption@c {\unexpanded\expandafter{#1}} % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % { % \ekvo@set@handlers@local,\ekvo@set@handlers@global, % \ekvo@set@handlers@list % } % These macros are boring. They just set up the handlers to respect the rules % documented earlier. % \begin{macrocode} \protected\def\ekvo@set@handlers@local {% \ekvo@if@need@handlers {% \ifx\@currext\@clsextension \ifx\@classoptionslist\relax \let\ekvo@handle@undefined@k\@gobble \let\ekvo@handle@undefined@kv\@gobbletwo \else \expandafter \ifx \csname @raw@opt@\@currname.\@currext\endcsname \@raw@classoptionslist \let\ekvo@handle@undefined@k\ekvo@addto@unused@one \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two \unless\ifx\@unusedoptionlist\@empty \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two \fi \else \let\ekvo@handle@undefined@k\@gobble \let\ekvo@handle@undefined@kv\@gobbletwo \fi \fi \else \let\ekvo@handle@undefined@k\ekvo@handle@undefined@k@pkg \let\ekvo@handle@undefined@kv\ekvo@handle@undefined@kv@pkg \fi }% } \protected\def\ekvo@set@handlers@global {% \unless\ifx\@unusedoptionlist\@empty \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two \fi \ekvo@if@need@handlers {% \let\ekvo@handle@undefined@k\@gobble \let\ekvo@handle@undefined@kv\@gobbletwo }% } \protected\def\ekvo@set@handlers@list {% \ekvo@if@need@handlers {% \let\ekvo@handle@undefined@k\@gobble \let\ekvo@handle@undefined@kv\@gobbletwo }% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\ekvo@if@need@handlers,\ekvo@dont@need@handlers} % If the user specifies handlers this macro will be let to % |\ekvo@dont@need@handlers|, which will act like |\@gobble| and also let it % to |\@firstofone| afterwards. % \begin{macrocode} \let\ekvo@if@need@handlers\@firstofone \protected\long\def\ekvo@dont@need@handlers#1% {% \let\ekvo@if@need@handlers\@firstofone }% % \end{macrocode} % \end{macro} % % We have to set the default for the handlers of defined keys, because they % don't necessarily get defined before a list is parsed. % \begin{macrocode} \let\ekvo@handle@defined@k\@gobble \let\ekvo@handle@defined@kv\@gobbletwo % \end{macrocode} % % % \subsection{Processing list elements} % % \begin{macro}[internal]{\ekvo@process@common} % All the key processing frontend macros use the same basic structure. |#1| % will be a simple test, deciding whether the list will really be parsed or % not, |#3| will be the \set, and |#2| will be the individual code of the % frontend macro which should be executed if both the test in |#1| is true and % the \set\ is defined. % \begin{macrocode} \protected\def\ekvo@process@common#1#2#3% {% #1{\ekvo@do@with@set{#3}{#2}}% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\ekvo@process@list} % This macro only expands the list holding macro and forwards it to the % loop macro. % \begin{macrocode} \protected\def\ekvo@process@list#1% {% \expandafter\ekvo@CurrentOption@loop\expandafter{#1}\ekvo@parse } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % { % \ekvo@parse, % \ekvo@parse@kv,\ekvo@parse@kv@,\ekvo@expansion@kv,\ekvo@expansion@kv@, % \ekvo@parse@k, \ekvo@parse@k@, \ekvo@expansion@k, \ekvo@expansion@k@ % } % This macro calls internals of \expkv\ such that the input is split at an % equals sign of category other. % \begin{macrocode} \long\def\ekvo@parse#1% {% \ekv@eq@other#1\ekv@nil\ekv@mark\ekvo@parse@kv =\ekv@mark\ekvo@parse@k } % \end{macrocode} % If there was an equals sign, this will be called and remove the remainder of % the split. Afterwards the \expnotation\ is checked and possibly executed, % and the \kv\ pair is set. While reinsertion works via the |Rr| % \expansion-rule, it might affect the unused global option list. % \begin{macrocode} \long\def\ekvo@parse@kv#1\ekv@stop#2\ekv@nil=\ekv@mark\ekvo@parse@k {\ekv@strip{#2}{\ekv@strip{#1}\ekvo@parse@kv@}} \long\def\ekvo@parse@kv@#1#2% {% \ekv@ifexp{#1}% {\ekvo@expansion@kv{#2}}% {\ekvo@set@kv{#1}{#2}}% } % \end{macrocode} % Check for \expansion-rules was true, now we need to execute them, and use % the result in |\ekvo@set@kv|. Also we have to handle the key as if it was a % defined key if the |\r| \expansion-rule was found (which potentially removes % it from the list of global unused options). % \begin{macrocode} \long\def\ekvo@expansion@kv#1#2#3#4% {% \ekv@expansion@rule@{#1}#2\ekv@mark\ekv@stop{#3}{}% {\ekvo@handle@defined@kv{#3}{#1}\ekvmorekv}% \ekvo@expansion@kv@ } \long\def\ekvo@expansion@kv@#1#2{\ekvo@set@kv{#1}{#2}} % \end{macrocode} % And basically the same two biggish steps, but for the case that no equals % sign is found. % \begin{macrocode} \long\def\ekvo@parse@k#1\ekv@nil\ekv@mark\ekvo@parse@kv\ekv@stop\ekv@mark {\ekv@strip{#1}\ekvo@parse@k@} \long\def\ekvo@parse@k@#1% {% \ekv@ifexp{#1}% \ekvo@expansion@k {\ekvo@set@k{#1}}% } \long\def\ekvo@expansion@k#1#2#3% {% \ekv@expansion@rule@{#2}#1\ekv@mark\ekv@stop{}{}% {\ekvo@handle@defined@k{#2}\ekvmorekv}% \ekvo@expansion@k@ } \long\def\ekvo@expansion@k@#1#2{\ekvo@set@k{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\ekvo@set@k,\ekvo@set@kv} % These two macros check whether the key is defined and if so call the handler % for defined keys and execute the key, else the handler for undefined keys is % called. % \begin{macrocode} \protected\def\ekvo@set@k#1% {% \ekv@ifdefined{\ekvo@name{#1}N}% {% \ekvo@handle@defined@k{#1}% \csname\ekvo@name{#1}N\endcsname }% {\ekvo@handle@undefined@k{#1}}% } \protected\def\ekvo@set@kv#1#2% {% \ekv@ifdefined{\ekvo@name{#1}}% {% \ekvo@handle@defined@kv{#1}{#2}% \csname\ekvo@name{#1}\endcsname{#2}% }% {\ekvo@handle@undefined@kv{#1}{#2}}% } % \end{macrocode} % \end{macro} % % % \subsection{List variable helpers} % % \begin{macro}[internal]{\ekvo@addto@list} % This macro is rather simple. If the list to which the |\CurrentOption| % should be added is empty we can just let the list to the |\CurrentOption|. % Else we have to expand the list once and the |\CurrentOption| once. % \begin{macrocode} \protected\def\ekvo@addto@list#1% {% \ekvo@ifx@TF#1\@empty {\let#1\CurrentOption}% {% \edef#1% {% \unexpanded\expandafter{#1},% \unexpanded\expandafter{\CurrentOption}% }% }% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\ekvo@addnewto@list} % This works just like |\ekvo@addto@list|, but it only adds elements which are % not yet part of the list, hence we check if the option is already in the % list. % \begin{macrocode} \protected\def\ekvo@addnewto@list#1% {% \ekvo@ifx@TF#1\@empty {\let#1\CurrentOption}% {% \ekvo@if@in@list#1% {}% {% \edef#1% {% \unexpanded\expandafter{#1},% \unexpanded\expandafter{\CurrentOption}% }% }% }% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal] % {\ekvo@if@in@list,\ekvo@if@in@list@,\ekvo@if@in@list@result} % This is a slow but robust test whether some option is already contained in a % list. Using argument gobbling logic would be faster, but that way wouldn't % be robust for elements containing |{|, |}|, or |#|. Just loop over the code % and compare each element, end early if a match is found. % \begin{macrocode} \protected\def\ekvo@if@in@list#1% {% \ekvo@ifx@TF#1\@empty \@secondoftwo {% \let\ekvo@curropt\CurrentOption \let\ekvo@if@in@list@result\@secondoftwo \expandafter\ekvo@CurrentOption@loop\expandafter{#1}\ekvo@if@in@list@ \let\CurrentOption\ekvo@curropt \ekvo@if@in@list@result }% } \protected\long\def\ekvo@if@in@list@#1% {% \ekvo@ifx@T\ekvo@curropt\CurrentOption {% \let\ekvo@if@in@list@result\@firstoftwo \ekvo@end@loop }% } % \end{macrocode} % \end{macro} % % \begin{macro}[internal]{\ekvo@rmfrom@list,\ekvo@rmfrom@list@} % This works by looping over every list item and comparing it to % |\ekvo@curropt| which stores the real |\CurrentOption|. This is % comparatively slow, but works for items containing braces unlike what % \LaTeXe\ does. We could be faster for items not containing braces, though. % \begin{macrocode} \protected\def\ekvo@rmfrom@list#1% {% \ekvo@ifx@F#1\@empty {% \let\ekvo@tmp@list\@empty \let\ekvo@curropt\CurrentOption \expandafter\ekvo@CurrentOption@loop\expandafter{#1}\ekvo@rmfrom@list@ \let\CurrentOption\ekvo@curropt \let#1\ekvo@tmp@list }% } \protected\long\def\ekvo@rmfrom@list@#1% {% \ekvo@ifx@F\CurrentOption\ekvo@curropt {\ekvo@addto@list\ekvo@tmp@list}% } % \end{macrocode} % \end{macro} % % % \subsection{Errors} % % \begin{macro}[internal] % { % \ekvo@err@undefined@key,\ekvo@err@value@required, % \ekvo@err@value@forbidden,\ekvo@err@undefined@set % } % Just some macros to throw errors in the few cases an error has to be thrown. % \begin{macrocode} \protected\def\ekvo@err@undefined@key#1% {% \ekvo@pkg@cls@error {Undefined option `\detokenize{#1}'}% {The used option was not defined. Perhaps you misspelled it?}% } \protected\def\ekvo@err@value@required#1% {% \ekvo@pkg@cls@error {Missing value for option `\detokenize{#1}'}% {The used option requires a value or you misspelled its name.}% } \protected\def\ekvo@err@value@forbidden#1% {% \ekvo@pkg@cls@error {Unwanted value for option `\detokenize{#1}'}% {The used option doesn't support a value or you misspelled its name.}% } \protected\def\ekvo@err@undefined@set#1% {% \PackageError{expkv-opt}% {Undefined set `#1'}% {The set for which you try to parse options isn't defined in expkv.}% } \protected\def\ekvo@pkg@cls@error {% \ekvo@ifx@TF\@currext\@clsextension \ClassError \PackageError \@currname } % \end{macrocode} % \end{macro} % % % \subsection{User Interface} % % The user interface macros just put together the bits and pieces. % % \begin{macro}{\ekvoProcessOptions} % First we check if user-defined handlers were used. If that's the case we % need to store them and restore them for each list processor. Else just call % them sequentially. % \begin{macrocode} \protected\def\ekvoProcessOptions#1% {% \ekvo@if@need@handlers {% \ekvoProcessGlobalOptions{#1}% \ekvoProcessLocalOptions {#1}% \ekvoProcessFutureOptions{#1}% \@gobbletwo }% \@firstofone {% \let\ekvo@tmpa\ekvo@handle@undefined@k \let\ekvo@tmpb\ekvo@handle@undefined@kv \ekvoUseUnknownHandlers\ekvo@tmpa\ekvo@tmpb \ekvoProcessGlobalOptions{#1}% \ekvoUseUnknownHandlers\ekvo@tmpa\ekvo@tmpb \ekvoProcessLocalOptions {#1}% \ekvoUseUnknownHandlers\ekvo@tmpa\ekvo@tmpb \ekvoProcessFutureOptions{#1}% \let\ekvo@tmpa\ekvo@undefined \let\ekvo@tmpb\ekvo@undefined }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\ekvoProcessLocalOptions} % \begin{macrocode} \protected\def\ekvoProcessLocalOptions {% \ekvo@process@common {\ekv@ifdefined{@raw@opt@\@currname.\@currext}\@firstofone\@gobble}% {% \ekvo@set@handlers@local \expandafter \ekvo@process@list\csname @raw@opt@\@currname.\@currext\endcsname \AtEndOfPackage{\let\@unprocessedoptions\relax}% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\ekvoProcessGlobalOptions} % \begin{macrocode} \protected\def\ekvoProcessGlobalOptions {% \ekvo@process@common{\ekvo@ifx@F\@classoptionslist\relax}% {% \ekvo@set@handlers@global \ekvo@process@list\@raw@classoptionslist \let\ekvo@handle@defined@k\@gobble \let\ekvo@handle@defined@kv\@gobbletwo }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\ekvoProcessUnusedGlobalOptions} % \begin{macrocode} \protected\def\ekvoProcessUnusedGlobalOptions#1% {% \PackageError{expkv-opt}% {% \noexpand \ekvoProcessUnusedGlobalOptions no longer works because of changes in% \MessageBreak the LaTeX2e kernel% }% {}% } % \end{macrocode} % \end{macro} % % \begin{macro}{\ekvoProcessFutureOptions} % Parsing future options (without patching kernel internals) is only possible % with kernel versions after 2022-11-01. % The user macro needs to store the user-set handlers for later if % |\ekvoUseUnknownHandlers| was used. Then it stores the correct code to % process future options in the |opt@handler@| variable. % \begin{macrocode} \IfFormatAtLeastTF{2022/11/01} {% \protected\def\ekvoProcessFutureOptions#1% {% \ekvo@if@need@handlers\@gobbletwo \@firstofone {% \expandafter\let \csname ekvo@future@undefined@k@\@currname.\@currext\endcsname \ekvo@handle@undefined@k \expandafter\let \csname ekvo@future@undefined@kv@\@currname.\@currext\endcsname \ekvo@handle@undefined@kv }% \protected\expandafter \xdef\csname opt@handler@\@currname.\@currext\endcsname {\ekv@unexpanded{\ekvo@future{#1}}}% } % \end{macrocode} % \begin{macro}[internal]{\ekvo@future,\ekvo@set@handlers@future} % Key parsing is pretty similar to |\ekvoProcessLocalOptions|, only the % handlers are defined differently, namely it is checked whether they are % user-specified, if not we reuse the undefined handlers for packages (which % will throw an error if an unknown key is found). % \begin{macrocode} \protected\def\ekvo@future {% \ekvo@process@common {\ekv@ifdefined{@raw@opt@\@currname.\@currext}\@firstofone\@gobble}% {% \ekvo@set@handlers@future \expandafter\ekvo@process@list \csname @raw@opt@\@currname.\@currext\endcsname \AtEndOfPackage{\let\@unprocessedoptions\relax}% }% } \protected\def\ekvo@set@handlers@future {% \expandafter\let\expandafter \ekvo@handle@undefined@k \csname \ekv@ifdefined{ekvo@future@undefined@k@\@currname.\@currext}% {ekvo@future@undefined@k@\@currname.\@currext}% {ekvo@handle@undefined@k@pkg}% \endcsname \expandafter\let\expandafter \ekvo@handle@undefined@kv \csname \ekv@ifdefined{ekvo@future@undefined@kv@\@currname.\@currext}% {ekvo@future@undefined@kv@\@currname.\@currext}% {ekvo@handle@undefined@kv@pkg}% \endcsname } % \end{macrocode} % \end{macro} % \begin{macrocode} } {% \protected\def\ekvoProcessFutureOptions#1% {% \PackageWarning{expkv-opt}% {LaTeX-kernel is too old to process future options.\@gobbletwo}% \protected\gdef\ekvoProcessFutureOptions##1{}% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\ekvoProcessOptionsList} % \begin{macrocode} \protected\def\ekvoProcessOptionsList#1% {% \ekvo@process@common{\ekvo@ifx@F#1\@empty}% {% \ekvo@set@handlers@list \ekvo@process@list#1% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\ekvoUseUnknownHandlers} % \begin{macro}[internal]{\ekvoUseUnknownHandlers@n,\ekvoUseUnknownHandlers@s} % \begin{macrocode} \protected\def\ekvoUseUnknownHandlers {% \let\ekvo@if@need@handlers\ekvo@dont@need@handlers \@ifstar\ekvoUseUnknownHandlers@s\ekvoUseUnknownHandlers@n } \protected\def\ekvoUseUnknownHandlers@s {% \long\def\ekvo@handle@undefined@k##1% {% \ekv@ifdefined{\ekvo@name{}uN}% {% \csname\ekvo@name{}uN\expandafter\endcsname\expandafter {\detokenize{##1}}{##1}% }% {\@gobble}% }% \long\def\ekvo@handle@undefined@kv##1##2% {% \ekv@ifdefined{\ekvo@name{}u}% {% \csname\ekvo@name{}u\ekv@expanded{\endcsname {\ekv@unexpanded{##2}}{\detokenize{##1}}}{##1}% }% {}% }% } \protected\def\ekvoUseUnknownHandlers@n#1#2% {% \let\ekvo@handle@undefined@k#1\relax \let\ekvo@handle@undefined@kv#2\relax } % \end{macrocode} % \end{macro} % \end{macro} % % All user interface macros should be only used in the preamble. % \begin{macrocode} \@onlypreamble\ekvoProcessOptions \@onlypreamble\ekvoProcessLocalOptions \@onlypreamble\ekvoProcessGlobalOptions \@onlypreamble\ekvoProcessFutureOptions \@onlypreamble\ekvoProcessOptionsList \@onlypreamble\ekvoUseUnknownHandlers % \end{macrocode} % % \gobbledocstriptag %