% \iffalse meta-comment % %% File: l3keys2e.dtx % % Copyright (C) 2009-2024 The LaTeX Project % % It 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 % % https://www.latex-project.org/lppl.txt % % This file is part of the "l3packages bundle" (The Work in LPPL) % and all files in that bundle must be distributed together. % % ----------------------------------------------------------------------- % % The development version of the bundle can be found at % % https://github.com/latex3/latex3 % % for those people who are interested. % %<*driver|package> % The version of expl3 required is tested as early as possible, as % some really old versions do not define \ProvidesExplPackage. \RequirePackage{expl3}[2020/02/08] %\@ifpackagelater{expl3}{2020/02/08} % {} % {% % \PackageError{l3keys2e}{Support package l3kernel too old} % {% % Please install an up to date version of l3kernel\MessageBreak % using your TeX package manager or from CTAN.\MessageBreak % \MessageBreak % Loading l3keys2e will abort!% % }% % \endinput % } % %<*driver> \documentclass[full]{l3doc} \usepackage{amstext} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3keys2e} package\\ % \LaTeXe{} option processing using \LaTeX3 keys^^A % } % % \author{^^A % The \LaTeX{} Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released 2024-03-14} % % \maketitle % % \begin{documentation} % % \section{Introduction} % % \begin{center} % \bfseries This package is obsolete with the June 2022 \LaTeX{} release. % \end{center} % % With new formats, \cs{ProcessKeyOptions} is available as a more powerful % version of \cs{ProcessKeysOptions}. In particular, it is built directly % into the \LaTeX{} kernel, uses `raw' options (and therefore does not % suffer from space stripping and expansion issues), and can avoid % option clash warnings. Package authors should transition their % code to the new approach. % % \section{Old introduction} % % The key--value method for optional arguments is very popular, as it % allows the class or package author to define a large number of % options with a simple interface. The \pkg{expl3} bundle of \LaTeX3 % base code includes the module \pkg{l3keys} for defining keys, but % to use these when loading \LaTeXe\ packages and classes requires % extra support. That support is provided by this small package, which % is intended to enable \LaTeXe\ packages to benefit from the power of % the \LaTeX3 key--value system. % % \subsection{Creating and using keyval options} % % As with any key--value input, using key--value pairs as package or % class options has two parts. The first stage is to define one or % more keys, using the \cs{keys_define:nn} function. For example, an % option which simply stores a value would be created using: % \begin{verbatim} % \keys_define:nn { module } % { option .tl_set:N = \l_module_variable_tl } % \end{verbatim} % On its own, this will not make the key an option for the package or % class containing the definition. The second stage is therefore to % process the current options, searching for applicable keys. % % \begin{function}{\ProcessKeysOptions} % \begin{syntax} % \cs{ProcessKeysOptions} \Arg{module} % \end{syntax} % The \cs{ProcessKeysOptions} function is used to check the current % option list against the keys defined for \Arg{module}. Global (class) % options and local (package) options are checked when this function % is called in a package. Each option which does match a key name is % then used to attempt to set the appropriate key using % \cs{keys_set:nn}. For example, the option defined earlier would be % processed by the line % \begin{verbatim} % \ProcessKeysOptions { module } % \end{verbatim} % \end{function} % % \begin{function}{\ProcessKeysPackageOptions} % \begin{syntax} % \cs{ProcessKeysPackageOptions} \Arg{module} % \end{syntax} % This function works in a similar manner to \cs{ProcessKeysOptions}. % When used in a \LaTeXe{} package, \cs{ProcessKeysPackageOptions} % will not examine any class options available. In contrast, % \cs{ProcessKeysOptions} does parse class options (in common with the % \LaTeXe{} kernel function \cs{ProcessOptions}). % \end{function} % % When passing unknown keys to other packages, the standard \LaTeX{} % \tn{CurrentOption} command is available and should be used. In contrast % to \cs{l_keys_key_str}, \cs{CurrentOption} is a token list and thus retains % category code information. Depending on how options are used by third-party % packages, this may be essential for the option to be recognised. % %\end{documentation} % %\begin{implementation} % %\subsection{\pkg{l3keys2e} implementation} % % \begin{macrocode} %<*package> % \end{macrocode} % % \begin{macrocode} %<@@=keys> % \end{macrocode} % % \begin{macrocode} \ProvidesExplPackage{l3keys2e}{2024-03-14}{} {LaTeX2e option processing using LaTeX3 keys} % \end{macrocode} % % Allow for a kernel-based implementation % \begin{macrocode} \cs_if_exist:NT \ProcessKeysOptions { \file_input_stop: } % \end{macrocode} % % Non-standard variants. % \begin{macrocode} \cs_generate_variant:Nn \clist_put_right:Nn { Nv } \cs_generate_variant:Nn \keys_if_exist:nnT { nx } \cs_generate_variant:Nn \keys_if_exist:nnTF { nx } % \end{macrocode} % % \begin{macro}{\l_@@_latexe_options_clist} % A single list is used for all options, into which they are collected % before processing. % \begin{macrocode} \clist_new:N \l_@@_latexe_options_clist % \end{macrocode} % \end{macro} % % \begin{macro}{\l_@@_process_class_bool} % A flag to indicate that class options should be processed for % packages. % \begin{macrocode} \bool_new:N \l_@@_process_class_bool % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_latexe_options:n} % The main function calls functions to collect up the global and local % options into \cs{l_@@_latexe_options_clist} before calling the % underlying functions to actually do the processing. So that a suitable % message is produced if the option is unknown, the special % \texttt{unknown} key is set if it does not already exist for the % current module. % \begin{macrocode} \cs_new_protected:Npn \@@_latexe_options:n #1 { \clist_clear:N \l_@@_latexe_options_clist \@@_latexe_options_global:n {#1} \@@_latexe_options_local: \keys_if_exist:nnF {#1} { unknown } { \keys_define:nn {#1} { unknown .code:n = { \msg_error:nnee { keyvalue } { option-unknown } { \l_keys_key_str } { \@currname } } } \AtEndOfPackage { \keys_define:nn {#1} { unknown .undefine: } } } \clist_map_inline:Nn \l_@@_latexe_options_clist { \tl_set:Nn \CurrentOption {##1} \keys_set:nn {#1} {##1} } \AtEndOfPackage { \cs_set_eq:NN \@unprocessedoptions \scan_stop: } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_latexe_options_global:n} % Global (class) options are handled differently for \LaTeXe{} packages % and classes. Hence this function is essentially a check on the current % file type. The initial test is needed as \LaTeXe{} allows variables to % be equal to \cs{scan_stop:}, which is forbidden in \LaTeX3 code. % \begin{macrocode} \cs_new_protected:Npn \@@_latexe_options_global:n #1 { \cs_if_eq:NNF \@classoptionslist \scan_stop: { \cs_if_eq:NNTF \@currext \@clsextension { \@@_latexe_options_class:n {#1} } { \bool_if:NT \l_@@_process_class_bool { \@@_latexe_options_package:n {#1} } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_latexe_options_class:n} % For classes, each option (stripped of any content after |=|) % is checked for existence as a key. If found, the option is added to % the combined list for processing. On the other hand, unused options % are stored up in \cs{@unusedoptionlist}. Before any of that, though, % there is a simple check to see if there is an |unknown| key. If there % is, then \emph{everything} will match and the mapping can be skipped. % \begin{macrocode} \cs_new_protected:Npn \@@_latexe_options_class:n #1 { \cs_if_free:cF { opt@ \@currname . \@currext } { \keys_if_exist:nnTF {#1} { unknown } { \clist_put_right:Nv \l_@@_latexe_options_clist { opt@ \@currname . \@currext } } { \clist_map_inline:cn { opt@ \@currname . \@currext } { \keys_if_exist:neTF {#1} { \@@_latexe_remove_equals:n {##1} } { \clist_put_right:Nn \l_@@_latexe_options_clist {##1} } { \clist_put_right:Nn \@unusedoptionlist {##1} } } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_latexe_options_package:n} % For global options when processing a package, the tasks are slightly % different from those for a class. The check is the same, but here % there is nothing to do if the option is not applicable. Each valid % option also needs to be removed from \cs{@unusedoptionlist}. % \begin{macrocode} \cs_new_protected:Npn \@@_latexe_options_package:n #1 { \clist_map_inline:Nn \@classoptionslist { \keys_if_exist:neT {#1} { \@@_latexe_remove_equals:n {##1} } { \clist_put_right:Nn \l_@@_latexe_options_clist {##1} \clist_remove_all:Nn \@unusedoptionlist {##1} } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_latexe_options_local:} % If local options are found, the are added to the processing list. % \LaTeXe{} stores options for each file in a macro which may or may not % exist, hence the need to use \cs{cs_if_exist:c}. % \begin{macrocode} \cs_new_protected:Npn \@@_latexe_options_local: { \cs_if_eq:NNF \@currext \@clsextension { \cs_if_exist:cT { opt@ \@currname . \@currext } { \exp_args:NNc \clist_put_right:NV \l_@@_latexe_options_clist { opt@ \@currname . \@currext } } } } % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_latexe_remove_equals:n} % \begin{macro}{\@@_latexe_remove_equals:w} % As the name suggests, this is a simple function to remove an equals % sign from the input. This is all wrapped up in an \texttt{n} function % so that there will always be a sign available. % \begin{macrocode} \cs_new:Npn \@@_latexe_remove_equals:n #1 { \@@_latexe_remove_equals:w #1 = \s_@@_stop } \cs_new:Npn \@@_latexe_remove_equals:w #1 = #2 \s_@@_stop { \exp_not:n {#1} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\ProcessKeysOptions} % \begin{macro}{\ProcessKeysPackageOptions} % The user macro are simply wrappers around the internal process. In % contrast to other similar packages, the module name is always required % here. % \begin{macrocode} \cs_new_protected:Npn \ProcessKeysOptions #1 { \bool_set_true:N \l_@@_process_class_bool \@@_latexe_options:n {#1} } \cs_new_protected:Npn \ProcessKeysPackageOptions #1 { \bool_set_false:N \l_@@_process_class_bool \@@_latexe_options:n {#1} } \@onlypreamble \ProcessKeysOptions \@onlypreamble \ProcessKeysPackageOptions % \end{macrocode} %\end{macro} %\end{macro} % % One message to give. % \begin{macrocode} \msg_new:nnnn { keyvalue } { option-unknown } { Unknown~option~'#1'~for~package~#2. } { LaTeX~has~been~asked~to~set~an~option~called~'#1'~ but~the~#2~package~has~not~created~an~option~with~this~name. } % \end{macrocode} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex