From ad3e732d16c097d105a5e990ff587c22c875a723 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Tue, 6 Apr 2021 22:16:32 +0000 Subject: expkv-opt (7apr21) git-svn-id: svn://tug.org/texlive/trunk@58772 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/generic/expkv-opt/README.md | 2 +- .../texmf-dist/doc/generic/expkv-opt/expkv-opt.pdf | Bin 260616 -> 268534 bytes .../generic/expkv-opt/expkv-opt-2020-10-10.dtx | 938 +++++++++++++++++++++ .../source/generic/expkv-opt/expkv-opt.dtx | 239 ++++-- .../tex/generic/expkv-opt/expkv-opt-2020-10-10.sty | 287 +++++++ .../texmf-dist/tex/generic/expkv-opt/expkv-opt.sty | 112 ++- 6 files changed, 1460 insertions(+), 118 deletions(-) create mode 100644 Master/texmf-dist/source/generic/expkv-opt/expkv-opt-2020-10-10.dtx create mode 100644 Master/texmf-dist/tex/generic/expkv-opt/expkv-opt-2020-10-10.sty diff --git a/Master/texmf-dist/doc/generic/expkv-opt/README.md b/Master/texmf-dist/doc/generic/expkv-opt/README.md index aa5d63cb029..447c4a87daa 100644 --- a/Master/texmf-dist/doc/generic/expkv-opt/README.md +++ b/Master/texmf-dist/doc/generic/expkv-opt/README.md @@ -1,7 +1,7 @@ ------------------------------------------------------------------------------- # expkv-opt -- parse class and package options with expkv -Version 2020-10-10 v0.1b +Version 2021-04-04 v0.2 Released under the LaTeX Project Public License v1.3c or later See http://www.latex-project.org/lppl.txt diff --git a/Master/texmf-dist/doc/generic/expkv-opt/expkv-opt.pdf b/Master/texmf-dist/doc/generic/expkv-opt/expkv-opt.pdf index 140d0c79f3e..5ecded074ae 100644 Binary files a/Master/texmf-dist/doc/generic/expkv-opt/expkv-opt.pdf and b/Master/texmf-dist/doc/generic/expkv-opt/expkv-opt.pdf differ diff --git a/Master/texmf-dist/source/generic/expkv-opt/expkv-opt-2020-10-10.dtx b/Master/texmf-dist/source/generic/expkv-opt/expkv-opt-2020-10-10.dtx new file mode 100644 index 00000000000..ab2dcec41ab --- /dev/null +++ b/Master/texmf-dist/source/generic/expkv-opt/expkv-opt-2020-10-10.dtx @@ -0,0 +1,938 @@ +% \iffalse meta-comment +% +% File: expkv-opt.dtx Copyright (C) 2020 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\nameofplainTeX{plain} +\ifx\fmtname\nameofplainTeX\else + \expandafter\begingroup +\fi +\input l3docstrip.tex +\askforoverwritefalse +\preamble + +-------------------------------------------------------------- +expkv-opt -- parse class and package options with expkv +E-mail: jspratte@yahoo.de +Released under the LaTeX Project Public License v1.3c or later +See http://www.latex-project.org/lppl.txt +-------------------------------------------------------------- + +Copyright (C) 2020 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 + +This work is "maintained" (as per LPPL maintenance status) by + Jonathan P. Spratte. + +This work consists of the file expkv-opt.dtx +and the derived files expkv-opt.pdf + expkv-opt.sty + +\endpreamble +% stop docstrip adding \endinput +\postamble +\endpostamble +\generate{\file{expkv-opt-2020-10-10.sty}{\from{expkv-opt-2020-10-10.dtx}{pkg}}} +\ifx\fmtname\nameofplainTeX + \expandafter\endbatchfile +\else + \expandafter\endgroup +\fi +% +\IfFileExists{expkv-opt.sty}{\RequirePackage{expkv-opt}}{} +\ProvidesFile{expkv-opt.dtx} + [\csname ekvoDate\endcsname\ parse class and package options with expkv] +\PassOptionsToPackage{full}{textcomp} +\documentclass{l3doc} +\RequirePackage[oldstylenums,nott]{kpfonts} +\input{glyphtounicode} +\pdfgentounicode=1 +\RequirePackage{listings} +\RequirePackage{booktabs} +\RequirePackage{array} +\RequirePackage{collcell} +\RequirePackage{siunitx} +\RequirePackage{xcolor} +\RequirePackage{caption} +\RequirePackage{microtype} +\RequirePackage{accsupp} +\lstset + { + ,flexiblecolumns=false + ,basewidth=.53em + ,gobble=2 + ,basicstyle=\fontfamily{jkp}\itshape + ,morekeywords=^^A + {^^A + \ekvoProcessLocalOptions, + \ekvoProcessGlobalOptions, + \ekvoProcessUnusedGlobalOptions, + \ekvoProcessOptionsList, + \ekvoUseUnknownHandlers + } + ,morecomment=[l]\% + ,commentstyle=\color[gray]{0.4} + ,literate={\{}{{\CodeSymbol\{}}{1} + {\}}{{\CodeSymbol\}}}{1} + ^^A,literate=*{}{\key}{4}{}{\set}{4} + } +\newcommand*\CodeSymbol[1]{\textbf{#1}} +\RequirePackage{randtext} +\let\metaORIG\meta +\protected\def\meta #1{\texttt{\metaORIG{#1}}} +\renewcommand*\thefootnote{\fnsymbol{footnote}} +\definecolor{expkvred}{HTML}{9F393D} +\colorlet{expkvgrey}{black!75} +\makeatletter +\newcommand*\expkv + {^^A + \texorpdfstring + {^^A + \mbox + {^^A + \BeginAccSupp{ActualText=expkv}^^A + \href{https://github.com/Skillmon/tex_expkv} + {^^A + \rmfamily + \bfseries + {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A + \lower.493ex + \hbox{{\color{expkvgrey}P}\kern-.1em{\color{expkvred}k}}^^A + \kern-.18em{\color{expkvred}v}^^A + }^^A + \EndAccSupp{}^^A + }^^A + } + {expkv}^^A + } +\newcommand*\expkvpkg[1] + {^^A + \texorpdfstring + {^^A + \mbox + {^^A + \BeginAccSupp{ActualText=expkv-#1}^^A + \href{https://github.com/Skillmon/tex_expkv-#1} + {^^A + \rmfamily + \bfseries + {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A + \lower.493ex + \hbox{{\color{expkvgrey}P}\kern-.1em{\color{expkvred}k}}^^A + \kern-.18em{\color{expkvred}v}^^A + {\color{expkvgrey}^^A + \kern.05em\rule[-.1ex]{.08em}{1.2ex}\kern.05em\textsc{#1}^^A + }^^A + }^^A + \EndAccSupp{}^^A + }^^A + } + {expkv-#1}^^A + } +\newcommand*\expkvd{\expkvpkg{def}} +\newcommand*\expkvc{\expkvpkg{cs}} +\newcommand*\expkvo{\expkvpkg{opt}} +\newcommand\kv{\meta{key}=\meta{value}} +\newcommand\key{\meta{key}} +\newcommand\val{\meta{value}} +\newcommand\set{\meta{set}} +\newcommand\enfprot{\textcolor{black}{protected}} +\newcommand\allprot{\textcolor{gray}{protected}} +\newcommand\notprot{\textcolor{red!80!black}{protected}} +\newcommand\enflong{\textcolor{black}{long}} +\newcommand\alllong{\textcolor{gray}{long}} +\newcommand\notlong{\textcolor{red!80!black}{long}} +\newcommand\prefixes[2] + {^^A + \hfill + \ifcase\numexpr#1\relax\or + \enfprot\or + \allprot\or + \notprot\fi\space + \ifcase\numexpr#2\relax\or + \enflong\or + \alllong\or + \notlong\fi + } +\hypersetup{linkcolor=red!80!black,urlcolor=purple!80!black} +\DoNotIndex{\def,\edef,\,,\=,\begingroup,\catcode,\chardef,\csname,\endcsname} +\DoNotIndex{\endgroup,\endinput,\errmessage,\expandafter,\input,\let,\long} +\DoNotIndex{\protected,\ProvidesFile,\ProvidesPackage,\relax,\space} +\DoNotIndex{\@,\unexpanded,\string,\expanded,\dimexpr,\global,\glueexpr,\hbox} +\DoNotIndex{\numexpr,\RequirePackage,\setbox,\the,\unless,\xdef,\@firstofone} +\DoNotIndex{\@firstoftwo,\@gobble,\@secondoftwo,\AtEndOfPackage,\newcommand} +\DoNotIndex{\PackageError,\@classoptionslist,\@clsextension,\@currext} +\DoNotIndex{\@currname,\@empty,\@gobbletwo,\@onlypreamble,\@unprocessedoptions} +\DoNotIndex{\@unusedoptionlist} +\DoNotIndex{\ifcsname} +\DoNotIndex{\ifx} +\DoNotIndex{\ifdefined} +\DoNotIndex{\iffalse} +\DoNotIndex{\iftrue} +\DoNotIndex{\else} +\DoNotIndex{\fi} +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@ifdefinable\gobbledocstriptag{\def\gobbledocstriptag#1>{}} +\makeatother +\begin{document} + \title + {^^A + \texorpdfstring + {^^A + \huge\expkvo + \\[\medskipamount] + \Large parse class and package options with \expkv + }{expkv-opt - parse class and package options with expkv}^^A + } + \date{\ekvoDate\space v\ekvoVersion} + \author{Jonathan P. Spratte\thanks{\protect\randomize{jspratte@yahoo.de}}} + \DocInput{expkv-opt.dtx} +\end{document} +%^^A=<< +% \fi +% +% \maketitle +% \renewcommand*\thefootnote{\arabic{footnote}} +% +% \begin{abstract} +% \noindent\parfillskip=0pt +% \expkvo\ provides option parsing for classes and packages in \LaTeXe\ based on +% \expkv. Global and local options are parsed individually by different +% commands. The stylised name is \expkvo\ but the files use \file{expkv-opt}, +% this is due to CTAN-rules which don't allow \string| in package names since +% that is the pipe symbol in *nix shells. +% \end{abstract} +% +% \tableofcontents +% +% \begin{documentation}^^A>>= +% +% \section{Documentation} +% +% The \expkv\ family provides at its core a \kv\ parser and additionally +% packages, one to conveniently define new keys (\expkvd) and another to build +% expandable \kv\ taking control sequences (\expkvc). Still missing from the mix +% was a solution to parse \LaTeXe\ class and package options, a gap that's +% hereby filled with \expkvo. +% +% \expkvo\ shouldn't place any restrictions on the keys, but note that parts of +% \LaTeXe\ can break if the \kv\ list contains braces. This includes the global +% options list depending on which class you're using. Also keep in mind that +% every value provided should be save from an |\edef| expansion, as the space +% stripping code of \LaTeXe\ options (which is applied before \expkvo\ takes +% control) uses such an expansion. +% +% The package can be loaded with +% \begin{lstlisting} +% \usepackage{expkv-opt} +% \end{lstlisting} +% Unlike the other packages in the \expkv\ family, \expkvo\ is only provided as +% a \LaTeX\ package. +% +% Before reading this documentation you should read \expkv's documentation and +% might want to also read the documentation of \expkvd. +% +% +% \subsection{Macros} +% +% \expkvo's behaviour if it encounters a defined or an undefined \key\ depends +% on which list is being parsed and whether the current file is a class or not. +% Of course in every case a defined \key's callback will be invoked but an +% additional action might be executed. For this reason the rule set of every +% macro will be given below the short description which list it will parse. +% +% During each of the processing macros the current list element (not separated +% in \key\ and \val\ but as a whole) is stored within the macro +% \cs{CurrentOption}. +% +% \begin{function}{\ekvoProcessLocalOptions} +% \begin{syntax} +% \cs{ekvoProcessLocalOptions}\marg{set} +% \end{syntax} +% This parses the options which are directly passed to the current class or +% package for an \expkv\ \set. +% \end{function} +% \begin{description} +% \item[Class:] +% \begin{description} +% \item[defined] \emph{nothing} +% \item[undefined] +% add the key to the list of unused global options (if the local option +% list matches the option list of the main class) +% \end{description} +% \item[Package:] +% \begin{description} +% \item[defined] \emph{nothing} +% \item[undefined] throw an error +% \end{description} +% \end{description} +% +% \begin{function}{\ekvoProcessGlobalOptions} +% \begin{syntax} +% \cs{ekvoProcessGlobalOptions}\marg{set} +% \end{syntax} +% In \LaTeXe\ the options given to |\documentclass| are global options. This +% macro processes the global options for an \expkv\ \set. +% \end{function} +% \begin{description} +% \item[Class:] +% \begin{description} +% \item[defined] remove the option from the list of unused global options +% \item[undefined] \emph{nothing} +% \end{description} +% \item[Package:] +% \begin{description} +% \item[defined] remove the option from the list of unused global options +% \item[undefined] \emph{nothing} +% \end{description} +% \end{description} +% +% \begin{function}{\ekvoProcessUnusedGlobalOptions} +% \begin{syntax} +% \cs{ekvoProcessUnusedGlobalOptions}\marg{set} +% \end{syntax} +% If you want to, instead of parsing all global options, you can parse only +% those global options which weren't yet used by another package or class. +% \end{function} +% \begin{description} +% \item[Class:] +% \begin{description} +% \item[defined] remove the option from the list of unused global options +% \item[undefined] \emph{nothing} +% \end{description} +% \item[Package:] +% \begin{description} +% \item[defined] remove the option from the list of unused global options +% \item[undefined] \emph{nothing} +% \end{description} +% \end{description} +% +% \begin{function}{\ekvoProcessOptionsList} +% \begin{syntax} +% \cs{ekvoProcessOptionsList}\meta{list}\marg{set} +% \end{syntax} +% Process the \kv\ list stored in the macro \meta{list}. +% \end{function} +% \begin{description} +% \item[Class:] +% \begin{description} +% \item[defined] \emph{nothing} +% \item[undefined] \emph{nothing} +% \end{description} +% \item[Package:] +% \begin{description} +% \item[defined] \emph{nothing} +% \item[undefined] \emph{nothing} +% \end{description} +% \end{description} +% +% \begin{function}{\ekvoUseUnknownHandlers} +% \begin{syntax} +% \cs{ekvoUseUnknownHandlers}\meta{cs_1}\meta{cs_2} +% \end{syntax} +% With this macro you can change the action \expkvo\ executes if it encounters +% an undefined \key\ for the next (and only the next) list processing macro. +% The macro \meta{cs_1} will be called if an undefined \key\ without a \val\ +% is encountered and get one argument, being the \key. Analogous the macro +% \meta{cs_2} will be called if an undefined \key\ with a \val\ was specified. +% It will get two arguments, the first being the \key\ and the second the +% \val. +% \end{function} +% +% \begin{function}{\ekvoVersion,\ekvoDate} +% These two macros store the version and date of the package. +% \end{function} +% +% +% \subsection{Example} +% +% Let's say we want to create a package that changes the way footnotes are +% displayed in \LaTeX. For this it will essentially just redefine +% \cs[no-index]{thefootnote} and we'll call this package \pkg{ex-footnote}. +% First we report back which package we are: +% \begin{lstlisting} +% \ProvidesPackage{ex-footnote}[2020-02-02 v1 change footnotes] +% \end{lstlisting} +% Next we'll need to provide the options we want the package to have. +% \begin{lstlisting} +% \RequirePackage{color} +% \RequirePackage{expkv-opt} % also loads expkv +% \ekvdef{ex-footnote}{color}{\def\exfn@color{#1}} +% \ekvdef{ex-footnote}{format}{\def\exfn@format{#1}} +% \end{lstlisting} +% We can provide initial values just by defining the two macros storing the +% value. +% \begin{lstlisting} +% \newcommand*\exfn@color{} +% \newcommand*\exfn@format{arabic} +% \end{lstlisting} +% Next we need to process the options given to the package. The package should +% only obey options directly passed to it, so we're only using +% |\ekvoProcessLocalOptions|: +% \begin{lstlisting} +% \ekvoProcessLocalOptions{ex-footnote} +% \end{lstlisting} +% Now everything that's still missing is actually changing the way footnotes +% appear: +% \begin{lstlisting} +% \renewcommand*\thefootnote +% {% +% \ifx\exfn@color\@empty +% \csname\exfn@format\endcsname{footnote}% +% \else +% \textcolor{\exfn@color}{\csname\exfn@format\endcsname{footnote}}% +% \fi +% } +% \end{lstlisting} +% \bigskip +% +% \noindent +% So the complete code of the package would look like this: +% \begin{lstlisting} +% \ProvidesPackage{ex-footnote}[2020-02-02 v1 change footnotes] +% +% \RequirePackage{color} +% \RequirePackage{expkv-opt} % also loads expkv +% +% \ekvdef{ex-footnote}{color}{\def\exfn@color{#1}} +% \ekvdef{ex-footnote}{format}{\def\exfn@format{#1}} +% \newcommand*\exfn@color{} +% \newcommand*\exfn@format{arabic} +% +% \ekvoProcessLocalOptions{ex-footnote} +% +% \renewcommand*\thefootnote +% {% +% \ifx\exfn@color\@empty +% \csname\exfn@format\endcsname{footnote}% +% \else +% \textcolor{\exfn@color}{\csname\exfn@format\endcsname{footnote}}% +% \fi +% } +% \end{lstlisting} +% \bigskip +% +% \noindent +% And it could be used with one of the following lines: +% \begin{lstlisting} +% \usepackage{ex-footnote} +% \usepackage[format=fnsymbol]{ex-footnote} +% \usepackage[color=green]{ex-footnote} +% \usepackage[color=red,format=roman]{ex-footnote} +% \end{lstlisting} +% +% +% \subsection{Bugs} +% +% If you happen to find bugs, it'd be great if you let me know. Just write me an +% email (see the front page) or submit a bug report on GitHub: +% \url{https://github.com/Skillmon/tex_expkv-opt} +% +% +% \subsection{License} +% +% Copyright \textcopyright\ 2020\unless\ifnum\year=2020--\the\year\fi\ +% Jonathan P. Spratte +% +% \medskip\noindent +% 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: +% +% \url{http://www.latex-project.org/lppl.txt} +% +% \noindent +% This work is ``maintained'' (as per LPPL maintenance status) by +% +% \mbox{Jonathan P. Spratte}. +% +% \end{documentation}^^A=<< +% +% \begin{implementation}^^A>>= +% +% \clearpage +% +% +% \section{Implementation} +% +% \gobbledocstriptag +%<*pkg> +% Start the package with the typical \LaTeX\ standards. +% +% \begin{macro}{\ekvoVersion,\ekvoDate} +% Store the packages version and date in two macros. +% \begin{macrocode} +\newcommand*\ekvoVersion{0.1b} +\newcommand*\ekvoDate{2020-10-10} +% \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. +% \begin{macrocode} +\protected\long\def\ekvo@CurrentOption@loop#1#2% + {% + \ekvo@CurrentOption@loop@#2\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#2,% + {% + \ekv@gobble@from@mark@to@stop#2\ekvo@end@loop\ekv@stop + \ekv@ifblank{#2}% + {}% + {% + \edef\CurrentOption{\unexpanded\expandafter{\@gobble#2}}% + #1{#2}% + }% + \ekvo@CurrentOption@loop@#1\ekv@mark + } +\long\def\ekvo@end@loop#1\ekvo@tail{} +% \end{macrocode} +% \end{macro} +% +% +% \subsection{Tests} +% +% \begin{macro}[internal]{\ekvo@ifx@TF,\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@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. +% \begin{macrocode} +\long\def\ekvo@addto@unused@one#1{\ekvo@addto@list\@unusedoptionlist} +\long\def\ekvo@addto@unused@two#1#2{\ekvo@addto@list\@unusedoptionlist} +\long\def\ekvo@rmfrom@unused@one#1{\ekvo@rmfrom@list\@unusedoptionlist} +\long\def\ekvo@rmfrom@unused@two#1#2{\ekvo@rmfrom@list\@unusedoptionlist} +% \end{macrocode} +% \end{macro} +% \begin{macro}[internal] +% { +% \ekvo@set@handlers@local,\ekvo@set@handlers@global, +% \ekvo@set@handlers@unusedglobal,\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 opt@\@currname.\@currext\endcsname\@classoptionslist + \let\ekvo@handle@undefined@k\ekvo@addto@unused@one + \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two + \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@unusedglobal + {% + \ekvo@if@need@handlers + {% + \let\ekvo@handle@undefined@k\ekvo@addto@unused@one + \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two + \let\@unusedoptionlist\@empty + \@gobbletwo + }% + \@firstofone + {% + \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one + \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two + }% + } +\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} +% This macro calls internals of |\ekvparse| such that the code splitting at +% commas isn't executed, else this is equivalent to +% |\ekvparse\ekvo@set@k\ekvo@set@kv{#1}|. +% \begin{macrocode} +\protected\long\def\ekvo@parse#1% + {% + \ekv@eq@other#1\ekv@nil\ekv@mark\ekv@parse@eq@other@a + =\ekv@mark\ekv@parse@eq@active + \ekvo@set@k\ekvo@set@kv + \ekvo@tail + } +% \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. They have to clean up a bit of code which is left by |\ekvo@parse|. +% \begin{macrocode} +\protected\def\ekvo@set@k#1#2\ekvo@tail + {% + \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#3\ekvo@tail + {% + \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@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% + {% + \PackageError{expkv-opt}{Undefined key `#1' in set `\ekvo@setname'}{}% + } +\protected\def\ekvo@err@value@required#1% + {% + \PackageError{expkv-opt}% + {Value required for key `#1' in set `\ekvo@setname'}% + {}% + } +\protected\def\ekvo@err@value@forbidden#1% + {% + \PackageError{expkv-opt}% + {Value forbidden for key `#1' in set `\ekvo@setname'}% + {}% + } +\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.}% + } +% \end{macrocode} +% \end{macro} +% +% +% \subsection{User Interface} +% +% The user interface macros just put together the bits and pieces. +% \begin{macro}{\ekvoProcessLocalOptions} +% \begin{macrocode} +\protected\def\ekvoProcessLocalOptions + {% + \ekvo@process@common + {\ekv@ifdefined{opt@\@currname.\@currext}\@firstofone\@gobble}% + {% + \ekvo@set@handlers@local + \expandafter + \ekvo@process@list\csname 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\@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 + {% + \ekvo@process@common{\ekvo@ifx@F\@unusedoptionlist\@empty}% + {% + \let\ekvo@tmp@list\@unusedoptionlist + \ekvo@set@handlers@unusedglobal + \ekvo@process@list\ekvo@tmp@list + \let\ekvo@handle@defined@k\@gobble + \let\ekvo@handle@defined@kv\@gobbletwo + }% + } +% \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{macrocode} +\protected\def\ekvoUseUnknownHandlers#1#2% + {% + \let\ekvo@handle@undefined@k#1\relax + \let\ekvo@handle@undefined@kv#2\relax + \let\ekvo@if@need@handlers\ekvo@dont@need@handlers + } +% \end{macrocode} +% \end{macro} +% +% All user interface macros should be only used in the preamble. +% \begin{macrocode} +\@onlypreamble\ekvoProcessLocalOptions +\@onlypreamble\ekvoProcessGlobalOptions +\@onlypreamble\ekvoProcessUnusedGlobalOptions +\@onlypreamble\ekvoProcessOptionsList +\@onlypreamble\ekvoUseUnknownHandlers +% \end{macrocode} +% +% \gobbledocstriptag +% +% +% \end{implementation}^^A=<< +% +% \clearpage +% \PrintIndex +% +% \Finale +\endinput +% +^^A vim: ft=tex fdm=marker fmr=>>=,=<< diff --git a/Master/texmf-dist/source/generic/expkv-opt/expkv-opt.dtx b/Master/texmf-dist/source/generic/expkv-opt/expkv-opt.dtx index f9a30b79663..22a9a9b0c3e 100644 --- a/Master/texmf-dist/source/generic/expkv-opt/expkv-opt.dtx +++ b/Master/texmf-dist/source/generic/expkv-opt/expkv-opt.dtx @@ -151,24 +151,6 @@ and the derived files expkv-opt.pdf \newcommand\key{\meta{key}} \newcommand\val{\meta{value}} \newcommand\set{\meta{set}} -\newcommand\enfprot{\textcolor{black}{protected}} -\newcommand\allprot{\textcolor{gray}{protected}} -\newcommand\notprot{\textcolor{red!80!black}{protected}} -\newcommand\enflong{\textcolor{black}{long}} -\newcommand\alllong{\textcolor{gray}{long}} -\newcommand\notlong{\textcolor{red!80!black}{long}} -\newcommand\prefixes[2] - {^^A - \hfill - \ifcase\numexpr#1\relax\or - \enfprot\or - \allprot\or - \notprot\fi\space - \ifcase\numexpr#2\relax\or - \enflong\or - \alllong\or - \notlong\fi - } \hypersetup{linkcolor=red!80!black,urlcolor=purple!80!black} \DoNotIndex{\def,\edef,\,,\=,\begingroup,\catcode,\chardef,\csname,\endcsname} \DoNotIndex{\endgroup,\endinput,\errmessage,\expandafter,\input,\let,\long} @@ -177,19 +159,24 @@ and the derived files expkv-opt.pdf \DoNotIndex{\numexpr,\RequirePackage,\setbox,\the,\unless,\xdef,\@firstofone} \DoNotIndex{\@firstoftwo,\@gobble,\@secondoftwo,\AtEndOfPackage,\newcommand} \DoNotIndex{\PackageError,\@classoptionslist,\@clsextension,\@currext} -\DoNotIndex{\@currname,\@empty,\@gobbletwo,\@onlypreamble,\@unprocessedoptions} -\DoNotIndex{\@unusedoptionlist} +\DoNotIndex{\@currname,\@empty,\@gobbletwo,\@onlypreamble,\@raw@classoptionslist} +\DoNotIndex{\@unprocessedoptions,\@unusedoptionlist} +\DoNotIndex{\DeclareRelease,\DeclareCurrentRelease,\IfFormatAtLeastTF} +\DoNotIndex{\PackageWarning,\requestedLaTeXdate,\@ifstar} +\DoNotIndex{\pkgcls@parse@date@arg,\pkgcls@targetdate,\pkgcls@targetlabel} \DoNotIndex{\ifcsname} \DoNotIndex{\ifx} \DoNotIndex{\ifdefined} \DoNotIndex{\iffalse} \DoNotIndex{\iftrue} +\DoNotIndex{\ifnum} \DoNotIndex{\else} \DoNotIndex{\fi} \@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi \@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi \@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi \@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi +\@gobble\fi ^^A ignoring \ifx, \ifcsname, etc., but only one \fi \@ifdefinable\gobbledocstriptag{\def\gobbledocstriptag#1>{}} \makeatother \begin{document} @@ -233,17 +220,34 @@ and the derived files expkv-opt.pdf % was a solution to parse \LaTeXe\ class and package options, a gap that's % hereby filled with \expkvo. % -% \expkvo\ shouldn't place any restrictions on the keys, but note that parts of -% \LaTeXe\ can break if the \kv\ list contains braces. This includes the global -% options list depending on which class you're using. Also keep in mind that -% every value provided should be save from an |\edef| expansion, as the space -% stripping code of \LaTeXe\ options (which is applied before \expkvo\ takes -% control) uses such an expansion. +% With the 2021-05-01 release of \LaTeXe\ there were some very interesting +% changes to the package and class options code. It is now possible to use +% braces inside the options, and we can access options without them being +% preprocessed. As a result, some but not all restrictions were lifted from the +% possible option usage. What will still fail is things that aren't save from an +% |\edef| expansion. One thing that doesn't work any more is the possibility to +% parse the unused option list, because that one doesn't contain the full +% information any more. +% +% \expkvo\ will fall back to v0.1 if the kernel is older than 2021-05-01. +% \expkvo\ shouldn't place any restrictions on the keys, historic shortcomings +% of the kernel cannot be helped though, so the supported things vary with the +% kernel version. The one thing that \expkvo\ doesn't support, which \expkv\ +% alone would, is active commas. But there is no good reason why a comma could +% be active in the preamble. % % The package can be loaded with % \begin{lstlisting} % \usepackage{expkv-opt} % \end{lstlisting} +% and if you need a specific version you can use \LaTeXe's rollback support, so +% to load v0.1 explicitly use: +% \begin{lstlisting} +% \usepackage{expkv-opt}[=v0.1] +% \end{lstlisting} +% which will load the latest subversion of v0.1 +% (this shouldn't be done by a package author, but only by a user on a +% single-document basis if there are some incompatibilities, which is unlikely) % Unlike the other packages in the \expkv\ family, \expkvo\ is only provided as % a \LaTeX\ package. % @@ -259,9 +263,8 @@ and the derived files expkv-opt.pdf % additional action might be executed. For this reason the rule set of every % macro will be given below the short description which list it will parse. % -% During each of the processing macros the current list element (not separated -% in \key\ and \val\ but as a whole) is stored within the macro -% \cs{CurrentOption}. +% During each of the processing macros the current list element (not processed +% in any way) is stored within the macro \cs{CurrentOption}. % % \begin{function}{\ekvoProcessLocalOptions} % \begin{syntax} @@ -309,21 +312,10 @@ and the derived files expkv-opt.pdf % \begin{syntax} % \cs{ekvoProcessUnusedGlobalOptions}\marg{set} % \end{syntax} -% If you want to, instead of parsing all global options, you can parse only -% those global options which weren't yet used by another package or class. +% This does no longer work with \LaTeXe\ kernels starting from 2021-05-01, +% since the handling of the unused option list changed and no longer includes +% the values. As a result this will throw a warning and else will be ignored. % \end{function} -% \begin{description} -% \item[Class:] -% \begin{description} -% \item[defined] remove the option from the list of unused global options -% \item[undefined] \emph{nothing} -% \end{description} -% \item[Package:] -% \begin{description} -% \item[defined] remove the option from the list of unused global options -% \item[undefined] \emph{nothing} -% \end{description} -% \end{description} % % \begin{function}{\ekvoProcessOptionsList} % \begin{syntax} @@ -346,7 +338,8 @@ and the derived files expkv-opt.pdf % % \begin{function}{\ekvoUseUnknownHandlers} % \begin{syntax} -% \cs{ekvoUseUnknownHandlers}\meta{cs_1}\meta{cs_2} +% \cs{ekvoUseUnknownHandlers}\meta{cs_1}\meta{cs_2}\quad{\normalfont\itshape or} +% \cs{ekvoUseUnknownHandlers}* % \end{syntax} % With this macro you can change the action \expkvo\ executes if it encounters % an undefined \key\ for the next (and only the next) list processing macro. @@ -354,7 +347,11 @@ and the derived files expkv-opt.pdf % is encountered and get one argument, being the \key. Analogous the macro % \meta{cs_2} will be called if an undefined \key\ with a \val\ was specified. % It will get two arguments, the first being the \key\ and the second the -% \val. +% \val.\par +% If you use the starred variant, it'll not take further arguments. In this +% case the undefined handlers defined via |\ekvdefunknown| and +% |\ekvdefunknownNoVal| in the parsing set get used, and if those aren't +% available they'll simply do nothing. % \end{function} % % \begin{function}{\ekvoVersion,\ekvoDate} @@ -476,13 +473,36 @@ and the derived files expkv-opt.pdf % % \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 packages version and date in two macros. % \begin{macrocode} -\newcommand*\ekvoVersion{0.1b} -\newcommand*\ekvoDate{2020-10-10} +\newcommand*\ekvoVersion{0.2} +\newcommand*\ekvoDate{2021-04-04} % \end{macrocode} % \end{macro} % And we report who we are and what we need. @@ -594,18 +614,73 @@ and the derived files expkv-opt.pdf % \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. +% 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@addto@list} +\long\def\ekvo@addto@unused@two#1#2{\ekvo@do@unusedoptionlist\ekvo@addto@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} -\long\def\ekvo@addto@unused@one#1{\ekvo@addto@list\@unusedoptionlist} -\long\def\ekvo@addto@unused@two#1#2{\ekvo@addto@list\@unusedoptionlist} -\long\def\ekvo@rmfrom@unused@one#1{\ekvo@rmfrom@list\@unusedoptionlist} -\long\def\ekvo@rmfrom@unused@two#1#2{\ekvo@rmfrom@list\@unusedoptionlist} +\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@unusedglobal,\ekvo@set@handlers@list +% \ekvo@set@handlers@list % } % These macros are boring. They just set up the handlers to respect the rules % documented earlier. @@ -620,7 +695,9 @@ and the derived files expkv-opt.pdf \let\ekvo@handle@undefined@kv\@gobbletwo \else \expandafter - \ifx\csname opt@\@currname.\@currext\endcsname\@classoptionslist + \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 \else @@ -646,21 +723,6 @@ and the derived files expkv-opt.pdf \let\ekvo@handle@undefined@kv\@gobbletwo }% } -\protected\def\ekvo@set@handlers@unusedglobal - {% - \ekvo@if@need@handlers - {% - \let\ekvo@handle@undefined@k\ekvo@addto@unused@one - \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two - \let\@unusedoptionlist\@empty - \@gobbletwo - }% - \@firstofone - {% - \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one - \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two - }% - } \protected\def\ekvo@set@handlers@list {% \ekvo@if@need@handlers @@ -853,11 +915,11 @@ and the derived files expkv-opt.pdf \protected\def\ekvoProcessLocalOptions {% \ekvo@process@common - {\ekv@ifdefined{opt@\@currname.\@currext}\@firstofone\@gobble}% + {\ekv@ifdefined{@raw@opt@\@currname.\@currext}\@firstofone\@gobble}% {% \ekvo@set@handlers@local \expandafter - \ekvo@process@list\csname opt@\@currname.\@currext\endcsname + \ekvo@process@list\csname @raw@opt@\@currname.\@currext\endcsname \AtEndOfPackage{\let\@unprocessedoptions\relax}% }% } @@ -870,7 +932,7 @@ and the derived files expkv-opt.pdf \ekvo@process@common{\ekvo@ifx@F\@classoptionslist\relax}% {% \ekvo@set@handlers@global - \ekvo@process@list\@classoptionslist + \ekvo@process@list\@raw@classoptionslist \let\ekvo@handle@defined@k\@gobble \let\ekvo@handle@defined@kv\@gobbletwo }% @@ -879,16 +941,10 @@ and the derived files expkv-opt.pdf % \end{macro} % \begin{macro}{\ekvoProcessUnusedGlobalOptions} % \begin{macrocode} -\protected\def\ekvoProcessUnusedGlobalOptions +\protected\def\ekvoProcessUnusedGlobalOptions#1% {% - \ekvo@process@common{\ekvo@ifx@F\@unusedoptionlist\@empty}% - {% - \let\ekvo@tmp@list\@unusedoptionlist - \ekvo@set@handlers@unusedglobal - \ekvo@process@list\ekvo@tmp@list - \let\ekvo@handle@defined@k\@gobble - \let\ekvo@handle@defined@kv\@gobbletwo - }% + \PackageWarning{expkv-opt}% + {This macro no longer works because of changes in the LaTeX2e kernel.}% } % \end{macrocode} % \end{macro} @@ -906,7 +962,25 @@ and the derived files expkv-opt.pdf % \end{macro} % \begin{macro}{\ekvoUseUnknownHandlers} % \begin{macrocode} -\protected\def\ekvoUseUnknownHandlers#1#2% +\protected\def\ekvoUseUnknownHandlers + {\@ifstar\ekvoUseUnknownHandlers@s\ekvoUseUnknownHandlers@n} +\protected\def\ekvoUseUnknownHandlers@s + {% + \def\ekvo@handle@undefined@k + {% + \ekv@ifdefined{\ekvo@name{}uN}% + {\csname\ekvo@name{}uN\endcsname}% + {\@gobble}% + }% + \long\def\ekvo@handle@undefined@kv##1##2% + {% + \ekv@ifdefined{\ekvo@name{}u}% + {\csname\ekvo@name{}u\endcsname{##2}{##1}}% + {}% + }% + \let\ekvo@if@need@handlers\ekvo@dont@need@handlers + } +\protected\def\ekvoUseUnknownHandlers@n#1#2% {% \let\ekvo@handle@undefined@k#1\relax \let\ekvo@handle@undefined@kv#2\relax @@ -932,6 +1006,7 @@ and the derived files expkv-opt.pdf % \clearpage % \PrintIndex % +% \Finale \endinput % ^^A vim: ft=tex fdm=marker fmr=>>=,=<< diff --git a/Master/texmf-dist/tex/generic/expkv-opt/expkv-opt-2020-10-10.sty b/Master/texmf-dist/tex/generic/expkv-opt/expkv-opt-2020-10-10.sty new file mode 100644 index 00000000000..333622fd4c8 --- /dev/null +++ b/Master/texmf-dist/tex/generic/expkv-opt/expkv-opt-2020-10-10.sty @@ -0,0 +1,287 @@ +%% +%% This is file `expkv-opt-2020-10-10.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% expkv-opt-2020-10-10.dtx (with options: `pkg') +%% +%% -------------------------------------------------------------- +%% expkv-opt -- parse class and package options with expkv +%% E-mail: jspratte@yahoo.de +%% Released under the LaTeX Project Public License v1.3c or later +%% See http://www.latex-project.org/lppl.txt +%% -------------------------------------------------------------- +%% +%% Copyright (C) 2020 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 +%% +%% This work is "maintained" (as per LPPL maintenance status) by +%% Jonathan P. Spratte. +%% +%% This work consists of the file expkv-opt.dtx +%% and the derived files expkv-opt.pdf +%% expkv-opt.sty +%% +\newcommand*\ekvoVersion{0.1b} +\newcommand*\ekvoDate{2020-10-10} +\ProvidesPackage{expkv-opt} + [% + \ekvoDate\space v\ekvoVersion\space + parse class and package options with expkv% + ] +\RequirePackage{expkv} +\protected\long\def\ekvo@CurrentOption@loop#1#2% + {% + \ekvo@CurrentOption@loop@#2\ekv@mark#1,\ekv@stop,\ekvo@tail + } +\long\def\ekvo@CurrentOption@loop@#1#2,% + {% + \ekv@gobble@from@mark@to@stop#2\ekvo@end@loop\ekv@stop + \ekv@ifblank{#2}% + {}% + {% + \edef\CurrentOption{\unexpanded\expandafter{\@gobble#2}}% + #1{#2}% + }% + \ekvo@CurrentOption@loop@#1\ekv@mark + } +\long\def\ekvo@end@loop#1\ekvo@tail{} +\def\ekvo@ifx@TF#1#2{\ifx#1#2\ekv@fi@firstoftwo\fi\@secondoftwo} +\def\ekvo@ifx@F#1#2{\ifx#1#2\ekv@fi@gobble\fi\@firstofone} +\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}}% + } +\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}}% + } +\long\def\ekvo@addto@unused@one#1{\ekvo@addto@list\@unusedoptionlist} +\long\def\ekvo@addto@unused@two#1#2{\ekvo@addto@list\@unusedoptionlist} +\long\def\ekvo@rmfrom@unused@one#1{\ekvo@rmfrom@list\@unusedoptionlist} +\long\def\ekvo@rmfrom@unused@two#1#2{\ekvo@rmfrom@list\@unusedoptionlist} +\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 opt@\@currname.\@currext\endcsname\@classoptionslist + \let\ekvo@handle@undefined@k\ekvo@addto@unused@one + \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two + \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@unusedglobal + {% + \ekvo@if@need@handlers + {% + \let\ekvo@handle@undefined@k\ekvo@addto@unused@one + \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two + \let\@unusedoptionlist\@empty + \@gobbletwo + }% + \@firstofone + {% + \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one + \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two + }% + } +\protected\def\ekvo@set@handlers@list + {% + \ekvo@if@need@handlers + {% + \let\ekvo@handle@undefined@k\@gobble + \let\ekvo@handle@undefined@kv\@gobbletwo + }% + } +\let\ekvo@if@need@handlers\@firstofone +\protected\long\def\ekvo@dont@need@handlers#1% + {% + \let\ekvo@if@need@handlers\@firstofone + }% +\let\ekvo@handle@defined@k\@gobble +\let\ekvo@handle@defined@kv\@gobbletwo +\protected\def\ekvo@process@common#1#2#3% + {% + #1{\ekvo@do@with@set{#3}{#2}}% + } +\protected\def\ekvo@process@list#1% + {% + \expandafter\ekvo@CurrentOption@loop\expandafter{#1}\ekvo@parse + } +\protected\long\def\ekvo@parse#1% + {% + \ekv@eq@other#1\ekv@nil\ekv@mark\ekv@parse@eq@other@a + =\ekv@mark\ekv@parse@eq@active + \ekvo@set@k\ekvo@set@kv + \ekvo@tail + } +\protected\def\ekvo@set@k#1#2\ekvo@tail + {% + \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#3\ekvo@tail + {% + \ekv@ifdefined{\ekvo@name{#1}}% + {% + \ekvo@handle@defined@kv{#1}{#2}% + \csname\ekvo@name{#1}\endcsname{#2}% + }% + {\ekvo@handle@undefined@kv{#1}{#2}}% + } +\protected\def\ekvo@addto@list#1% + {% + \ekvo@ifx@TF#1\@empty + {\let#1\CurrentOption}% + {% + \edef#1% + {% + \unexpanded\expandafter{#1},% + \unexpanded\expandafter{\CurrentOption}% + }% + }% + } +\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}% + } +\protected\def\ekvo@err@undefined@key#1% + {% + \PackageError{expkv-opt}{Undefined key `#1' in set `\ekvo@setname'}{}% + } +\protected\def\ekvo@err@value@required#1% + {% + \PackageError{expkv-opt}% + {Value required for key `#1' in set `\ekvo@setname'}% + {}% + } +\protected\def\ekvo@err@value@forbidden#1% + {% + \PackageError{expkv-opt}% + {Value forbidden for key `#1' in set `\ekvo@setname'}% + {}% + } +\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\ekvoProcessLocalOptions + {% + \ekvo@process@common + {\ekv@ifdefined{opt@\@currname.\@currext}\@firstofone\@gobble}% + {% + \ekvo@set@handlers@local + \expandafter + \ekvo@process@list\csname opt@\@currname.\@currext\endcsname + \AtEndOfPackage{\let\@unprocessedoptions\relax}% + }% + } +\protected\def\ekvoProcessGlobalOptions + {% + \ekvo@process@common{\ekvo@ifx@F\@classoptionslist\relax}% + {% + \ekvo@set@handlers@global + \ekvo@process@list\@classoptionslist + \let\ekvo@handle@defined@k\@gobble + \let\ekvo@handle@defined@kv\@gobbletwo + }% + } +\protected\def\ekvoProcessUnusedGlobalOptions + {% + \ekvo@process@common{\ekvo@ifx@F\@unusedoptionlist\@empty}% + {% + \let\ekvo@tmp@list\@unusedoptionlist + \ekvo@set@handlers@unusedglobal + \ekvo@process@list\ekvo@tmp@list + \let\ekvo@handle@defined@k\@gobble + \let\ekvo@handle@defined@kv\@gobbletwo + }% + } +\protected\def\ekvoProcessOptionsList#1% + {% + \ekvo@process@common{\ekvo@ifx@F#1\@empty}% + {% + \ekvo@set@handlers@list + \ekvo@process@list#1% + }% + } +\protected\def\ekvoUseUnknownHandlers#1#2% + {% + \let\ekvo@handle@undefined@k#1\relax + \let\ekvo@handle@undefined@kv#2\relax + \let\ekvo@if@need@handlers\ekvo@dont@need@handlers + } +\@onlypreamble\ekvoProcessLocalOptions +\@onlypreamble\ekvoProcessGlobalOptions +\@onlypreamble\ekvoProcessUnusedGlobalOptions +\@onlypreamble\ekvoProcessOptionsList +\@onlypreamble\ekvoUseUnknownHandlers +%% +%% +%% End of file `expkv-opt-2020-10-10.sty'. diff --git a/Master/texmf-dist/tex/generic/expkv-opt/expkv-opt.sty b/Master/texmf-dist/tex/generic/expkv-opt/expkv-opt.sty index 1683a2ca995..12fa98acec1 100644 --- a/Master/texmf-dist/tex/generic/expkv-opt/expkv-opt.sty +++ b/Master/texmf-dist/tex/generic/expkv-opt/expkv-opt.sty @@ -29,8 +29,19 @@ %% and the derived files expkv-opt.pdf %% expkv-opt.sty %% -\newcommand*\ekvoVersion{0.1b} -\newcommand*\ekvoDate{2020-10-10} +\IfFormatAtLeastTF{2021/05/01} + {} + {% + \ifx\pkgcls@targetlabel\@empty + \ifnum\requestedLaTeXdate=\pkgcls@targetdate + \pkgcls@parse@date@arg{=v0.1}% + \fi + \fi + } +\DeclareRelease{v0.1}{2020/10/10}{expkv-opt-2020-10-10.sty} +\DeclareCurrentRelease{v0.2}{2021/04/04} +\newcommand*\ekvoVersion{0.2} +\newcommand*\ekvoDate{2021-04-04} \ProvidesPackage{expkv-opt} [% \ekvoDate\space v\ekvoVersion\space @@ -78,10 +89,42 @@ {\ekvo@err@value@forbidden{#1}}% {\ekvo@err@undefined@key{#1}}% } -\long\def\ekvo@addto@unused@one#1{\ekvo@addto@list\@unusedoptionlist} -\long\def\ekvo@addto@unused@two#1#2{\ekvo@addto@list\@unusedoptionlist} -\long\def\ekvo@rmfrom@unused@one#1{\ekvo@rmfrom@list\@unusedoptionlist} -\long\def\ekvo@rmfrom@unused@two#1#2{\ekvo@rmfrom@list\@unusedoptionlist} +\long\def\ekvo@addto@unused@one#1{\ekvo@do@unusedoptionlist\ekvo@addto@list} +\long\def\ekvo@addto@unused@two#1#2{\ekvo@do@unusedoptionlist\ekvo@addto@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}% + } +\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}} \protected\def\ekvo@set@handlers@local {% \ekvo@if@need@handlers @@ -92,7 +135,9 @@ \let\ekvo@handle@undefined@kv\@gobbletwo \else \expandafter - \ifx\csname opt@\@currname.\@currext\endcsname\@classoptionslist + \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 \else @@ -118,21 +163,6 @@ \let\ekvo@handle@undefined@kv\@gobbletwo }% } -\protected\def\ekvo@set@handlers@unusedglobal - {% - \ekvo@if@need@handlers - {% - \let\ekvo@handle@undefined@k\ekvo@addto@unused@one - \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two - \let\@unusedoptionlist\@empty - \@gobbletwo - }% - \@firstofone - {% - \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one - \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two - }% - } \protected\def\ekvo@set@handlers@list {% \ekvo@if@need@handlers @@ -234,11 +264,11 @@ \protected\def\ekvoProcessLocalOptions {% \ekvo@process@common - {\ekv@ifdefined{opt@\@currname.\@currext}\@firstofone\@gobble}% + {\ekv@ifdefined{@raw@opt@\@currname.\@currext}\@firstofone\@gobble}% {% \ekvo@set@handlers@local \expandafter - \ekvo@process@list\csname opt@\@currname.\@currext\endcsname + \ekvo@process@list\csname @raw@opt@\@currname.\@currext\endcsname \AtEndOfPackage{\let\@unprocessedoptions\relax}% }% } @@ -247,21 +277,15 @@ \ekvo@process@common{\ekvo@ifx@F\@classoptionslist\relax}% {% \ekvo@set@handlers@global - \ekvo@process@list\@classoptionslist + \ekvo@process@list\@raw@classoptionslist \let\ekvo@handle@defined@k\@gobble \let\ekvo@handle@defined@kv\@gobbletwo }% } -\protected\def\ekvoProcessUnusedGlobalOptions +\protected\def\ekvoProcessUnusedGlobalOptions#1% {% - \ekvo@process@common{\ekvo@ifx@F\@unusedoptionlist\@empty}% - {% - \let\ekvo@tmp@list\@unusedoptionlist - \ekvo@set@handlers@unusedglobal - \ekvo@process@list\ekvo@tmp@list - \let\ekvo@handle@defined@k\@gobble - \let\ekvo@handle@defined@kv\@gobbletwo - }% + \PackageWarning{expkv-opt}% + {This macro no longer works because of changes in the LaTeX2e kernel.}% } \protected\def\ekvoProcessOptionsList#1% {% @@ -271,7 +295,25 @@ \ekvo@process@list#1% }% } -\protected\def\ekvoUseUnknownHandlers#1#2% +\protected\def\ekvoUseUnknownHandlers + {\@ifstar\ekvoUseUnknownHandlers@s\ekvoUseUnknownHandlers@n} +\protected\def\ekvoUseUnknownHandlers@s + {% + \def\ekvo@handle@undefined@k + {% + \ekv@ifdefined{\ekvo@name{}uN}% + {\csname\ekvo@name{}uN\endcsname}% + {\@gobble}% + }% + \long\def\ekvo@handle@undefined@kv##1##2% + {% + \ekv@ifdefined{\ekvo@name{}u}% + {\csname\ekvo@name{}u\endcsname{##2}{##1}}% + {}% + }% + \let\ekvo@if@need@handlers\ekvo@dont@need@handlers + } +\protected\def\ekvoUseUnknownHandlers@n#1#2% {% \let\ekvo@handle@undefined@k#1\relax \let\ekvo@handle@undefined@kv#2\relax -- cgit v1.2.3