Is there a standard way to define mutually exclusive options in a package?
Could someone provide a simple example?
Currently I am mostly intrested in LaTeX2e but it would be nice to see a LaTeX3 implementation also.
Is there a standard way to define mutually exclusive options in a package?
Could someone provide a simple example?
Currently I am mostly intrested in LaTeX2e but it would be nice to see a LaTeX3 implementation also.
The kvoptions package, which provides key-value type options, also has the possibility to define complementary options:
\DeclareBoolOption{draft}
\DeclareComplementaryOption{final}{draft}
This generates an if-switch which is set to true by draft but to false by final.
If you however mean otherwise mutually exclusive options, e.g. three options where only one can be used, then you best define three if-switches which are set to true by its corresponding option. The options then either set the if-switches of the other options to false or raise an error or warning if one of these if-switches are already set to true.
% package 'foo'
% Example: three mutually options alpha, beta, gamma; last one
\newif\iffoo@alpha
\newif\iffoo@beta
\newif\iffoo@gamma
\DeclareOption{alpha}{\foo@alphatrue\foo@betafalse\foo@gammafalse}
\DeclareOption{beta}{\foo@alphafalse\foo@betatrue\foo@gammafalse}
\DeclareOption{gamma}{\foo@alphafalse\foo@betafalse\foo@gammatrue}
\ProcessOptions*% process options it the order the user provides them
% package body:
\iffoo@alpha
% alpha code
\fi
\iffoo@beta
% beta code
\fi
\iffoo@gamma
% gamma code
\fi
or with error messages:
\def\foo@mutopterr{%
\PackageError{foo}{Options 'alpha', 'beta' and 'gamma' are mutually exclusive.}{}%
}%
\DeclareOption{alpha}{%
\iffoo@beta\foo@mutopterr\fi
\iffoo@gamma\foo@mutopterr\fi
\foo@alphatrue\foo@betafalse\foo@gammafalse
}
\DeclareOption{beta}{%
\iffoo@alpha\foo@mutopterr\fi
\iffoo@gamma\foo@mutopterr\fi
\foo@alphafalse\foo@betatrue\foo@gammafalse
}
\DeclareOption{gamma}{%
\iffoo@alpha\foo@mutopterr\fi
\iffoo@beta\foo@mutopterr\fi
\foo@alphafalse\foo@betafalse\foo@gammatrue
}
Could someone provide a simple example?
The standard LaTeX document classes take onesided and twosided, draft and final, titlepage and notitlepage as options, each pair of which is mutually exclusive. There are also mutually exclusive options to specify the paper size and point size, but here there are multiple choices rather than two. The implementations of these options are a simple `\DeclareOption'. An example for the fictitious foo/nofoo option:
\newif\@foo
\@footrue % Makes foo the default; use \@foofalse if the default is nofoo
\DeclareOption{foo}{\@footrue}
\DeclareOption{nofoo}{\@foofalse}
A key question: How to address a user who specifies contradictory options? For example, specify twosided,final,onesided,draft as the options to one of the base LaTeX document classes and you will get (without complaints) a two-sided document formatted in final mode.
This is because the base LaTeX document classes use \ProcessOption to process the options. \ProcessOption walks through the options in the order the options are declared. If those classes had used \ProcessOption* instead of \ProcessOption, the consequences of twosided,final,onesided,draft would be a one-sided document in draft form. With \ProcessOption the winner in the case of conflict is the package itself while with \ProcessOption* the winner in case of conflict is the user of the package.
If you want the implementation to scold the user for specifying mutually exclusive options you will have to do something a bit more involved.
\ProcessOptions* instead of \ProcessOptions to have the last one win. The former process the options in the calling order while the later in the order of options declarations.
– Yan Zhou
Jun 20 '11 at 06:19
Below is an example that I use for a list of option where only one can be active. You can also specify a default option.
\newcommand\opt@select[1]{@#1@select}
\newcommand\opt@ifpre[1]{@#1@}
\newcommand\DeclareOptionList[3]{%
\@namedef{\opt@select{#1}}{#3}%-- default
\edef\opt@list{\zap@space#2 \@empty}%
\@for\opt@item:=\opt@list\do{%
\expandafter\newif\csname if\opt@ifpre{#1}\opt@item\endcsname
\edef\opt@temp{%
\noexpand\DeclareOption{\opt@item}%
{\def\expandafter\noexpand\csname\opt@select{#1}\endcsname{\opt@item}}}%
\opt@temp}}
\newcommand\SetListOption[1]{%
\def\opt@set{\@nameuse{\opt@select{#1}}}%
\@nameuse{\opt@ifpre{#1}\opt@set true}}
\newcommand\IfListOption[3]{%
\csname if\opt@ifpre{#1}#2\endcsname #3\fi}
%____ Process options ___________________________________________
\DeclareOptionList{layout}{goldenblock,a5block,wideblock,stdblock}{goldenblock}
\DeclareOptionList{fonts}{cm,charter,fourier,times}{cm}
\ProcessOptions*\relax
\AtEndOfPackage{\let\@unprocessedoptions\relax}
\SetListOption{layout}%--- Activate layout option
\SetListOption{fonts}%---- Activate font option
%____ Page Layout _______________________________________________
\RequirePackage[a4paper]{geometry}
\IfListOption{layout}{goldenblock}{%
\geometry{text={0.6667\paperwidth, 1.0787\paperwidth}}%
\geometry{hmarginratio=1:1}%
\geometry{vmarginratio=2:3}%
\geometry{marginparwidth=50pt}}
\IfListOption{layout}{a5block}{%
\geometry{text={0.5\paperheight, \paperwidth}}%
\geometry{hmarginratio=1:1}%
\geometry{vmarginratio=2:3}%
\geometry{marginparwidth=50pt}}
\IfListOption{layout}{wideblock}{%
\geometry{margin=25mm}%
\geometry{marginparwidth=50pt}}
\IfListOption{layout}{stdblock}{}%----- Latex default type block ----
%____ Fonts _________________________________________________________
\IfListOption{fonts}{cm}{%
\RequirePackage[T1]{fontenc}
\RequirePackage{textcomp}
\RequirePackage{lmodern}
\RequirePackage{bm}}
:
\countregister initialized to-1instead? The three (or more) options would simply be 1, 2, 3, (etc.) and when using them, you simply use\ifcase. To ensure that they're mutually exclusive, you just use a single\ifnumcheck. – TH. Jun 20 '11 at 10:17defaultoption from the setalpha,betaandgamma? – Dror Aug 27 '13 at 10:38