From f68189f71d0a9a9a67cba3d61a6d3a1ce35ec832 Mon Sep 17 00:00:00 2001
From: Karl Berry <karl@freefriends.org>
Date: Sun, 6 Dec 2015 23:51:36 +0000
Subject: options (6dec15)

git-svn-id: svn://tug.org/texlive/trunk@39030 c570f23f-e606-0410-a88d-b1316a301751
---
 Master/texmf-dist/tex/latex/options/options.sty | 1387 +++++++++++++++++++++++
 1 file changed, 1387 insertions(+)
 create mode 100644 Master/texmf-dist/tex/latex/options/options.sty

(limited to 'Master/texmf-dist/tex/latex/options/options.sty')

diff --git a/Master/texmf-dist/tex/latex/options/options.sty b/Master/texmf-dist/tex/latex/options/options.sty
new file mode 100644
index 00000000000..ebd0311e27d
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/options/options.sty
@@ -0,0 +1,1387 @@
+%---------------------------------------------------------------------------
+% Copyright 2015 Daan Leijen, Microsoft Corporation.
+%
+% This work may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3
+% of this license or (at your option) any later version.
+% The latest version of this license is in
+%   http://www.latex-project.org/lppl.txt
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.  
+%---------------------------------------------------------------------------
+\NeedsTeXFormat{LaTeX2e}[1995/12/01]
+
+\ProvidesPackage{options}[2015/03/01, Daan Leijen, Provides convenient path-value (or key-value) options]
+\RequirePackage{etoolbox}
+\RequirePackage{xcolor}
+
+\newif\ifopt@debug
+\DeclareOption{debug}{\opt@debugtrue}
+\ProcessOptions\relax
+
+% --------------------------------------------------------
+% make the package robust agains catcode changes of = and ,
+% --------------------------------------------------------
+\edef\opt@restore@catcodes{%
+  \catcode`\noexpand\=\the\catcode`\=\relax
+  \catcode`\noexpand\,\the\catcode`\,\relax
+  \let\noexpand\opt@catcodes\relax
+}
+\catcode`\=12\relax
+\catcode`\,12\relax
+
+
+% --------------------------------------------------------
+% Extensions to etoolbox
+% --------------------------------------------------------
+
+\providecommand*\@swaparg[2]{#2{#1}}
+\providecommand*\expandnext[2]{\expandafter\@swaparg\expandafter{#2}{#1}}
+
+\providecommand*\@swaptwo[2]{#2#1}
+\providecommand*\expandnextcmds[2]{\expandafter\@swaptwo\expandafter{#2}{#1}}
+
+% unsafe expand next if the command is a single token..
+\providecommand*\expandnextsingle[2]{\expandafter#1\expandafter{#2}}
+
+\providecommand*\eifstrequal[1]{\expandnextsingle\ifstrequal{#1}}
+\providecommand*\eifblank[1]{\expandnextsingle\ifblank{#1}}
+
+\providecommand*\ontoggle[2]{\iftoggle{#1}{#2}{}}
+
+\providerobustcmd*\providelength[1]{\ifdef{#1}{}{\newlength#1}}
+\providerobustcmd*\csnewlength[1]{\expandafter\newlength\csname #1\endcsname}
+\providerobustcmd*\csprovidelength[1]{\ifcsdef{#1}{}{\expandafter\newlength\csname #1\endcsname}}
+\providerobustcmd*\cssetlength[2]{\expandafter\setlength\csname #1\endcsname{#2}}
+
+% --------------------------------------------------------
+% Basic option commands
+% \option{<path>} returns the value of a path
+% \letoption{<path>}\cmd  let's \cmd to the value of <path>
+% --------------------------------------------------------
+
+\newcommand*\optionname[1]{optk@#1}
+\newcommand*\option[1]{\csname optk@#1\endcsname}
+\newcommand*\letoption[2]{\expandafter\let\expandafter#2\csname optk@#1\endcsname}
+
+% \letoption@ will not be redefined for debugging and can be used to test if an option exists
+\let\letoption@\letoption 
+
+% --------------------------------------------------------
+% options, optionsalso
+% main path setting routine
+% --------------------------------------------------------
+
+\newif\ifopt@allowsearch      % allow searching along search-also handlers
+\newif\ifopt@ignoreunknown    % ignore unknown options?
+\newif\ifopt@unknownwarnonly  % issue just a warning on an unknown option? (instead of an error)
+
+% process options together with remaining ones from a previous run
+\newrobustcmd*\optionswithremaining[1]{%
+  \letoptionlist{/options/remaining}\opt@savedremaining
+  \options{#1}%
+  %\typeout{now process: \meaning\opt@savedremaining, in default: \option@defaultpath}%
+  \expandnextsingle\optionsalso{\opt@savedremaining}%
+}
+
+% process options
+\newrobustcmd*\options{%
+  \def\option@defaultpath{}%
+  \opt@allowsearchtrue%
+  \opt@ignoreunknownfalse%
+  \opt@unknownwarnonlyfalse%
+  \optionsalso%
+}
+
+% track nesting level of options (due to calls to options in an argument)
+\newif\ifopt@nested
+\newcount\opt@nesting
+
+% Process options in the context of an other options call
+% For efficiency, only save state if nested
+\newrobustcmd*\optionsalso[1]{%
+  \ifopt@nested
+    \optionsalso@save{#1}% save state in a nested context for chained handlers
+  \else
+    \opt@nestedtrue
+    \opt@parse#1,\opt@stop,%
+    \opt@nestedfalse
+  \fi
+}
+
+% this saves and restores any nested state: for now only about chained handlers
+\newrobustcmd*\optionsalso@save[1]{%
+  \opt@savestate{\the\opt@nesting}%
+  \advance\opt@nesting 1\relax
+  \opt@parse#1,\opt@stop,%
+  \advance\opt@nesting -1\relax
+  \opt@restorestate{\the\opt@nesting}%
+}
+
+\newrobustcmd*\opt@savestate[1]{%
+  \cslet{option@handlernext#1}\option@handlernext%
+  \cslet{option@handlerpath#1}\option@handlerpath%
+  \cslet{optionvalue#1}\optionvalue%
+  \def\option@handlernext{}%
+  \def\option@handlerpath{}%  
+}
+
+\newrobustcmd*\opt@restorestate[1]{%
+  \letcs\option@handlernext{option@handlernext#1}%
+  \letcs\option@handlerpath{option@handlerpath#1}%
+  \letcs\optionvalue{optionvalue#1}%
+}
+
+% Qualified options -- mostly for here for compatibility with pgfqkeys
+\newrobustcmd*\qoptions[2]{%
+  \def\option@defaultpath{#1}%
+  \opt@allowsearchtrue%
+  \opt@ignoreunknownfalse%
+  \optionsalso{#2}%
+}
+
+% Qualified optionsalso
+\newrobustcmd*\qoptionsalso[2]{%
+  \def\option@defaultpath{#1}%
+  \optionsalso{#2}%  
+}
+
+%-----------------------------------------------------------------------
+% The main option processing
+%
+% For an option <option> we may have these values:
+% <option>    : the value read by \option{<option>}
+%   /@code    : the code invoked on assignment (use option@invoke to invoke explicitly), gets \optionvalue
+%   /@cmdN    : command handlers invoked by code with arguments from \optionvalue
+%   /@type    : the type of value (not set for pure code values)
+%   /@unknown : an unknown handler for this path
+%     /@code  : taking 2 arguments: path and value
+%   /@searchalso: the other paths needed to be search for this path
+%     /@code
+%
+% Handlers start with a "." in their name; the handlers are found in: /handlers/<handlername>
+% Special handlers are defined in: /handlers/special/<char>
+% If a path starts with <char> it is invoked; just like first-char-syntax in pgfkeys.
+%-----------------------------------------------------------------------
+
+% this is used if no argument is given
+% define as relax, this makes it unique but also safe against infinite expansion
+\def\optionnovalue{\relax}
+
+% opt@stop is used to stop argument processing in tex \def's with patterns
+\let\opt@stop\relax
+
+% The main parsing of options
+% This code is quite expanded to make it as efficient as possible.
+% It is based on the original code by David Carlisle in the standard latex "keyval" package.
+\def\opt@parse#1,{%
+ \ifx\opt@stop#1\@empty\else
+  \opt@parse@arg#1==\opt@stop
+  \expandafter\opt@parse\fi}
+
+\def\opt@parse@arg#1=#2=#3\opt@stop{%
+  \opt@trimdef\option@rawpath{#1}%
+  \ifx\@empty#3\@empty%
+    \let\optionvalue\optionnovalue
+  \else      
+    \opt@trimdef\optionvalue{#2}%
+  \fi
+  \ifx\option@rawpath\@empty
+    \ifx\optionvalue\optionnovalue\else\optionerror@nopath{#2}\fi
+  \else    
+    % try path directly
+    \expandafter\opt@setcodepath@\option@rawpath\opt@stop%
+    \ifx\opt@codepath\relax
+      \opt@handle{#1}{#2}% not directly found, try handlers, search etc.
+    \fi
+    % now \optionvalue is defined; invoke the /@code
+    \opt@codepath%
+    \ifx\option@handlernext\@empty\else\optionerror@handler\fi 
+  \fi
+}
+
+% Phase 2: look for a handler or search along the path
+\newrobustcmd*\opt@handle[2]{%
+  % not directly found..
+  \opt@setoptionpath{\option@rawpath}% create full option@path applying the default path
+  \option@gethandler\option@path% defines option@handlerpath & option@handler
+  \ifx\option@handler\@empty
+    % search path
+    \ifopt@allowsearch
+      \opt@searchalso{\option@path}%
+    \fi
+  \else
+    % handler
+    \letoption@{/handlers/\option@handler/@code}\opt@codepath
+  \fi
+  \ifx\opt@codepath\relax
+    \opt@handle@specials{#1}{#2}%
+  \fi
+}
+
+% Set opt@codepath from a raw path taking the default path into account
+\newcommand\opt@setcodepath[1]{\expandafter\opt@setcodepath@#1\opt@stop}
+\def\opt@setcodepath@#1#2\opt@stop{\ifx#1/\relax\letoption@{#1#2/@code}\opt@codepath\else\letoption@{\option@defaultpath/#1#2/@code}\opt@codepath\fi}
+
+% Set option@path from a raw path taking the default path into account
+\newcommand\opt@setoptionpath[1]{\expandafter\opt@setoptionpath@#1\opt@stop}
+\def\opt@setoptionpath@#1#2\opt@stop{\ifx#1/\relax\edef\option@path{#1#2}\else\edef\option@path{\option@defaultpath/#1#2}\fi}
+
+
+% Phase 3: look for a special syntax handler, or invoke the unknown handlers
+\newrobustcmd*\opt@handle@specials[2]{%
+  % special handler?
+  \edef\opt@first{\expandafter\option@firstletterof@\option@rawpath\opt@stop}%
+  \letoption@{/handlers/special/\opt@first/@code}\opt@codepath    
+  \ifx\opt@codepath\relax
+    % still not found: invoke unknown handler
+    \ifopt@ignoreunknown
+      \opt@collectunknown{#1}{#2}% expects \optionvalue to be defined
+    \else
+      \opt@unknown{\option@path}%
+    \fi
+  \else 
+    % it is a special handler
+    \ifx\optionvalue\optionnovalue
+      \let\optionvalue\option@rawpath%
+    \else
+      \optionerror{\option@rawpath}{special options cannot take an argument ("\meaning\optionvalue")}%
+    \fi
+  \fi
+}
+
+% Space gobbling; basically unchanged from the original definition in the keyval package by David Carlisle
+% note: takes off one layer of braces
+\newrobustcmd\opt@define@trimdef[1]{%
+  \long\def\opt@trimdef##1##2{%
+    \futurelet\opt@firsttoken\opt@trim@##2\opt@stop\opt@stop#1\opt@stop\relax##1}%
+  \def\opt@trim@{%
+    \ifx\opt@firsttoken\opt@sptoken%
+      \expandafter\opt@trim@left%
+    \else%
+      \expandafter\opt@trim@left\expandafter#1% add space token since sp@b removes one 
+    \fi}%
+  \long\def\opt@trim@left#1##1 \opt@stop{\opt@trim@right##1}%
+}
+\opt@define@trimdef{ }% define trimdef with a space as argument
+\long\def\opt@trim@right#1\opt@stop#2\relax#3{\edef#3{\unexpanded{#1}}}
+{\def\:{\global\let\opt@sptoken= } \: }
+
+
+% --------------------------------------------------------
+% Searching
+% --------------------------------------------------------
+
+% search a relative path: <default path><search path>
+\newrobustcmd*\opt@searchforpath[2]{%
+  \option@ifisabsolute{#2}%
+   {\letoption@{#2/@code}\opt@codepath}%
+   {\letoption@{#1#2/@code}\opt@codepath% use default path
+    \ifx\opt@codepath\relax
+      \ifopt@allowsearch\else
+        \opt@searchalso{#1#2}%
+      \fi    
+    \fi}%
+}
+
+% search an absolute path
+% this is called by search-also handlers.
+\newrobustcmd*\opt@searchforabspath[1]{%
+  \letoption@{#1/@code}\opt@codepath
+  \ifx\opt@codepath\relax
+    \ifopt@allowsearch\else
+      \opt@searchalso{#1}%
+    \fi
+  \fi
+}
+
+% \opt@searchalso: invoked to search for a path: set \opt@codepath if a match is found
+%
+% note: we can nest searches without grouping
+% because they all use the same "\opt@do@search" (option@searchalsodo) and
+% all need to break once the inner one breaks 
+\newrobustcmd*\opt@searchalso[1]{%
+  \option@foreachparent\opt@do@search{#1}%
+}
+\newrobustcmd*\opt@do@search[3]{% {<root>}{<subpath>}{<name>}
+  \letoption@{#1/@searchalso/@code}\opt@temp
+  \ifx\opt@temp\relax\else
+    \edef\option@searchpath{#2#3}% subpath
+    \opt@temp% invoke search routine
+    \ifx\opt@codepath\relax\else\opt@break\fi% on found: break loop
+  \fi
+}
+
+% --------------------------------------------------------
+% Unknown handler search
+% --------------------------------------------------------
+
+% invoked on unknown path: set \opt@codepath to the unknown handler (with option@unknownpath)
+\newrobustcmd*\opt@unknown[1]{%
+  %\typeout{found unknown: #1}%
+  \def\opt@do@unknown##1##2##3{%
+    \letoption@{##1/@unknown/@code}\opt@codepath
+    \ifx\opt@codepath\relax\else
+      \edef\option@unknownpath{#1}% full path
+      \edef\option@unknownsubpath{##2##3}% subpath
+      \expandnext{\opt@addarg{#1}}{\optionvalue}% set optionvalue to two arguments: the path and the original value
+      \opt@break%
+    \fi%
+  }%
+  \option@foreachparent\opt@do@unknown{#1}%
+}
+\newrobustcmd*\opt@addarg[2]{\edef\optionvalue{\unexpanded{{#1}{#2}}}}%
+
+% invoked when unknown option needs to be saved (and ignored)
+\newrobustcmd*\opt@collectunknown[2]{%
+  \ifx\optionvalue\optionnovalue
+    \option@push{/options/remaining}{#1}%
+  \else
+    \option@push{/options/remaining}{#1={#2}}%
+  \fi
+}
+
+% --------------------------------------------------------
+% Handlers' splitting and chaining
+% --------------------------------------------------------
+
+% \option@gethandler{path}: split off the part after the "/.", sets option@handlerpath and option@handler and option@handlernext
+\def\option@gethandler#1{\expandafter\option@gethandler@#1/././.\opt@stop}
+\def\option@gethandler@#1/.#2/.#3/.#4\opt@stop{%
+  \def\option@handler{#2}%
+  \ifx\option@handler\@empty\else
+      \def\option@handlerpath{#1}%
+      \def\option@handler{#2}%
+      \def\option@handlernext{#3}%
+  \fi
+}
+\def\option@handlerpath{}
+\def\option@handlernext{}
+
+\newrobustcmd*\option@chainempty{\let\optionvalue\optionnovalue\option@chainonly}
+\newrobustcmd*\option@chainonly{\ifx\option@handlernext\@empty\else\option@chain\fi}
+\newrobustcmd*\option@chain{%
+  \ifx\option@handlernext\@empty
+    % we are done, invoke the option itself
+    \letoption@{\option@handlerpath/@code}\opt@codepath
+    \ifx\opt@codepath\relax
+      \opt@unknown{\option@handlerpath}%
+    \fi
+  \else
+    % invoke the next handler
+    %\typeout{call next handler: \option@handlerpath, \option@handlernext, \optionvalue}%
+    \edef\opt@temp{\option@handlerpath/.\option@handlernext}%
+    \option@gethandler{\opt@temp}%
+    \letoption@{/handlers/\option@handler/@code}\opt@codepath
+    \ifx\opt@codepath\relax
+      \opt@unknown{/handlers/\option@handler}%
+    \fi
+  \fi
+  \opt@codepath
+}
+
+% --------------------------------------------------------
+% Path splitting
+% --------------------------------------------------------
+
+% \option@isabsolute{path}: check if path starts with /
+\def\ifoptionisabsolute#1{\expandafter\ifoptionisabsolute@#1\opt@stop}
+\def\ifoptionisabsolute@#1#2\opt@stop{\ifx#1/\relax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}%
+
+% \option@splitroot{path}: split off the first directory of a path into \option@root 
+% option@splitroot{/foo/bar} -> foo 
+% option@splitroot{/foo}  -> foo
+\newrobustcmd*\option@splitroot[1]{\expandafter\option@splitroot@#1//\opt@stop}
+\def\option@splitroot@#1/#2/#3\opt@stop{%
+  \def\option@root{#1}%
+  \ifx\option@root\@empty
+    \def\option@root{#2}%
+  \fi
+}
+
+% \option@splitpath{path}: \option@path and \option@name
+% \option@splitpath{/foo/bar/baz} -> /foo/bar baz
+\newrobustcmd*\option@splitpath[1]{%
+  \let\option@path\@empty
+  \ifoptionisabsolute{#1}{%
+    \def\opt@do@split##1##2##3{%
+      \edef\option@path{##1/}%
+      \edef\option@name{##3}%
+      \opt@break
+    }%
+    \option@foreachparent\opt@do@split{#1}%
+  }{\edef\option@name{#1}}%
+}
+
+
+% \option@foreachparent\<do>{<path>}  basic routine for iterating over path components
+% applies \<do> to each parent path. todo: can we optimize this routine more for the searchalso?
+%   /foo/bar/baz  -> \<do>{/foo/bar}{}{baz} \<do>{/foo}{bar/}{baz} \<do>{}{foo/bar/}{baz} 
+\newrobustcmd*\option@foreachparent[2]{%
+  \let\opt@donext#1%
+  \expandafter\opt@foreachparent@#2/\opt@stop\opt@stop%
+  \opt@donext{}{\option@subpath}{\option@name}%
+}
+
+\newrobustcmd*\opt@break{\def\opt@donext##1##2##3{}}
+
+\def\opt@foreachparent@/#1/#2\opt@stop#3\opt@stop{% #3 is the current root
+  \def\opt@temp{#2}%
+  \ifx\opt@temp\@empty% final path
+    \def\option@name{#1}%
+    \def\option@subpath{}%
+  \else
+    \opt@foreachparent@/#2\opt@stop#3/#1\opt@stop% recurse first
+    \opt@donext{#3/#1}{\option@subpath}{\option@name}%
+    \edef\option@subpath{#1/\option@subpath}%
+  \fi
+}
+
+
+% --------------------------------------------------------
+% Errors
+% --------------------------------------------------------
+\newrobustcmd*\optionwarning[2]{%
+  \eifblank{\option@handler}{\def\opt@temp{}}{\def\opt@temp{(in ".\option@handler") }}%
+  \PackageWarning{options}{option "#1": \opt@temp #2}{}}
+
+\newrobustcmd*\optionerror[2]{%
+  \eifblank{\option@handler}{\def\opt@temp{}}{\def\opt@temp{(in ".\option@handler") }}%
+  \PackageError{options}{option "#1": \opt@temp #2}{}}
+
+\newrobustcmd*\optionerror@expect[2]{\optionerror{#1}{unexpected "\optionvalue" (expecting #2)}}
+\newrobustcmd*\optionerror@toomany[2]{\optionerror{#1}{too many arguments (expecting #2)}}
+\newrobustcmd*\optionerror@noarg[1]{\optionerror{#1}{does not take an argument}}
+\newrobustcmd*\optionerror@needarg[1]{\optionerror{#1}{requires an argument}}
+
+\newrobustcmd*\optionerror@nopath[1]{\optionerror{?}{value without option path: "#1"}}
+\newrobustcmd*\optionerror@handler[1]{\optionerror{\option@rawpath}{handler ".\option@handlernext" is not allowed to follow the previous handlers}}%
+
+\newrobustcmd*\option@ensurefree[1]{\ifoptiondefined{#1}{\optionerror{#1}{already defined}}{}}   
+\newrobustcmd*\option@ensuredefined[1]{\ifoptiondefined{#1}{}{\optionerror{#1}{unknown option}}}
+
+
+% --------------------------------------------------------
+% Basic option setting
+% --------------------------------------------------------
+
+\newrobustcmd*\edefoption[2]{\protected@edef#2{\option{#1}}}%
+
+\newrobustcmd*\option@set[2]{\csdef{optk@#1}{#2}}
+\newrobustcmd*\option@let[2]{\cslet{optk@#1}#2}
+
+\newrobustcmd*\option@def[1]{\csdef{optk@#1}}
+\newrobustcmd*\option@undef[1]{\csundef{optk@#1}}
+
+\newrobustcmd*\option@eset[2]{\expandnext{\option@set{#1}}{#2}}
+\newrobustcmd*\option@xset[2]{\protected@edef\opt@temp{#2}\option@let{#1}\opt@temp}
+
+\newrobustcmd*\option@appto[2]{\csappto{optk@#1}{#2}}
+\newrobustcmd*\option@preto[2]{\cspreto{optk@#1}{#2}}
+
+\newcommand*\ifoptiondefined[1]{\ifcsdef{optk@#1}}
+\newcommand*\ifoptionvoid[1]{\ifcsvoid{optk@#1}}
+\newcommand*\ifoptioncmd[1]{\ifcsparam{optk@#1}}
+
+\newrobustcmd*\ifoptionequal[2]{%
+  \edefoption{#1}\opt@temp
+  \eifstrequal{\opt@temp}{#2}%
+}
+
+\newrobustcmd*\ifoptionblank[2]{%
+  \edefoption{#1}\opt@temp
+  \eifblank{\opt@temp}{#2}%
+}
+
+\newcommand*\ifoptiontype[2]{%
+  \letoptiontype{#1}\opt@type    
+  \eifstrequal{\opt@type}{#2}%
+}
+\newcommand*\ifoptioniscode[1]{%
+  \let\opt@next\@secondoftwo%
+  \letoption@{#1/@code}\opt@code
+  \letoption@{#1}\opt@value
+  \ifx\opt@code\opt@value
+    \let\opt@next\@firstoftwo
+  \else
+    \letoptiontype{#1}\opt@type
+    \eifstrequal{\opt@type}{code}%
+      {\let\opt@next\@firstoftwo}{}%
+  \fi
+  \opt@next
+}
+
+\newcommand*\letoptiontype[2]{%
+  \letoption@{#1/@type}#2%
+  \ifx#2\relax\def#2{code}\fi
+}%
+
+\newcommand*\optionparamcount[1]{%
+  \ifoptiondefined{#1/@cmd1}{1}{%
+  \ifoptiondefined{#1/@cmd2}{2}{%
+  \ifoptiondefined{#1/@cmd3}{3}{%
+  \ifoptiondefined{#1/@cmd4}{4}{%
+  \ifoptiondefined{#1/@cmd5}{5}{%
+  \ifoptiondefined{#1/@cmdx}{x}{%
+  0%
+  }}}}}}%
+}
+
+\newcommand*\optionshowtype[1]{%
+  \letoptiontype{#1}\opt@type%
+  \eifstrequal{\opt@type}{code}%
+    {\option@font@special{cmd}$_\optionparamcount{#1}$}%
+    {\option@font@special{\opt@type}}%
+}
+
+% Set the current color from a color options.
+% Keeps color unchanged if the color name was blank.
+\newcommand*\optioncolor[1]{\ifoptioncolortransparent{#1}{}{\color{#1}}}
+\newcommand*\optiontextcolor[2]{\ifoptioncolortransparent{#1}{#2}{\textcolor{#1}{#2}}}
+\newcommand*\optioncolorbox[2]{\ifoptioncolortransparent{#1}{#2}{\colorbox{#1}{#2}}}
+
+\newcommand*\ifoptioncolortransparent[3]{%
+  \ifoptionblank{#1}{#2}{%
+    \ifoptiontype{#1}{color expr}{%
+      \edefoption{#1}\opt@color
+      \expandnext{\opt@colorlet{#1}}{\opt@color}%
+    }{}%
+    #3
+  }%
+}
+
+
+% convert dimension option into number in pt for use in picture
+\newcommand*\opt@unit[1]{\strip@pt\dimexpr#1\relax}
+\newcommand*\optionunit[1]{\opt@unit{\option{#1}}}
+
+% --------------------------------------------------------
+% Comma seperated values
+% --------------------------------------------------------
+
+\newcommand\option@headof[1]{\option@headof@#1,\opt@stop}%
+\def\option@headof@#1,#2\opt@stop{#1}%
+
+\providerobustcmd*\option@ifanyof[2]{%
+  \let\opt@do@next\@secondoftwo
+  \edef\opt@temp{#1}%
+  \def\opt@do@anyof##1{\eifstrequal{\opt@temp}{##1}{\let\opt@do@next\@firstoftwo\listbreak}{}}%
+  \expandnext{\forcsvlist\opt@do@anyof}{#2}%
+  \opt@do@next
+}
+
+\newrobustcmd*\ifoptionanyof[2]{\option@ifanyof{\option{#1}}{#2}}
+
+\newcount\opt@idx
+\providerobustcmd*\option@findidx[3]{%
+  \opt@idx=0\relax
+  \def#3{-1}%
+  \edef\opt@temp{#1}%
+  \def\opt@do@findidx##1{\eifstrequal{\opt@temp}{##1}{\edef#3{\the\opt@idx}\listbreak}{\advance\opt@idx 1\relax}}%
+  \expandnext{\forcsvlist\opt@do@findidx}{#2}%
+}
+
+% return the first letter of the argument or ' ' (space) if the input was empty. Does not expand the argument.
+\providecommand*\option@firstletterof[1]{\eifblank{#1}{ }{\expandafter\option@firstletterof@#1\opt@stop}}
+\def\option@firstletterof@#1#2\opt@stop{#1}
+
+
+% --------------------------------------------------------
+% Lists
+% --------------------------------------------------------
+
+\newrobustcmd*\option@setnil[1]{\option@set{#1}{}}
+\newrobustcmd*\option@push[2]{\listcsadd{optk@#1}{#2}}
+\newrobustcmd*\option@epush[2]{\listcseadd{optk@#1}{#2}}%
+\newrobustcmd\optionlistdo[2]{\def\opt@@do##1{#2}\forlistcsloop{\opt@@do}{optk@#1}}
+
+\newrobustcmd*\option@setlist[2]{\option@setnil{#1}\option@concat{#1}{#2}}
+\newrobustcmd*\option@concat[2]{%
+  \def\opt@do@concat##1{\option@push{#1}{##1}}%
+  \expandnext{\forcsvlist\opt@do@concat}{#2}%
+}
+\newcommand*\letoptionlist[2]{%
+  \def#2{}%
+  \optionlistdo{#1}{%
+    \ifdefempty#2%
+      {\def#2{##1}}%
+      {\appto#2{,##1}}%
+  }%
+}
+\newcommand*\optionlist[1]{%
+  \let\opt@comma\@empty%
+  \optionlistdo{#1}{%
+    \opt@comma##1%
+    \ifx\opt@comma\@empty
+      \def\opt@comma{,}%
+    \fi
+  }%
+}
+
+\let\ifoptionnil\ifoptionvoid
+\newrobustcmd*\ifoptioncontains[2]{\xifinlistcs{#2}{optk@#1}}
+\newrobustcmd*\option@pushifnew[2]{\ifoptioncontains{#1}{#2}{}{\option@push{#1}{#2}}}
+
+
+% --------------------------------------------------------
+% Choices: these functions are used for the choice type
+% --------------------------------------------------------
+
+% find a choice: sets opt@choicename, opt@choicevalue, and opt@choiceord
+\newcount\opt@choiceord
+\newcommand*\opt@findchoice[2]{% {<name>}{<option>}
+  \opt@choiceord=0\relax
+  \def\opt@choicevalue{}%
+  \def\opt@choicename{}%
+  \def\opt@do@choice##1{\opt@do@choice@##1\opt@stop}%
+  \def\opt@do@choice@##1=##2\opt@stop{%
+    \ifstrequal{##1}{#1}{%
+      \def\opt@choicename{##1}%
+      \def\opt@choicevalue{##2}%
+      \listbreak
+    }%
+    {\advance\opt@choiceord 1\relax}%
+  }%
+  \forlistcsloop\opt@do@choice{\optionname{#2/@choices}}%
+  \ifx\opt@choicename\@empty%
+    \opt@choiceord=-1\relax
+  \fi
+}
+
+% get choice list as comma separated name list
+\newcommand\letoptionchoices[2]{% {<option>}{\<macro>}
+  \def#2{}%
+  \def\opt@do@choice##1{\opt@do@choice@##1\opt@stop}%
+  \def\opt@do@choice@##1=##2\opt@stop{%
+    \ifx#2\@empty
+      \def#2{##1}%
+    \else
+      \appto#2{,##1}%
+    \fi
+  }%
+  \forlistcsloop\opt@do@choice{\optionname{#1/@choices}}%
+}%
+
+% parse choices into a list of elements "choice=value". Set  \opt@choices and \opt@firstchoicename
+\newcommand*\opt@choices@parse[2]{% {<option>}{<user list>}
+  \def\opt@choices{}%
+  \def\opt@firstchoicename{}%
+  \edef\opt@choicepath{#1}%
+  \opt@choice@foreach#2,\opt@stop,\relax
+  %\typeout{choice list: \opt@choices}%
+}
+
+\def\opt@choice@foreach#1,{%
+ \ifx\opt@stop#1\@empty\else
+  \opt@choice@item#1==\opt@stop
+  \expandafter\opt@choice@foreach\fi}
+
+\def\opt@choice@item#1=#2=#3\opt@stop{%
+  \opt@trimdef\opt@choicename{#1}%
+  \ifx\@empty#3\@empty%
+    \let\opt@choicevalue\opt@choicename% default is the name itself
+  \else      
+    \opt@trimdef\opt@choicevalue{#2}%
+  \fi
+  \expandnext{\expandnextsingle\opt@choice@push{\opt@choicename}}{\opt@choicevalue}%
+}
+
+\newcommand*\opt@choice@push[2]{%
+  %\typeout{parse choice: #1={#2}}%
+  \listadd\opt@choices{#1={#2}}%
+  \ifx\opt@firstchoicename\@empty
+    \def\opt@firstchoicename{#1}%
+  \fi
+}
+
+
+% --------------------------------------------------------
+% Invoke
+% --------------------------------------------------------
+
+\newcommand*\option@xinvoke[2]{%
+  \protected@edef\opt@temp{#2}%
+  \expandnext{\option@invoke{#1}}{\opt@temp}%
+}%
+\newcommand*\option@einvoke[2]{%
+  \expandnext{\option@invoke{#1}}{#2}%
+}%
+\newcommand*\option@invoke[2]{%
+  \option@ensuredefined{#1}%
+  \def\optionvalue{#2}%
+  \option{#1/@code}%
+}%
+\newcommand*\option@invokedefault[1]{%
+  \option@ensuredefined{#1}%
+  \let\optionvalue\optionnovalue%
+  \option{#1/@code}%
+}%
+
+
+% --------------------------------------------------------
+% Record metadata
+% --------------------------------------------------------
+
+\newrobustcmd*\option@addpathinfo[1]{%
+  \def\opt@do@add##1##2##3{%
+    \ifoptiondefined{##1/@names}{}{%
+      \option@setnil{##1/@names}\option@setnil{##1/@paths}%
+    }%
+    \eifblank{##2}%
+      {\expandnext{\option@pushifnew{##1/@names}}{##3}%
+       %\typeout{path "##1/@names": add "##3": \option{##1/@names}}%      
+      }%
+      {\option@splitroot{##2}%
+       \expandnext{\option@pushifnew{##1/@paths}}{\option@root}%
+       %\typeout{path "##1/@paths": add "\option@root"; \option{##1/@paths}}%
+      }%
+  }%
+  \option@foreachparent\opt@do@add{#1}%
+}
+
+% --------------------------------------------------------
+% Basic definitions of options
+% --------------------------------------------------------
+\def\option@patch@pre{}
+\def\option@patch@post{}
+
+\newrobustcmd*\optionnewcode{\@ifstar{\optionnewcode@{true}}{\optionnewcode@{false}}}
+\newrobustcmd*\optionnewcode@[3]{%*[]
+  %\typeout{define cmd: #2}%  
+  \option@ensurefree{#2}%
+  \option@splitpath{#2}% sets option@path, and option@name
+  \eifblank{\option@path}{%
+    \optionerror{#2}{no valid option name specified. Option definitions must start with a forward slash (i.e. "/path/<name>")}%
+  }{}%
+  \option@addpathinfo{#2}%
+  \ifbool{#1}%  noarg? expand out for efficiency
+   {\csdef{optk@#2/@code}{%
+      \ifx\optionvalue\optionnovalue\else\optionerror@noarg{#2}\fi
+      \option@patch@pre% hook to patch in extra checking code
+      #3%
+      \option@patch@post% hook for post code.. generally unsafe due to chained handlers
+    }}%
+   {\csdef{optk@#2/@code}{%
+      \ifx\optionvalue\optionnovalue
+        \letoption@{#2/@def}\optionvalue%
+        \ifx\optionvalue\relax\optionerror@needarg{#2}\fi
+      \fi
+      \option@patch@pre
+      #3%
+      \option@patch@post
+    }}%
+  \csletcs{optk@#2}{optk@#2/@code}% point at first to the cmd
+}
+
+% define handler code; such code takes the expanded option@handlerpath and optionvalue as arguments 
+\newrobustcmd*\optionnewhandler{\@ifstar{\optionnewhandler@{true}}{\optionnewhandler@{false}}}
+\newrobustcmd*\optionnewhandler@[3]{%
+  \option@ensurefree{#2}%
+  \option@def{#2/@cmd2}##1##2{#3}%
+  \optionnewcode@{#1}{#2}{\expandnext{\expandnext{\option{#2/@cmd2}}{\option@handlerpath}}{\optionvalue}}\relax%
+}
+
+
+% --------------------------------------------------------
+% Add pre/post processing to an option
+% note: patchcmd leaves some spaces behind.. can we switch to appto?
+% --------------------------------------------------------
+
+\newrobustcmd*\optionprependcode[2]{%
+  \option@ensuredefined{#1}%
+  \expandafter\patchcmd\expandafter{\csname optk@#1/@code\endcsname}{\option@patch@pre}{#2\option@patch@pre}{}{\optionerror{#1}{unable to prepend code}}%
+}
+
+\newrobustcmd*\optionappendcode[2]{%
+  \option@ensuredefined{#1}%
+  \expandafter\patchcmd\expandafter{\csname optk@#1/@code\endcsname}{\option@patch@post}{\option@patch@post #2}{}{\optionerror{#2}{unable to append code}}%
+}
+
+
+% --------------------------------------------------------
+% Bootstrap and use our options themselves to define everything else
+% --------------------------------------------------------
+
+% start bootstrap with the 'new handler' handler
+\optionnewhandler{/handlers/new handler}{\optionnewhandler{#1}{#2\option@chainempty}\option@chainempty}
+
+\options{
+  %
+  /handlers/new transformer/.new handler  =\optionnewhandler{#1}{#2\option@chain},
+  /handlers/new operation/.new handler    =\optionnewhandler{#1}{#2\option@chainonly},
+  /handlers/new handler*/.new handler     =\optionnewhandler*{#1}{#2\option@chainempty},
+  /handlers/new operation*/.new handler   =\optionnewhandler*{#1}{#2\option@chainonly},
+  %
+  /handlers/new cmd transformer/.new handler=\optionsalso{%
+    #1/.new operation* = {\expandnextsingle\optionprependcode{##1}{#2}}% prepend code to the option it is handling (##1)
+  },
+  % command transformers
+  /handlers/expands/.new cmd transformer  ={\protected@edef\optionvalue{\optionvalue}},
+  /handlers/defaults/.new cmd transformer ={\option@default@transform},
+  % the "new handler" can be provided with defaults.
+  /handlers/new handler/.defaults,
+  % value transformers
+  /handlers/expand once/.new transformer  =\edef\optionvalue{\expandafter\expandafter\expandafter\noexpand\optionvalue},
+  /handlers/expand twice/.new transformer =\edef\optionvalue{\expandafter\expandafter\expandafter\noexpand\optionvalue}%
+                                           \edef\optionvalue{\expandafter\expandafter\expandafter\noexpand\optionvalue},
+  /handlers/expanded/.new transformer     =\protected@edef\optionvalue{\optionvalue},
+}
+
+% For values of the form "[default]value" we assign "default" as the default, and continue with "value"
+\newrobustcmd\option@default@transform{\expandafter\option@default@transform@\optionvalue\opt@stop}
+\def\option@default@transform@{\@ifnextchar[{\option@default@transform@opt}{\option@default@transform@end}}
+\def\option@default@transform@end#1\opt@stop{}
+\def\option@default@transform@opt[#1]#2\opt@stop{%
+  \option@set{\option@handlerpath/@def}{#1}%
+  \edef\optionvalue{\unexpanded{#2}}% preserve # arguments in optionvalue
+}
+
+
+% --------------------------------------------------------
+% command actions take arguments
+% --------------------------------------------------------
+
+% provide command pattern; defined separately so we can expand the option@handler and pass as an argument
+\newrobustcmd*\optionnewcmdx[4]{%
+  \option@def{#1/@cmdx}#2\opt@stop{#4}%
+  \optionnewcode{#1}{\expandnextcmds{\option{#1/@cmdx}}{\optionvalue#3\opt@stop}\relax}%
+}
+
+\options{
+  /handlers/new code/.new handler/.defaults   = \optionnewcode{#1}{#2}\option@chainempty,
+  /handlers/new cmd*/.new handler             = \optionnewcode*{#1}{#2}\option@chainempty,
+  /options/exec/.new code                     =\optionvalue,
+  % commands 
+  /handlers/new cmd/.new handler/.defaults=\optionsalso{%
+    /options/exec={\option@def{#1/@cmd1}##1{#2}},%
+    #1/.new code={\expandnext{\option{#1/@cmd1}}{\optionvalue}},%
+  },%
+  /handlers/new cmd 2/.new handler/.defaults  = \optionsalso{
+    /options/exec = {\option@def{#1/@cmd2}##1##2##3{\ifblank{##3}{#2}{\optionerror@toomany{#1}{2 (but got: ##1,##2,##3)}}}},
+    #1/.new code  = {\expandnextcmds{\option{#1/@cmd2}}{\optionvalue}{}{}{}\relax},
+  },
+  /handlers/new cmd 3/.new handler/.defaults  = \optionsalso{
+    /options/exec = {\option@def{#1/@cmd3}##1##2##3##4{\ifblank{##4}{#2}{\option@toomany{#1}{3 (but got: ##1,##2,##3,##4)}}}},
+    #1/.new code  = {\expandnextcmds{\option{#1/@cmd3}}{\optionvalue}{}{}{}{}\relax},
+  },
+  /handlers/new cmd 4/.new handler/.defaults  = \optionsalso{
+    /options/exec = \option@def{#1/@cmd4}##1##2##3##4##5{\ifblank{##5}{#2}{\optionerror@toomany{#1}{4}}},
+    #1/.new code  = \expandnextcmds{\option{#1/@cmd4}}{\optionvalue}{}{}{}{}{}\relax,
+  },  
+  % tuples and triples take exactly 2 or 3 arguments
+  /handlers/new cmd tuple*/.new handler/.defaults  = \optionsalso{
+    #1/.new cmdx = {##1,##2,##3}{,,}%
+      {\ifstrequal{##3}{,}{#2}{\optionerror{#1}{expecting a 2 argument tuple \{_,_\}, but got "\optionvalue"}}},
+    #1/.type=cmd tuple*,
+  },
+  /handlers/new cmd tuple/.new handler/.defaults  = \optionsalso{
+    /options/exec = {\option@def{#1/@cmd2}##1##2{#2}},
+    #1/.new cmdx = {##1,##2}{,}%
+      {\ifblank{##2}{\option{#1/@cmd2}{##1}{##1}}{\option{#1/@cmd2}{##1}{##2}}},
+    #1/.type=cmd tuple,
+  },
+  /handlers/new cmd triple/.new handler/.defaults = \optionsalso{
+    #1/.new cmdx = {##1,##2,##3,##4}{,,,}%
+      {\ifstrequal{##4}{,,}{#2}{\optionerror{#1}{expecting a 3 argument triple \{_,_,_\}, but got "\optionvalue"}}},
+    #1/.type=cmd triple,
+  },
+  % aliases
+  /handlers/new cmdx/.new cmd 3/.defaults = \expandnextsingle\optionnewcmdx{\option@handlerpath}{#1}{#2}{#3},
+  /handlers/new code alias/.new handler   = \option@set{#1/@code}{\option{#2/@code}},
+  /handlers/new cmd 0/.new code alias     = /handlers/new cmd*,
+  /handlers/new cmd 1/.new code alias     = /handlers/new cmd,
+}
+
+
+% --------------------------------------------------------
+% Provide unknown here so we get a proper error for unknown options
+% --------------------------------------------------------
+
+\options{
+  /@unknown/.new cmd 2 = {%
+    \ifopt@unknownwarnonly
+      \optionwarning{#1}{unknown option}%
+    \else
+      \optionerror{#1}{unknown option}%
+    \fi%
+  }%
+}
+
+
+% --------------------------------------------------------
+% Convenience handlers
+% --------------------------------------------------------
+
+% debugging
+\options{
+  /handlers/show/.new handler*    = {\option@font@name{#1}=\optionshow{#1}},
+  /handlers/typeout/.new handler* = {\optiontypeout{#1}},
+}
+
+% family options
+\options{
+  /handlers/new style/.new handler/.defaults = \optionsalso{
+     #1/.new cmd = \optionsalso{#2}, 
+     #1/.type    = style,
+  },
+  /handlers/new style*/.new handler = \optionsalso{
+    #1/.new cmd* = \optionsalso{#2},
+    #1/.type     = style,
+  },
+  /handlers/new alias/.new handler ={%
+    \option@ensuredefined{#2}%
+    \optionsalso{%
+       #1/.new cmd =  \optionsalso{#2={##1}}, 
+       #1/.type    = alias,
+    }%
+    \option@xset{#1}{\option{#2}}%
+    %\option@xset{#1/@ini}{\option{#2/@ini}}%
+  },
+  /handlers/new alias*/.new handler = \optionsalso{
+    \option@ensuredefined{#2}%
+    \optionsalso{
+       #1/.new cmd = \optionsalso{#2}, 
+       #1/.type    = alias,
+    }%
+    \option@xset{#1}{\option{#2}}%
+    %\option@xset{#1/@ini}{\option{#2/@ini}}%
+  },
+  /handlers/show/style/.new cmd = {\option@font@special{style}},
+  %
+  /handlers/search also/.new handler =\optionaddsearch{#1}{#2},
+  /handlers/cd/.new handler*         =\edef\option@defaultpath{#1},
+  /handlers/new family/.new handler  =[]{\optionsalso{
+    #1/.new cmd* = {\edef\option@defaultpath{#1}}, 
+    #1/.search also = {#2},
+    #1/.type = family,
+    #1/.cd
+  }},
+  /handlers/show/family/.new cmd = {\option@font@special{family}, searches: \option@showvalue{\optionlist{#1/@searchalso}}},
+}
+
+% compatibility
+\options{
+  /handlers/code/.new handler        = \optionsalso{#1/.new cmd = {#2}},
+  /handlers/style/.new handler       = \optionsalso{#1/.new style= {#2}},
+  /handlers/is family/.new handler*  = \optionsalso{#1/.new family},
+}
+
+% defining new option types
+\options{%
+  /handlers/undef/.new handler = {%
+    \ifoptiondefined{#1}{%
+      \option@undef{#1}%
+      \option@undef{#1/@type}%
+      \option@undef{#1/@code}%
+      \option@undef{#1/@def}%
+      \option@undef{#1/@ini}%
+      % may leave other values but the above ones are surely required to be removed      
+    }%
+  },
+  /handlers/type/.new handler     = \option@ensuredefined{#1}\option@set{#1/@type}{#2},
+  /handlers/default/.new handler  = \option@ensuredefined{#1}\option@set{#1/@def}{#2},
+  /handlers/defaulted/.new handler= {%
+    \option@ensuredefined{#1}%
+    \option@default@transform% changes optionvalue and sets /@def if provided   
+  },
+  /handlers/initial/.new handler  = {%
+    \option@ensuredefined{#1}%
+    \option@default@transform% changes optionvalue and sets /@def if provided
+    \option@eset{#1/@ini}{\optionvalue}%
+    \option@einvoke{#1}{\optionvalue}%
+  },
+  /handlers/reset/.new operation* = {%
+    \letoption@{#1/@ini}\opt@temp
+    \ifx\opt@temp\relax
+      \optionerror{#1}{cannot reset an option that has no initial value}%
+    \else
+      \option@einvoke{#1}{\opt@temp}%
+    \fi
+  },
+}
+
+% \optionaddsearch{<path>}{<search paths>}
+% add new search paths to a path.
+% for efficiency we expand out the search code inline instead of iterating
+\newrobustcmd*\optionaddsearch[2]{%
+  \ifoptiondefined{#1/@searchalso/@code}%
+   {\option@concat{#1/@searchalso}{#2}}%
+   {\option@setlist{#1/@searchalso}{#2}%
+    \option@set{#1/@searchalso/@type}{searchalso}%
+    \option@def{#1/@searchalso/@code}{}}%
+  \def\opt@do@addsearch##1{%
+    \edef\opt@temp{%
+      \noexpand\ifx\noexpand\opt@codepath\noexpand\relax
+        \noexpand\opt@searchforabspath{##1/\noexpand\option@searchpath}%
+      \noexpand\fi
+    }%
+    \expandnext{\option@appto{#1/@searchalso/@code}}{\opt@temp}%
+  }%
+  \forcsvlist\opt@do@addsearch{#2}%
+}
+
+
+% --------------------------------------------------------
+% Basic data type handlers
+% --------------------------------------------------------
+
+\options{
+  /handlers/new value/.new handler = []\optionsalso{%
+    #1/.new code  = \option@let{#1}\optionvalue,
+    #1/.type      = value,
+    #1/.initial   = {#2},
+  },
+  %
+  /handlers/new num/.new handler = [0]\optionsalso{%
+    #1/.new code  = \option@eset{#1}{\the\numexpr\optionvalue\relax},
+    #1/.type      = num,
+    #1/.initial   = {#2},
+  },
+  %
+  /handlers/new glue/.new handler = [0pt]\optionsalso{%
+    #1/.new code  = \option@eset{#1}{\the\glueexpr\optionvalue\relax},
+    #1/.type      = glue,
+    #1/.initial   = {#2},
+  },
+  %
+  /handlers/new length/.new handler = [0pt]\optionsalso{%
+    #1/.new code  = \cssetlength{#1}{\dimexpr\optionvalue\relax},
+    #1/.type      = length,
+    /options/exec = \csnewlength{#1}\option@eset{#1}{\csname #1\endcsname},
+    #1/.initial   = {#2},
+  },
+  /handlers/show/length/.new cmd = {\option@showvalue{\the\option{#1}}},
+  %
+  /handlers/new dim/.new handler = [0pt]\optionsalso{%
+    #1/.new code  = {\option@eset{#1/@dimexpr}{\optionvalue}},
+    #1/.type      = dim,
+    /options/exec = {\option@eset{#1}{\dimexpr\option{#1/@dimexpr}\relax}},% read as dimexpr
+    #1/.initial   = {#2},
+  },
+  /handlers/show/dim/.new cmd ={\option@showvalue{\the\option{#1}}\ (=\optionshowliteral{#1/@dimexpr})},
+  %
+  /handlers/new toggle/.new handler = [false]\optionsalso{%
+    #1/.new code  = {[true]{%
+      \ifcsdef{toggle\optionvalue}%
+        {\csuse{toggle\optionvalue}{#1}}%
+        {\eifstrequal\optionvalue{True}%
+            {\toggletrue{#1}}%
+            {\eifstrequal\optionvalue{False}%
+              {\togglefalse{#1}}%
+              {\optionerror@expect{#1}{true or false}}}}%
+    }},
+    #1/.type      = toggle,
+    /options/exec = {\newtoggle{#1}\option@set{#1}{\iftoggle{#1}{true}{false}}},
+    #1/.initial   = {#2},
+  },
+  /handlers/flip/.new operation = \iftoggle{#1}{\togglefalse{#1}}{\toggletrue{#1}},
+  %
+  /handlers/new list/.new handler = []\optionsalso{%
+    #1/.new code  = \expandnext{\option@setlist{#1}}{\optionvalue},
+    #1/.type      = list,
+    #1/.initial   = {#2},
+  },
+  /handlers/show/list/.new cmd    = \letoptionlist{#1}\opt@list\option@showvalue{\opt@list},
+  /handlers/push/.new operation   = \option@push{#1}{#2},
+  /handlers/concat/.new operation = \option@concat{#1}{#2},
+  %
+  /handlers/new choice/.new handler={%
+    \opt@choices@parse{#1}{#2}% sets \opt@choices & opt@firstchoicename
+    \option@let{#1/@choices}{\opt@choices}%
+    \optionsalso{%
+      #1/.new cmd/.expands = {%
+        \opt@findchoice{##1}{#1}%
+        \ifnum\opt@choiceord<0%
+          \letoptionchoices{#1}\opt@choices
+          \optionerror@expect{#1}{one of "\opt@choices"}%
+        \else
+          \option@eset{#1}{\opt@choicevalue}%
+          \option@eset{#1/@ord}{\the\opt@choiceord}%
+          \option@eset{#1/@name}{\opt@choicename}%
+        \fi
+      },
+      #1/.type    = choice,
+      #1/.expanded/.initial = \opt@firstchoicename,%
+    }%
+  },
+  /handlers/show/choice/.new cmd = {%
+    \option@showvalue{\option{#1}} %
+    (\option@font@name{@ord}=\option{#1/@ord}), %
+    \letoptionchoices{#1}\opt@choices
+    choices=\option@showvalue{\opt@choices}%
+  },
+  %
+  /handlers/new color/.new handler=[black]{%
+    %\opt@ensurexcolor{#1}%
+    \optionsalso{%
+      #1/.new cmd/.expands = {%
+        \option@set{#1}{##1}%
+        \eifblank{##1}{}{\opt@colorlet{#1}{##1}}%
+      },
+      #1/.type      = color,
+      #1/.initial   = {#2},
+    }%
+  },
+  /handlers/new color expr/.new handler=[black]{%
+    %\opt@ensurexcolor{#1}%
+    \optionsalso{%
+      #1/.new value,
+      #1/.type      = color expr,
+      #1/.initial   = {#2},
+    }%
+  },
+}
+
+\providecommand\colorlet[2]{\optionerror{#1}{color options require package "xcolor"; please include this package}}%
+\providecommand\definecolor[3]{\optionerror{#1}{color options require package "xcolor"; please include this package}}%
+
+% opt@colorlet{<color name>}{<color>} lets color be a color name or \#XXXXXX HTML color
+\def\opt@colorlet@html#1\opt@stop#2\opt@stop{\definecolor{#2}{HTML}{#1}}
+\def\opt@colorlet@name#1\opt@stop#2\opt@stop{\colorlet{#2}{#1}}
+\def\opt@colorlet@{\@ifnextchar \#{\@firstoftwo{\opt@colorlet@html}}{\opt@colorlet@name}}
+\newrobustcmd*\opt@colorlet[2]{%
+  \ifdef{\colorlet}%
+    {\opt@colorlet@#2\opt@stop#1\opt@stop}%
+    {\definecolor{#1}{named}{#2}}% if no xcolor, only support named colors
+}
+
+
+
+
+% --------------------------------------------------------
+% Hook into existing definitions
+% --------------------------------------------------------
+
+\options{
+  /handlers/is if/.new handler = \optionsalso{%
+    /options/exec = {\ifcsdef{if#2}{}{\optionerror{#1}{no `if` with name "#2" is defined}}},
+    #1/.new code  = {[true]\ifcsdef{#2\optionvalue}{\csuse{#2\optionvalue}}{\optionerror@expect{#1}{true or false}}},
+    #1/.type      = if,
+    /options/exec = {\option@set{#1}{#2}},% read name of the if
+  },
+  /handlers/show/if/.new cmd = {\option@showvalue{\option{#1}} (=\option@showvalue{\ifbool{\option{#1}}{true}{false})}},
+  %
+  /handlers/is def/.new handler = \optionsalso{%
+    /options/exec = \ifdef{#2}{}{\optionerror{#1}{no definition "\detokenize{#2}" is found}},
+    #1/.new code  = \expandafter\def\expandafter#2\expandafter{\optionvalue},
+    #1/.type      = def,
+    /options/exec =\option@set{#1}{#2},% read returns definition 
+    %#1/.initial   = {#2},
+  },
+  %
+  /handlers/is edef/.new handler = \optionsalso{%
+    /options/exec = \ifdef{#2}{}{\optionerror{#1}{no definition "\detokenize{#2}" is found}},
+    #1/.new code  = \protected@edef#2{\optionvalue},
+    #1/.type      = edef,
+    /options/exec =\option@set{#1}{#2},% read returns definition 
+    %#1/.initial   = {#2},
+  },  
+  %
+  /handlers/is counter/.new handler = \optionsalso{%
+    /options/exec = \ifltxcounter{#2}{}{\optionerror{#1}{no definition "\detokenize{#2}" is found}},
+    #1/.new code  = \setcounter{#2}{\optionvalue},
+    #1/.type      = counter,
+    /options/exec =\option@set{#1}{#2},% read returns definition 
+    %#1/.initial   = {#2},
+  },
+  /handlers/show/counter/.new cmd = {\option@showvalue{\option{#1}} (=\option@font@value{\arabic{\option{#1}}})},
+  /handlers/inc/.new operation = [1]{%
+    \ifoptiontype{#1}{counter}% check if this is a counter or a number
+      {\addtocounter{\option{#1}}{#2}}%
+      {\option@xinvoke{#1}{\option{#1} + #2}}%
+  },
+  /handlers/step/.new operation* = {%
+    \ifoptiontype{#1}{counter}% check if this is a counter 
+      {\stepcounter{\option{#1}}}%
+      {\optionerror{#1}{cannot "step" a non-counter}}%
+  },
+  /handlers/refstep/.new operation* = {%
+    \ifoptiontype{#1}{counter}% check if this is a counter 
+      {\refstepcounter{\option{#1}}}%
+      {\optionerror{#1}{cannot "refstep" a non-counter}}%
+  },
+}
+
+
+% --------------------------------------------------------
+% Initial options for our library
+% --------------------------------------------------------
+\options{
+  /options/ignoreunknown/.is if       = opt@ignoreunknown,
+  /options/unknownwarnonly/.is if     = opt@unknownwarnonly,
+  /options/allowsearch/.is if         = opt@allowsearch,
+  /options/collectunknown/.new style* = {/options/ignoreunknown,/options/remaining={}},
+  /options/showbuiltin/.new toggle,
+}
+
+\csundef{optk@/options/remaining}% tricksy, but we want to define it officially here :-)
+\optionsalso{  
+  /options/remaining/.new list,
+}
+
+
+% --------------------------------------------------------
+% Show definitions
+% --------------------------------------------------------
+
+\newrobustcmd*\optionshowall[1][false]{\options{/options/showbuiltin=#1}\optionshowpath{}}
+
+\newcommand*\option@font@name[1]{\textsf{#1}}
+\newcommand*\option@font@path[1]{\textsf{#1}}
+\newcommand*\option@font@value[1]{\textsf{#1}}
+\newcommand*\option@font@special[1]{\textit{#1}}
+
+\newcommand*\option@showvalue[1]{$\langle$\option@font@value{#1}$\rangle$}
+
+\newrobustcmd*\optionshowpath[2][]{\option@showpath{#1#2}{#2}}
+\newrobustcmd*\option@showpath[2]{%
+  \noindent\option@font@path{#2/}%
+  \option@showitems{/@names}{\option@showname}{#1}%
+  \option@showitems{/@paths}{\option@showpath}{#1}%
+}
+
+\newrobustcmd*\option@showitems[3]{%
+  \ifoptionvoid{#3#1}{}{%
+    \begin{opt@marginlr}{1em}{0em}%
+     \optionlistdo{#3#1}{%
+       \iftoggle{/options/showbuiltin}{}%
+         {\option@ifanyof{#3/##1}{/handlers,/options}{\@gobble}%
+          {\if\option@firstletterof{##1}.\relax\expandafter\@gobble\fi}}%
+       {%
+         \noindent\hspace*{-0.5em}#2{#3/##1}{##1}%
+         \par%
+       }%
+     }%
+    \end{opt@marginlr}%
+  }%
+}
+
+\newrobustcmd*\option@showname[2]{%
+  \option@font@name{#2}%
+  =\optionshow{#1}%
+  \ifoptiondefined{#1/@ini}{%
+    , initial=\optionshowliteral{#1/@ini}%
+  }{}%
+  \ifoptiondefined{#1/@def}{%
+    , default=\optionshowliteral{#1/@def}%
+  }{}%
+}
+
+\newrobustcmd*\optionshowliteral[1]{\letoption{#1}\opt@temp\option@showvalue{\texttt{\expandnextsingle\detokenize{\opt@temp}}}}
+
+\newcommand*\optiontypeout[1]{%
+  \def\option@font@special##1{##1}%
+  \def\option@font@name##1{##1}% 
+  \def\option@font@path##1{##1}%
+  \def\option@font@value##1{##1}%
+  \def\option@showvalue##1{##1}%
+  \typeout{#1=\optionshow{#1}}%
+}
+
+\newcommand*\optionshow[1]{%
+  \ifoptiondefined{#1/@type}%
+    {\ifoptiondefined{/handlers/show/\option{#1/@type}}{\@firstoftwo}{\@secondoftwo}}%
+    {\@secondoftwo}%
+  {\option@invoke{/handlers/show/\option{#1/@type}}{#1}}%
+  {\ifoptiondefined{#1}%
+    {\ifoptioniscode{#1}%
+      {\optionshowtype{#1}}%
+      {\option@showvalue{\option{#1}}}}%
+    {\option@font@special{undefined}}%
+  }%
+}
+
+\newenvironment{opt@marginlr}[2]{%
+  \topsep\z@
+  \partopsep\z@
+  \trivlist
+  \rightmargin=\dimexpr#2\relax%
+  \leftmargin=\dimexpr#1\relax%  
+  \advance\linewidth -\rightmargin
+  \advance\linewidth -\leftmargin
+  \advance\@totalleftmargin \leftmargin
+  \parshape \@ne \@totalleftmargin \linewidth
+  \item[]%
+}%
+{\endtrivlist}
+
+
+% --------------------------------------------------------
+% Handling Package and Class options
+% --------------------------------------------------------
+
+% Process the 'global' class options in a package file
+% Just take care of known options and adjust the unusedoptionslist accordingly
+\newrobustcmd*\option@ProcessGlobalOptions[1]{%
+  \ifdefvoid{\@classoptionslist}{}{%
+    % process known options, and collect the rest in the remaining list
+    \options{/options/collectunknown,#1}\expandnext\optionsalso{\@classoptionslist}%
+    % remove processed options from the latex @unusedoptionlist
+    \ifx\@unusedoptionlist\@empty\relax\else
+      \def\opt@do##1{%
+        \ifoptioncontains{/options/remaining}{##1}{}{%
+          \expandnext{\@removeelement{##1}}{\@unusedoptionlist}{\@unusedoptionlist}%
+        }%
+      }%
+      \expandnext{\forcsvlist\opt@do}{\@classoptionslist}%
+    \fi
+  }%
+}
+
+% Process the local option in a .sty file, raise an error on unknown flags
+\newrobustcmd*\option@ProcessPackageOptions[1]{%
+  \letcs\opt@localoptions{opt@\@currname.\@currext}%
+  \ifdefvoid{\opt@localoptions}{}{%
+    \options{#1}\expandnext\optionsalso{\opt@localoptions}%
+  }%
+  \let\CurrentOption\@empty
+  \AtEndOfPackage{\let\@unprocessedoptions\relax}%
+}
+
+% Process the local options in a .cls file
+\newrobustcmd*\option@ProcessClassOptions[1]{%
+  \letcs\opt@localoptions{opt@\@currname.\@currext}%
+  \ifdefvoid{\opt@localoptions}{}{%
+    \options{/options/collectunknown,#1}\expandnext\optionsalso{\opt@localoptions}%
+    \letoptionlist{/options/remaining}\@unusedoptionlist% set the unused option list
+  }%
+  \let\CurrentOption\@empty
+  \AtEndOfPackage{\let\@unprocessedoptions\relax}%
+}
+
+% Process class- or package options. 
+% A package will take global class options into account
+\newrobustcmd*\options@ProcessOptions[1]{%
+  \ifx\@currext\@clsextension
+    \option@ProcessClassOptions{#1}%
+  \else
+    \option@ProcessGlobalOptions{#1}%
+    \option@ProcessPackageOptions{#1}%
+  \fi
+}
+\@onlypreamble\options@ProcessOptions
+\@onlypreamble\options@ProcessPackageOptions
+\@onlypreamble\options@ProcessClassOptions
+\@onlypreamble\options@ProcessGlobalOptions
+
+
+% --------------------------------------------------------
+% Enable debugging
+% --------------------------------------------------------
+\ifopt@debug
+  \let\option@fast\option
+  \renewcommand*\option[1]{%
+    \ifcsdef{optk@#1}{}{\z@\optionerror{#1}{debug option: undefined option}}%
+    \option@fast{#1}%
+  }
+  \let\letoption@fast\letoption
+  \renewcommand*\letoption[2]{%
+    \ifcsdef{optk@#1}{}{\z@\optionerror{#1}{debug letoption: undefined option}}%
+    \letoption@fast{#1}#2%
+  }
+\fi
+
+% --------------------------------------------------------
+% restore cat codes
+% --------------------------------------------------------
+\opt@restore@catcodes
-- 
cgit v1.2.3

