summaryrefslogtreecommitdiff
path: root/macros/generic
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2023-01-24 03:02:57 +0000
committerNorbert Preining <norbert@preining.info>2023-01-24 03:02:57 +0000
commitb06c6695162b493aeec3b594c6beb518c15c98ba (patch)
tree0c1dc3cfc73ea789d6bdc4673d776f3ef652d6d8 /macros/generic
parent4451a2090261307c963209bc65fea9fde4eceeea (diff)
CTAN sync 202301240302
Diffstat (limited to 'macros/generic')
-rw-r--r--macros/generic/expkv-bundle/README.md46
-rw-r--r--macros/generic/expkv-bundle/comparison.tex246
-rw-r--r--macros/generic/expkv-bundle/expkv-bundle.ins101
-rw-r--r--macros/generic/expkv-bundle/expkv-bundle.pdfbin0 -> 714141 bytes
-rw-r--r--macros/generic/expkv-bundle/expkv-bundle.tex353
-rw-r--r--macros/generic/expkv-bundle/expkv-cs.dtx1748
-rw-r--r--macros/generic/expkv-bundle/expkv-def.dtx1369
-rw-r--r--macros/generic/expkv-bundle/expkv-opt-2020-10-10.dtx (renamed from macros/generic/expkv-opt/expkv-opt-2020-10-10.dtx)28
-rw-r--r--macros/generic/expkv-bundle/expkv-opt.dtx796
-rw-r--r--macros/generic/expkv-bundle/expkv-pop.dtx700
-rw-r--r--macros/generic/expkv-bundle/expkv.dtx2375
-rw-r--r--macros/generic/expkv-bundle/impatient.tex56
-rw-r--r--macros/generic/expkv-bundle/introduction.tex115
-rw-r--r--macros/generic/expkv-bundle/pkg-cs.tex937
-rw-r--r--macros/generic/expkv-bundle/pkg-def.tex727
-rw-r--r--macros/generic/expkv-bundle/pkg-main.tex1097
-rw-r--r--macros/generic/expkv-bundle/pkg-opt.tex229
-rw-r--r--macros/generic/expkv-bundle/pkg-pop.tex439
-rw-r--r--macros/generic/expkv-bundle/preamble-enverb.tex348
-rw-r--r--macros/generic/expkv-bundle/preamble-examples.tex16
-rw-r--r--macros/generic/expkv-bundle/preamble-l3doctweaks.tex39
-rw-r--r--macros/generic/expkv-bundle/preamble-logos.tex107
-rw-r--r--macros/generic/expkv-bundle/preamble-lst.tex218
-rw-r--r--macros/generic/expkv-bundle/preamble-noidx.tex50
-rw-r--r--macros/generic/expkv-bundle/preamble-prefixes.tex36
-rw-r--r--macros/generic/expkv-cs/README.md32
-rw-r--r--macros/generic/expkv-cs/expkv-cs.dtx3431
-rw-r--r--macros/generic/expkv-cs/expkv-cs.pdfbin470406 -> 0 bytes
-rw-r--r--macros/generic/expkv-def/README.md32
-rw-r--r--macros/generic/expkv-def/expkv-def.dtx2493
-rw-r--r--macros/generic/expkv-def/expkv-def.pdfbin424547 -> 0 bytes
-rw-r--r--macros/generic/expkv-opt/README.md29
-rw-r--r--macros/generic/expkv-opt/expkv-opt.dtx1012
-rw-r--r--macros/generic/expkv-opt/expkv-opt.pdfbin268534 -> 0 bytes
-rw-r--r--macros/generic/expkv/README.md35
-rw-r--r--macros/generic/expkv/expkv.dtx2980
-rw-r--r--macros/generic/expkv/expkv.pdfbin490757 -> 0 bytes
37 files changed, 12163 insertions, 10057 deletions
diff --git a/macros/generic/expkv-bundle/README.md b/macros/generic/expkv-bundle/README.md
new file mode 100644
index 0000000000..8d484d62d4
--- /dev/null
+++ b/macros/generic/expkv-bundle/README.md
@@ -0,0 +1,46 @@
+-------------------------------------------------------------------------------
+# `expkv-bundle` -- an expandable key=value implementation and more
+
+Version 2023-01-23
+
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+
+Hosted on the Island of TeX at https://gitlab.com/islandoftex/texmf/expkv-bundle
+
+-------------------------------------------------------------------------------
+
+Copyright (C) 2020-2023 Jonathan P. Spratte
+
+This work may be distributed and/or modified under the conditions of the LaTeX
+Project Public License (LPPL), either version 1.3c of this license or (at your
+option) any later version. The latest version of this license is in the file:
+
+ http://www.latex-project.org/lppl.txt
+
+This work is "maintained" (as per LPPL maintenance status) by
+ Jonathan P. Spratte
+
+-------------------------------------------------------------------------------
+
+## Summary of Contents
+
+`expkv-bundle` is a collection of different packages that provide key=value
+functionality in plainTeX, LaTeX, and ConTeXt.
+
+At the core the `expkv` package implements two expandable key=value parsers that
+are somewhat fast and robust against common bugs in many key=value
+implementations (no accidental brace stripping, no fragility for active commas
+or equals signs).
+
+`expkv-cs` enables users to define expandable key=value macros in a comfortable
+and straight forward way.
+
+`expkv-def` provides an interface to define common key types for `expkv` similar
+to the key defining interfaces of wide spread key=value implementations.
+
+`expkv-opt` allows to parse package or class options in LaTeX via `expkv`.
+
+`expkv-pop` is a utility package to define prefix oriented parsers that allow a
+somewhat natural formulation (it provides the core functionality for the
+key-defining front ends of both `expkv-cs` and `expkv-def`).
diff --git a/macros/generic/expkv-bundle/comparison.tex b/macros/generic/expkv-bundle/comparison.tex
new file mode 100644
index 0000000000..7736f0a4f1
--- /dev/null
+++ b/macros/generic/expkv-bundle/comparison.tex
@@ -0,0 +1,246 @@
+\section{Comparisons}\label{sec:cmp}
+
+This section makes some basic comparison between \expkv\ and other \kv\
+packages. The comparisons are really concise, regarding speed, feature range
+(without listing the features of each package, comparisons are done against the
+base \expkv\ not counting other packages in \expkvbundle\ that extend it, so
+\enquote{bigger feature set} might not necessarily be true if everything is
+included), and bugs and misfeatures.
+
+Comparisons of speed are done with a very simple test key and the help of the
+\pkg{l3benchmark} package. The key and its usage should be equivalent to
+\begin{enverb}[no-tcb]
+ \protected\ekvdef{test}{height}{\def\myheight{#1}}
+ \ekvsetdef\expkvtest{test}
+ \expkvtest{ height = 6 }
+\end{enverb}
+and only the usage of the key, not its definition, is benchmarked. For the
+impatient, the essence of these comparisons regarding speed and buggy
+behaviour is contained in \autoref{tab:comp}.
+
+As far as I know \expkv\ is the only fully expandable \kv\ parser. I tried to
+compare \expkv\ to every \kv\ package listed on
+\href{https://ctan.org/topic/keyval}{CTAN}, however, one might notice that
+some of those are missing from this list. That's because I didn't get the
+others to work due to bugs, or because they just provide wrappers around other
+packages in this list.
+
+In this subsection is no benchmark of |\ekvparse| and |\keyval_parse:NNn|
+contained, as most other packages don't provide equivalent features to my
+knowledge. |\ekvparse| is slightly faster than |\ekvset|, but keep in mind
+that it does less. The same is true for |\keyval_parse:NNn| compared to
+|\keys_set:nn| of \pkg{expl3} (where the difference is much bigger). Comparing
+just the two, |\ekvparse| is a tad faster than |\keyval_parse:NNn| because of
+two tests (for empty key names and only a single equal sign) which are
+omitted.
+
+\paragraph{\pkg{keyval}} is the fastest \kv\ package there is and has a minimal
+feature set with a slightly different way how it handles keys without values
+compared to \expkv. That might be considered a drawback, as it limits the
+versatility, but also as an advantage, as it might reduce doubled code. Keep in
+mind that as soon as someone loads \pkg{xkeyval} the performance of \pkg{keyval}
+gets replaced by \pkg{xkeyval}'s.
+
+Also \pkg{keyval} has a \pmso{bug}feature, which unfortunately can't really be
+resolved without breaking backwards compatibility for \emph{many} documents,
+namely it strips braces from the argument before stripping spaces if the
+outer most braces aren't surrounded by spaces, also it might strip more than one
+set of braces. Hence all of the following are equivalent in their outcome,
+though the last two lines should result in something different than the first
+two:
+\begin{enverb}[no-tcb]
+ \setkeys{foo}{bar=baz}
+ \setkeys{foo}{bar= {baz}}
+ \setkeys{foo}{bar={ baz}} % should be ` baz'
+ \setkeys{foo}{bar={{baz}}} % should be `{baz}'
+\end{enverb}
+
+\pkg{keyval} doesn't work with non-standard category codes of |=| and |,|. Also
+if a \kv\ pair contains multiple equals signs outside of braces everything post
+the first is silently ignored so the following two inputs yield identical
+outputs:
+\begin{enverb}[no-tcb,lst=belowskip=0pt]
+ \setkeys{foo}{bar=baz}
+ \setkeys{foo}{bar=baz=and more}
+\end{enverb}
+
+\paragraph{\pkg{xkeyval}} is pretty slow (yet not the slowest), but it provides
+more functionality, e.g., it has an interface to disable a list of keys, can
+search multiple sets simultaneously, and has an intriguing mechanism it calls
+\enquote{Pointers} to save the value of particular keys for later reuse. It
+contains the same bug as \pkg{keyval} as it has to be compatible with it by
+design (it replaces \pkg{keyval}'s frontend), but also adds even more cases in
+which braces are stripped that shouldn't be stripped, worsening the situation.
+
+\pkg{xkeyval} does work with non-standard category codes of |=| and |,|, but the
+used mechanism fails if the input contains a mix of different category codes for
+the same character. Just like with \pkg{keyval} equals signs after the first and
+everything after those is ignored.
+
+\paragraph{\pkg{ltxkeys}} is no longer compatible with the \LaTeX\ kernel
+starting with the release 2020-10-01. It is by far the slowest \kv\ package I've
+tested -- which is funny, because it aims to be ``[\ldots] faster [\ldots] than
+these earlier packages [referring to \pkg{keyval} and \pkg{xkeyval}].'' It needs
+more time to parse zero~keys than five of the packages in this comparison need
+to parse 100~keys. Since it aims to have a bigger feature set than
+\pkg{xkeyval}, it most definitely also has a bigger feature set than \expkv.
+Also, it can't parse |\long| input, so as soon as your values contain a |\par|,
+it'll throw errors. Furthermore, \pkg{ltxkeys} doesn't strip outer braces at
+all by design, which, imho, is a weird design choice. Some of the more
+intriguing features (e.g., the |\argpattern| mechanism) didn't work for me. In
+addition \pkg{ltxkeys} loads \pkg{catoptions} which is known to introduce bugs
+(e.g., see \url{https://tex.stackexchange.com/questions/461783}). Because it is
+no longer compatible with the kernel, I stop benchmarking it (so the numbers
+listed here and in \autoref{tab:comp} regarding \pkg{ltxkeys} were last updated
+on 2020-10-05).
+
+\pkg{ltxkeys} works with non-standard category codes, it also silently ignores
+any additional equals signs and the following tokens.
+
+\paragraph{\pkg{l3keys}} is at the slower end of the midfield yet not unusably
+slow, but has an, imho, great interface to define keys. It strips \emph{all}
+outer spaces, even if somehow multiple spaces ended up on either end. It offers
+more features, but has pretty much been bound to \pkg{expl3} code before.
+Nowadays the \LaTeX\ kernel has an interface with the macros |\DeclareKeys|,
+|\SetKeys|, and |\ProcessKeyOptions| that provides access to \pkg{l3keys} from
+the \LaTeXe\ layer as well as parsing package options with it. Because of the
+|\ProcessKeyOptions| macro and its features the only two viable options to
+provide \kv\ options for new projects in my opinion are the kernel's methods and
+\expkvo\ as those are the only two until now up to my knowledge that support
+parsing the raw options, and future options.
+
+\pkg{l3keys} handles active commas and equals signs fine. Multiple equals signs
+lead to an error if additional equals signs aren't nested inside of braces, so
+perfectly predictable behaviour here.
+
+\paragraph{\pkg{pgfkeys}} is among the top~4 of speed if one uses |\pgfqkeys|
+over |\pgfkeys|, else the initialisation parsing the family path takes roughly
+\SI{43}{\ops} and moves it two spots down the list (so in \autoref{tab:comp}
+both $p_0$ and $T_0$ would be about \SI{43}{\ops} bigger if
+|\pgfkeys{|\meta{path}|/.cd,|\meta{keys}|}| was used instead). It has an
+\emph{enormous} feature set. It stores keys in a way that reminds one of folders
+in a Unix system which allows interesting features and has other syntactic
+sugars. It is another package that implements something like the \expnotation\
+with less different options though. To get the best performance |\pgfqkeys| was
+used in the benchmark. It has the same or a very similar bug \pkg{keyval} has.
+The brace bug (and also the category fragility) can be fixed by \pkg{pgfkeyx},
+but this package was last updated in 2012 and it slows down |\pgfkeys| by
+factor~\num{8}. Also \pkg{pgfkeyx} is no longer compatible with versions of
+\pkg{pgfkeys} newer than 2020-05-25.
+
+\pkg{pgfkeys} silently drops anything after the second unbraced equals sign in a
+\kv\ pair.
+
+\paragraph{\pkg{kvsetkeys} with \pkg{kvdefinekeys}} is in the slower midfield,
+but it works even if commas and equals have category codes different from 12
+(just as some other packages in this list). It has quadratic run-time unlike
+most other \kv\ implementations which behave linear. The features of the
+keys are equal to those of \pkg{keyval}, the parser adds handling of unknown
+keys.
+
+\pkg{kvsetkeys} does include any additional equals sign in the value. But any
+active equals sign is turned into one of category code 12 if it's not nested in
+braces. Also spaces around superfluous equals signs are stripped. So the
+following all result in the same:
+\begin{enverb}[no-tcb,lst=belowskip=0pt]
+ \kvsetkeys{foo}{bar=baz=morebaz}
+ \kvsetkeys{foo}{bar=baz =morebaz}
+ \kvsetkeys{foo}{bar=baz= morebaz}
+ \kvsetkeys{foo}{bar=baz = morebaz}
+\end{enverb}
+
+\paragraph{\pkg{options}} is in the midfield of speed. It is faster per
+individual key than \pkg{pgfkeys} but has no shortcut like |\pgfqkeys|.
+It has a much bigger feature set than \expkv. Similar to \pkg{pgfkeys} it uses a
+folder like structure, makes searching multiple paths easy, incorporates package
+options and more. It also features a form of expansion control, predefined
+expansion kinds are limited though one can define additional ones. Unfortunately
+it also suffers from the premature unbracing bug \pkg{keyval} has.
+
+\pkg{options} can't handle non-standard category codes and will silently ignore
+superfluous equals signs and following tokens.
+
+\paragraph{\pkg{simplekv}} is hard to compare because I don't speak French (so
+I don't understand the documentation). There was an update released on
+2020-04-27 which greatly improved the package's performance and added
+functionality so that it can be used more like most of the other \kv\
+packages. Speed wise it is pretty close to \expkv. Regarding unknown keys it got
+a very interesting behaviour. It doesn't throw an error, but stores the \val\ in
+a new entry accessible with \cs[no-index]{useKV}. Also if you omit \val\ it
+stores |true| for that \key.
+
+\pkg{simplekv} can't correctly handle non-standard category codes. It silently
+ignores any unbraced equals sign beyond the first and any following tokens.
+
+\paragraph{\protect\yax} is the second slowest package I've tested. It has a
+pretty strange syntax for the \TeX-world, imho, and again a direct equivalent is
+hard to define (don't understand me wrong, I don't say I don't like the syntax,
+quite the contrary, it's just atypical). It has the premature unbracing bug,
+too. \yax\ features some prefixes one can use to make an assignment use |\edef|,
+|\gdef| or |\xdef| so has something that comes close to expansion control. Also
+somehow loading \yax\ broke \pkg{options} for me. The tested definition was:
+\begin{enverb}[no-tcb]
+ \usepackage{yax}
+ \defactiveparameter yax {\storevalue\myheight yax:height } % setup
+ \setparameterlist{yax}{ height = 6 } % benchmark
+\end{enverb}
+This seems important to state as \yax\ supports two different input syntaxes,
+the tested one was the one closer to traditional \kv\ input.
+
+\yax\ won't handle non-standard category codes correctly. Superfluous equals
+signs end up in the value in an unaltered form (just like with \expkv).
+
+\begin{table}
+ \def\fnsym{\textcolor{red!80!black}{*}}%
+ \sisetup{round-precision=1, round-mode=places}%
+ \begingroup
+ \centering
+ \newcommand*\yes{\textcolor{red!80!black} {yes}}^^A
+ \newcommand*\no {\textcolor{green!80!black}{no}}^^A
+ \caption[Comparison of \kv\ packages]
+ {^^A
+ Comparison of \kv\ packages. The packages are ordered from
+ fastest to slowest for one \kv\ pair. Benchmarking was done using
+ \pkg{l3benchmark} and the scripts in the \file{Benchmarks} folder
+ of \href{https://github.com/Skillmon/tex_expkv}{the original \expkv's git
+ repository}.
+ The columns $p_i$ are the polynomial coefficients of a linear fit to the
+ run-time, $p_0$ can be interpreted as the overhead for initialisation
+ and $p_1$ the cost per key. The $T_0$ column is the actual mean ops
+ needed for an empty list argument, as the linear fit doesn't match that
+ point well in general. The column ``BB'' lists whether the
+ parsing is affected by some sort of brace bug, ``CF'' stands for
+ category code fragile and lists whether the parsing breaks with active
+ commas or equal signs.^^A
+ \label{tab:comp}^^A
+ }
+ \begin{tabular}
+ {>{\collectcell\pkg}l<{\endcollectcell}*3{S[table-format=4.1]}ccc}
+ \toprule
+ \rmfamily Package & {$p_1$} & {$p_0$} & {$T_0$}& BB & CF & Date \\
+ \midrule
+ keyval & 13.557 & 2.202 & 7.185 & \yes & \yes & 2022-05-29 \\
+ \expkv & 16.669 & 3.132 & 5.836 & \no & \no & 2023-01-10 \\
+ simplekv & 19.943 & 2.850 & 15.120 & \no & \yes & 2022-10-01 \\
+ pgfkeys & 24.465 & 2.244 & 10.283 & \yes & \yes & 2021-05-15 \\
+ options & 23.255 & 16.160 & 20.400 & \yes & \yes & 2015-03-01 \\
+ kvsetkeys & {\fnsym} & {\fnsym} & 40.360 & \no & \no & 2022-10-05 \\
+ l3keys & 70.643 & 35.602 & 32.230 & \no & \no & 2022-12-17 \\
+ xkeyval & 255.906 & 221.276 & 173.400 & \yes & \yes & 2022-06-16 \\
+ \yax & 438.242 & 131.846 & 114.800 & \yes & \yes & 2010-01-22 \\
+ ltxkeys & 3400.142 & 4737.958 & 5368.000 & \no & \no & 2012-11-17 \\
+ \bottomrule
+ \end{tabular}
+ \par
+ \endgroup
+ \medskip
+ \fnsym For \pkg{kvsetkeys} the linear model used for the other
+ packages is a poor fit, \pkg{kvsetkeys} seems to have approximately
+ quadratic run-time, the coefficients of the second degree polynomial fit are
+ $p_2=\num{7.617}$, $p_1=\num{47.727}$, and $p_0=\num{57.988}$. Of course the
+ other packages might not really have linear run-time, but at least from 1~to
+ 20~keys the fits don't seem too bad. If one extrapolates the fits for 100
+ \kv\ pairs one finds that most of them match pretty well, the exception
+ being \pkg{ltxkeys}, which behaves quadratic as well with
+ $p_2=\num{23.500}$, $p_1=\num{2906.634}$, and $p_0=\num{6547.489}$.
+\end{table}
diff --git a/macros/generic/expkv-bundle/expkv-bundle.ins b/macros/generic/expkv-bundle/expkv-bundle.ins
new file mode 100644
index 0000000000..648b1b2871
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-bundle.ins
@@ -0,0 +1,101 @@
+\iffalse meta-comment
+
+Project: expkv-bundle Copyright (C) 2020-2023 Jonathan P. Spratte
+
+This work may be distributed and/or modified under the conditions of the
+LaTeX Project Public License (LPPL), either version 1.3c of this license or
+(at your option) any later version. The latest version of this license is in
+the file:
+
+ http://www.latex-project.org/lppl.txt
+
+-----------------------------------------------------------------------------
+
+This file is part of the "expkv bundle" (The Work in LPPL) and all files in
+that bundle must be distributed together.
+
+The released version of this bundle is available from CTAN.
+
+-----------------------------------------------------------------------------
+
+The development version of the bundle can be found at
+
+ https://gitlab.com/islandoftex/texmf/expkv-bundle
+
+for those people who are interested.
+
+-----------------------------------------------------------------------------
+
+\fi
+
+\input l3docstrip.tex
+\askforoverwritefalse
+\preamble
+
+----------------------------------------------------------------
+expkv-bundle -- an expandable key=val implementation and friends
+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-2023 Jonathan P. Spratte
+
+This work may be distributed and/or modified under the conditions of the
+LaTeX Project Public License (LPPL), either version 1.3c of this license or
+(at your option) any later version. The latest version of this license is in
+the file:
+
+ http://www.latex-project.org/lppl.txt
+
+This work is "maintained" (as per LPPL maintenance status) by
+ Jonathan P. Spratte.
+
+This work consists of the files expkv-bundle.ins
+ expkv.dtx
+ expkv-cs.dtx
+ expkv-def.dtx
+ expkv-opt.dtx
+ expkv-pop.dtx
+and the derived files expkv.sty
+ expkv.tex
+ t-expkv.tex
+ expkv-cs.sty
+ expkv-cs.tex
+ t-expkv-cs.tex
+ expkv-def.sty
+ expkv-def.tex
+ t-expkv-def.tex
+ expkv-opt.sty
+ expkv-pop.sty
+ expkv-pop.tex
+ t-expkv-pop.tex
+
+as well as any documentation files shipped with it.
+
+\endpreamble
+\postamble
+\endpostamble
+
+\keepsilent
+
+\ifdefined\expkvDocNoGenerate\endinput\fi
+
+\generate
+ {%
+ \file {expkv.sty} {\from{expkv.dtx} {pkg}}%
+ \file {expkv.tex} {\from{expkv.dtx} {tex}}%
+ \file{t-expkv.tex} {\from{expkv.dtx} {ctx}}%
+ \file {expkv-cs.sty} {\from{expkv-cs.dtx} {pkg}}%
+ \file {expkv-cs.tex} {\from{expkv-cs.dtx} {tex}}%
+ \file{t-expkv-cs.tex} {\from{expkv-cs.dtx} {ctx}}%
+ \file {expkv-def.sty}{\from{expkv-def.dtx}{pkg}}%
+ \file {expkv-def.tex}{\from{expkv-def.dtx}{tex}}%
+ \file{t-expkv-def.tex}{\from{expkv-def.dtx}{ctx}}%
+ \file {expkv-pop.sty}{\from{expkv-pop.dtx}{pkg}}%
+ \file {expkv-pop.tex}{\from{expkv-pop.dtx}{tex}}%
+ \file{t-expkv-pop.tex}{\from{expkv-pop.dtx}{ctx}}%
+ \file {expkv-opt.sty}{\from{expkv-opt.dtx}{pkg}}%
+ }
+
+\endbatchfile
diff --git a/macros/generic/expkv-bundle/expkv-bundle.pdf b/macros/generic/expkv-bundle/expkv-bundle.pdf
new file mode 100644
index 0000000000..1d7023208a
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-bundle.pdf
Binary files differ
diff --git a/macros/generic/expkv-bundle/expkv-bundle.tex b/macros/generic/expkv-bundle/expkv-bundle.tex
new file mode 100644
index 0000000000..f8110ea36a
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-bundle.tex
@@ -0,0 +1,353 @@
+\PassOptionsToPackage{full}{textcomp}
+\documentclass[exfoo=value, exbar, exfoo=\empty]{l3doc}
+
+% preamble >>=
+\makeatletter
+\let\save@onlypreamble\@onlypreamble
+\let\@onlypreamble\@gobble
+\usepackage[all]{expkv}
+\let\@onlypreamble\save@onlypreamble
+\makeatother
+\usepackage[oldstylenums,nott]{kpfonts}
+\input{glyphtounicode}
+\pdfgentounicode=1
+\usepackage{xfp} % required for an example
+\usepackage{booktabs}
+\usepackage{array}
+\usepackage{collcell}
+\usepackage{siunitx}
+\DeclareSIUnit\ops{ops}
+\usepackage{xcolor}
+\usepackage{caption}
+\usepackage{microtype}
+\usepackage{accsupp}
+\usepackage{enumitem}
+\usepackage{randtext}
+
+\usepackage{tcolorbox}%>>=
+\newtcolorbox{exresult}[2][]
+ {%
+ colback=ekvgrey!10!white%
+ ,colframe=ekvgrey%
+ ,fontupper=\small
+ ,width={\dimexpr#2\relax}%
+ ,#1%
+ }
+\newtcbox\exres[1][]
+ {
+ colback=ekvgrey!10!white
+ ,colframe=ekvgrey
+ ,size=small
+ ,nobeforeafter
+ ,tcbox raise base
+ ,fontupper=\small
+ ,#1
+ }
+%=<<
+
+\usepackage{listings}%>>=
+\input{preamble-lst.tex}
+%=<<
+
+\let\metaORIG\meta
+\protected\def\meta #1{\texttt{\metaORIG{#1}}}
+
+\input{preamble-examples.tex}
+\input{preamble-logos.tex}
+
+\makeatletter
+% shortcuts >>=
+\newcommand\Vkey{\texttt{Val}-\key}
+\newcommand*\Nkey{\texttt{NoVal}-\key}
+\newcommand\kv{\meta{key}=\penalty2000\meta{value}}
+\newcommand\kvarg{\{\kv, \ldots\}}
+\newcommand\key{\meta{key}}
+\newcommand\val{\meta{value}}
+\newcommand\set{\meta{set}}
+\newcommand\prefix{\texorpdfstring{\textit{prefix}}{prefix}}
+\newcommand\prefixes{\textit{prefixes}}
+\newcommand\type{\texorpdfstring{\textit{type}}{type}}
+\newcommand\types{\textit{types}}
+\newcommand\tkn[2]{\texttt{\char`#1}\textsubscript{#2}}
+\newcommand\expansion{\meta{expansion}}
+%\newcommand\expnotation{}
+%\edef\expnotation
+ %{\noexpand\texttt{exp\string|}\penalty\@M-\hskip\z@skip notation}
+\newcommand\singlecs[1]
+ {%
+ The \meta{cs} should be a single control sequence, such as
+ \cs[no-index]{#1}. \ignorespaces
+ }
+\newcommand\ekvdocsection[8]
+ {%
+ \clearpage
+ \chardef\ekvdoc@insection1
+ \section[{#7}]%
+ {%
+ #7%
+ \hfill
+ \begingroup\scriptsize\ttfamily
+ \begin{tabular}{@{}r@{}l@{}}%
+ #1{\string\input\{expkv#8\}} & \rlap{#2{\ \% plain}}\\
+ #3{\string\usepackage\{expkv#8\}} & \rlap{#4{\ \% LaTeX}}\\
+ #5{\string\usemodule[expkv#8]} & \rlap{#6{\ \% ConTeXt}}\\
+ \end{tabular}%
+ \endgroup
+ \label{sec:expkv#8}%
+ }%
+ \chardef\ekvdoc@insection0
+ }
+\chardef\ekvdoc@insection0
+\newcommand*\genericekv
+ {\ekvdocsection{}{\textcolor{gray}}{}{\textcolor{gray}}{}{\textcolor{gray}}}
+\newcommand*\latexekv
+ {\ekvdocsection\phantom\phantom{}{\textcolor{gray}}\phantom\phantom}
+%=<<
+
+\hypersetup{linkcolor=red!80!black,urlcolor=purple!80!black}
+
+\input{preamble-prefixes.tex}
+\input{preamble-noidx.tex}
+\input{preamble-enverb.tex}
+
+% vissp >>=
+\ExplSyntaxOn
+\cs_new_protected:Npn \vissp #1
+ {
+ \group_begin:
+ \tl_set:Nn \l_tmpa_tl {#1}
+ \tl_replace_all:Nnn \l_tmpa_tl { ~ } { \asciispace }
+ \l_tmpa_tl
+ \group_end:
+ }
+\ExplSyntaxOff
+% =<<
+
+\ekvcSplit\expkvorules% >>=
+ {
+ cd = \emph{nothing}
+ ,cu = \emph{nothing}
+ ,pd = \emph{nothing}
+ ,pu = \emph{nothing}
+ }
+ {%
+ \begin{description}
+ \item[Class:]
+ \begin{description}
+ \item[defined] #1
+ \item[undefined] #2
+ \end{description}
+ \item[Package:]
+ \begin{description}
+ \item[defined] #3
+ \item[undefined] #4
+ \end{description}
+ \end{description}%
+ }
+\ekvcSecondaryKeys\expkvorules
+ {
+ meta d = {cd={#1},pd={#1}}
+ ,meta u = {cu={#1},pu={#1}}
+ }% =<<
+
+\newcommand*\pmso[1] % poor man's strike out%>>=
+ {%
+ \leavevmode
+ \begingroup
+ \sbox0{#1}%
+ \rlap{\vrule height .6ex depth -.5ex width \wd0\relax}%
+ \usebox0\relax
+ \endgroup
+ }%=<<
+
+\@ifdefinable\gobbledocstriptag{\def\gobbledocstriptag#1>{}}
+
+\renewcommand*\partname{Part}
+
+% \addsec and friends >>=
+\newcommand*\addsec@[2]
+ {%
+ \c@secnumdepth=%
+ \expanded
+ {%
+ \m@ne
+ \unexpanded{#1{#2}}%
+ \c@secnumdepth=\the\c@secnumdepth\relax
+ }%
+ }
+\newcommand*\addsec {\addsec@\section}
+\newcommand*\addssec {\addsec@\subsection}
+\newcommand*\addsssec{\addsec@\subsubsection}
+% =<<
+
+\newenvironment{syntaxexample}% >>=
+ {%
+ \quote
+ \ttfamily\small\frenchspacing
+ \parskip=\z@
+ \def\indent{\leavevmode\phantom{mm}}%
+ }
+ {\endquote}
+\newenvironment{syntaxexample*}
+ {\syntaxexample\obeylines}
+ {\endsyntaxexample}% =<<
+
+\newcommand\expkvdocPrintErrors[1][]
+ {%
+ \protected\long\def\expkvdoc@errfont##1%
+ {\texttt{\frenchspacing\textcolor{red!80!black}{##1}}}%
+ \protected\long\def\ekv@err@collect##1\par##2%
+ {\expkvdoc@errfont{! \detokenize{##2} Error: ##1}#1}%
+ \protected\long\def\expkvdoc@errm##1##2%
+ {\expkvdoc@errfont{! expkv##1 Error: ##2}#1}%
+ \def\ekv@errm{\expkvdoc@errm{}}%
+ \def\ekvc@errm{\expkvdoc@errm{-cs}}%
+ \def\ekvd@errm{\expkvdoc@errm{-def}}%
+ \def\ekvp@errm{\expkvdoc@errm{-pop}}%
+ }
+\makeatother
+
+\ExplSyntaxOn
+\str_new:N \g__expkvdoc_module_str
+\cs_new_protected:Npn \expkvdocfile #1% >>=
+ {
+ \expkvdoc_for_module:nn {#1}
+ {
+ \str_if_eq:nnTF {#1} {main}
+ { \lstset{style=expkv} }
+ { \lstset{style=expkv-#1} }
+ \addtocontents{exs}
+ {
+ \medskip
+ \noindent
+ \use:c { expkv \str_if_eq:nnF {#1} {main} { \str_head:n {#1} } }
+ \smallskip
+ }
+ \input{pkg-#1.tex}
+ }
+ }% =<<
+\cs_new_protected:Npn \expkvdocdtx #1% >>=
+ {
+ \expkvdoc_for_module:nn {#1}
+ {
+ \str_if_eq:nnTF {#1} {main}
+ { \DocInput{expkv.dtx} }
+ { \DocInput{expkv-#1.dtx} }
+ }
+ }% =<<
+\cs_new_protected:Npn \expkvdoc_for_module:nn #1#2% >>=
+ {
+ \use:e
+ {
+ \exp_not:n
+ {
+ \str_gset:Nn \g__expkvdoc_module_str {#1}
+ #2
+ \str_gset:Nn \g__expkvdoc_module_str
+ }
+ { \g__expkvdoc_module_str }
+ }
+ }% =<<
+\ExplSyntaxOff
+
+\input{preamble-l3doctweaks.tex}
+
+%=<<
+
+% for thanking Niranjan
+% code from https://tex.stackexchange.com/a/635125/117050
+\def\DevnagVersion{2.17}
+\usepackage{devanagari}
+
+\newif\ifexpkvDocImplementation%\expkvDocImplementationtrue
+
+\begin{document}
+\title{\expkvbundle}
+%\title% >>=
+ %{%
+ %\texorpdfstring
+ %{%
+ %\huge\expkvbundle
+ %\\[\medskipamount]
+ %\Large an {\expFormat}andable
+ %\meta{{\kvstyle k}\kern-.05em ey}=%
+ %\meta{{\kvstyle v}\kern-.05em alue}
+ %implementation and more%
+ %}
+ %{expkv-bundle - an expandable <key>=<value> implementation and more}%
+ %}% =<<
+\author
+ {%
+ Jonathan P. Spratte%
+ \thanks
+ {%
+ \protect\randomize{jspratte@yahoo.de};
+ Special thanks to {\protect\dn Enr\2jn} (Niranjan) for valuable
+ suggestions and additions to this documentation.%
+ }%
+ }
+\date{2023-01-23}
+\begingroup
+\renewcommand*\thefootnote{\fnsymbol{footnote}}
+\maketitle
+\endgroup
+
+\begin{abstract}%>>=
+ \noindent\parfillskip=0pt
+ The \expkvbundle\ provides at its core a \emph{fully expandable} \kv\ parser,
+ that is \emph{safe} for active commas and equals signs, \emph{reliable} to
+ only strip one set of braces after spaces are stripped, and blazingly
+ \emph{fast}, as of writing this only \pkg{keyval} is faster.
+ \par
+ \bigskip
+ This parser gets augmented by a family of packages. \expkvc\ allows to easily
+ define expandable macros using a \kv\ interface, making the expandable parser
+ available to the masses. \expkvd\ provides a \kv\ interface to
+ define common \key-types. With \expkvo\ you can parse package
+ and class options. \expkvp\ enables you to design your own prefix
+ oriented parsers for interface definitions.
+\end{abstract}%=<<
+
+\tableofcontents
+
+\clearpage
+
+\begin{documentation}% >>=
+\ifexpkvDocImplementation\part{Documentation}\fi
+
+\input{introduction.tex}
+\clearpage
+\input{impatient.tex}
+
+\expkvdocfile{main}
+\expkvdocfile{cs}
+\expkvdocfile{def}
+\expkvdocfile{opt}
+\expkvdocfile{pop}
+\clearpage
+\lstset{style=expkv-all}
+\input{comparison.tex}
+\end{documentation}% =<<
+
+\clearpage
+\listofexamples
+
+\ifexpkvDocImplementation
+ \clearpage
+ \begin{implementation}% >>=
+ \part{Implementation}
+ \expkvdocdtx{main}
+ \clearpage
+ \expkvdocdtx{cs}
+ \clearpage
+ \expkvdocdtx{def}
+ \clearpage
+ \expkvdocdtx{opt}
+ \clearpage
+ \expkvdocdtx{pop}
+ \end{implementation}% =<<
+\fi
+
+\clearpage
+\PrintIndex
+\end{document}
diff --git a/macros/generic/expkv-bundle/expkv-cs.dtx b/macros/generic/expkv-bundle/expkv-cs.dtx
new file mode 100644
index 0000000000..4cf7946a87
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-cs.dtx
@@ -0,0 +1,1748 @@
+% \iffalse meta-comment
+%
+% File: expkv-cs.dtx Copyright (C) 2020-2023 Jonathan P. Spratte
+%
+% This work may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this license or
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% ------------------------------------------------------------------------------
+%
+%<*driver>^^A>>=
+\def\expkvDocNoGenerate{}
+\input expkv-bundle.ins
+\generate{\file{expkv-cs.sty}{\from{expkv-cs.dtx}{pkg}}}
+\generate{\file{expkv-cs.tex}{\from{expkv-cs.dtx}{tex}}}
+\generate{\file{t-expkv-cs.tex}{\from{expkv-cs.dtx}{ctx}}}
+\endbatchfile
+%</driver>^^A=<<
+% \fi
+%
+% \section{\expkvc}
+%^^A the LaTeX package >>=
+% \subsection{The \LaTeX\ Package}
+% Just like for \expkv\ we provide a small \LaTeX\ package that sets up things
+% such that we behave nicely on \LaTeX\ packages and files system. It'll
+% |\input| the generic code which implements the functionality.
+% \gobbledocstriptag
+%<*pkg>
+% \begin{macrocode}
+\RequirePackage{expkv-pop}
+\def\ekvc@tmp
+ {%
+ \ProvidesFile{expkv-cs.tex}%
+ [%
+ \ekvcDate\space v\ekvcVersion\space
+ define expandable key=val macros using expkv%
+ ]%
+ }
+\input{expkv-cs.tex}
+\ProvidesPackage{expkv-cs}%
+ [%
+ \ekvcDate\space v\ekvcVersion\space
+ define expandable key=val macros using expkv%
+ ]
+% \end{macrocode}
+% \gobbledocstriptag
+%</pkg>
+%^^A=<<
+%^^A the ConTeXt module >>=
+% \subsection{The \ConTeXt\ module}
+% \gobbledocstriptag
+%<*ctx>
+% \begin{macrocode}
+\writestatus{loading}{ConTeXt User Module / expkv-cs}
+\usemodule[expkv-pop]
+\unprotect
+\input expkv-cs.tex
+\writestatus{loading}
+ {ConTeXt User Module / expkv-cs / Version \ekvcVersion\space loaded}
+\protect\endinput
+% \end{macrocode}
+% \gobbledocstriptag
+%</ctx>
+%^^A=<<
+%^^A main file >>=
+% \subsection{The Generic Code}
+% The rest of this implementation will be the generic code.
+% \gobbledocstriptag
+%<*tex>
+%
+% Load \expkv\ if the package didn't already do so -- since \expkv\ has
+% safeguards against being loaded twice this does no harm and the overhead
+% isn't that big. Also we reuse some of the internals of \expkv\ to save us from
+% retyping them.
+% \begin{macrocode}
+\input expkv-pop
+% \end{macrocode}
+%
+% We make sure that \file{expkv-cs.tex} is only input once:
+% \begin{macrocode}
+\expandafter\ifx\csname ekvcVersion\endcsname\relax
+\else
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% \begin{macro}{\ekvcVersion,\ekvcDate}
+% We're on our first input, so lets store the version and date in a macro.
+% \begin{macrocode}
+\def\ekvcVersion{1.3}
+\def\ekvcDate{2023-01-23}
+% \end{macrocode}
+% \end{macro}
+%
+% If the \LaTeX\ format is loaded we want to be a good file and report back who
+% we are, for this the package will have defined |\ekvc@tmp| to use
+% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
+% \begin{macrocode}
+\csname ekvc@tmp\endcsname
+% \end{macrocode}
+%
+% Store the category code of |@| to later be able to reset it and change it to
+% 11 for now.
+% \begin{macrocode}
+\expandafter\chardef\csname ekvc@tmp\endcsname=\catcode`\@
+\catcode`\@=11
+% \end{macrocode}
+% |\ekvc@tmp| will be reused later, but we don't need it to ever store
+% information long-term after \expkvc\ was initialized.
+%
+% \begin{macro}[internal]{\ekvc@tripledots}
+% This macro just serves as a marker for a comparison to allow the syntax
+% for the unknown key handlers.
+% \begin{macrocode}
+\edef\ekvc@tripledots{\detokenize{...}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@keycount}
+% We'll need to keep count how many keys must be defined for each macro in the
+% |split| variants.
+% \begin{macrocode}
+\newcount\ekvc@keycount
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@long,\ekvc@any@long}
+% Some macros will have to be defined long. These two will be let to |\long|
+% when this should be the case.
+% \begin{macrocode}
+\let\ekvc@long\ekv@empty
+\let\ekvc@any@long\ekv@empty
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@ifdefined}
+% We want to test whether a macro is already defined. This test checks for a
+% defined macro that isn't |\relax|.
+% \begin{macrocode}
+\long\def\ekvc@ifdefined#1%
+ {%
+ \ifdefined#1%
+ \ifx\relax#1%
+ \ekv@fi@gobble
+ \fi
+ \@firstofone
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@ekvset@pre@expander,
+% \ekvc@ekvset@pre@expander@a,
+% \ekvc@ekvset@pre@expander@b
+% }
+% This macro expands |\ekvset| twice so that the first two steps of expansion
+% don't have to be made every time the \expkvc\ macros are used. We have to do
+% a little magic trick to get the macro parameter |#1| for the macro
+% definition this is used in, even though we're calling |\unexpanded|. We do
+% that by splitting the expanded |\ekvset| at some marks and place |##1| in
+% between. At this spot we also add |\ekv@alignsafe| and |\ekv@endalignsafe|
+% to ensure that macros created with \expkvc\ are alignment safe.
+% \begin{macrocode}
+\def\ekvc@ekvset@pre@expander#1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander@a\ekvset{#1}\ekvc@stop\ekvc@stop
+ }
+\def\ekvc@ekvset@pre@expander@a
+ {%
+ \expandafter\ekvc@ekvset@pre@expander@b
+ }
+\def\ekvc@ekvset@pre@expander@b#1\ekvc@stop#2\ekvc@stop
+ {%
+ \ekv@unexpanded\expandafter{\ekv@alignsafe}%
+ \ekv@unexpanded{#1}##1\ekv@unexpanded{#2}%
+ \ekv@unexpanded\expandafter{\ekv@endalignsafe}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcSplitAndUse}
+% The first user macro we want to set up can be reused for
+% \cs[no-index]{ekvcSplitAndForward} and \cs[no-index]{ekvcSplit}. We'll split
+% this one up so that the test whether the macro is already defined doesn't
+% run twice.
+% \begin{macrocode}
+\protected\long\def\ekvcSplitAndUse#1#2%
+ {%
+ \let\ekvc@helpers@needed\@firstoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {\ekvcSplitAndUse@#1{}{#2}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvcSplitAndUse@}
+% The actual macro setting up things. We need to set some variables, forward
+% the key list to |\ekvc@SetupSplitKeys|, and afterwards define the front
+% facing macro to call |\ekvset| and put the initials and the argument sorting
+% macro behind it. The internals |\ekvc@any@long|, |\ekvc@initials| and
+% |\ekvc@keycount| will be set correctly by |\ekvc@SetupSplitKeys|.
+% \begin{macrocode}
+\protected\long\def\ekvcSplitAndUse@#1#2#3%
+ {%
+ \edef\ekvc@set{\string#1}%
+ \ekvc@SetupSplitKeys{#3}%
+ \ekvc@helpers@needed
+ {%
+ \ekvc@any@long\edef#1##1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@split@\the\ekvc@keycount\endcsname}%
+ \ekv@unexpanded\expandafter{\ekvc@initials{}#2}%
+ }%
+ }%
+ {%
+ \ekvc@any@long\edef#1##1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
+ \ekv@unexpanded{#2}%
+ \ekv@unexpanded\expandafter{\ekvc@initials}%
+ }%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\ekvcSplitAndForward}
+% This just reuses |\ekvcSplitAndUse@| with a non-empty second argument,
+% resulting in that argument to be called after the splitting.
+% \begin{macrocode}
+\protected\long\def\ekvcSplitAndForward#1#2#3%
+ {%
+ \let\ekvc@helpers@needed\@firstoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {\ekvcSplitAndUse@#1{{#2}}{#3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcSplit}
+% The first half is just |\ekvcSplitAndForward| then we define the macro to
+% which the parsed key list is forwarded. There we need to allow for up to
+% nine arguments.
+% \begin{macrocode}
+\protected\long\def\ekvcSplit#1#2#3%
+ {%
+ \let\ekvc@helpers@needed\@secondoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {%
+ \expandafter
+ \ekvcSplitAndUse@\expandafter#1\csname ekvc@\string#1\endcsname{#2}%
+ \ifnum\ekvc@keycount<1
+ \ekvc@any@long\expandafter\def\csname ekvc@\string#1\endcsname{#3}%
+ \else
+ \ifnum\ekvc@keycount>9
+ \ekvc@err@toomany{#1}%
+ \let#1\ekvc@undefined
+ \else
+ \ekvcSplit@build@argspec
+ \ekvc@any@long\expandafter
+ \def\csname ekvc@\string#1\expandafter\endcsname\ekvc@tmp{#3}%
+ \fi
+ \fi
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvcSplit@build@argspec,\ekvcSplit@build@argspec@}
+% \begin{macrocode}
+\protected\def\ekvcSplit@build@argspec
+ {%
+ \begingroup
+ \edef\ekvc@tmp
+ {\endgroup\def\ekv@unexpanded{\ekvc@tmp}{\ekvcSplit@build@argspec@{1}}}%
+ \ekvc@tmp
+ }
+\def\ekvcSplit@build@argspec@#1%
+ {%
+ \ifnum#1>\ekvc@keycount
+ \ekv@fi@gobble
+ \fi
+ \@firstofone
+ {%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@#1\endcsname####}#1%
+ \expandafter\ekvcSplit@build@argspec@\expandafter{\the\numexpr#1+1}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@SetupSplitKeys, \ekvc@SetupSplitKeys@a, \ekvc@SetupSplitKeys@b,
+% \ekvc@SetupSplitKeys@unknown
+% }
+% These macros parse the list of keys and set up the key macros. First we need
+% to initialise some macros and start an \expkvp\ parser.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupSplitKeys
+ {%
+ \ekvc@keycount=\ekv@zero
+ \let\ekvc@any@long\ekv@empty
+ \let\ekvc@initials\ekv@empty
+ \ekvpParse@unsafe\ekvp@@p@ekvc@setup@splitkeys
+ }
+% \end{macrocode}
+% We're calling a parser here without the safety nets testing for parser
+% existence, so better define it now.
+% \begin{macrocode}
+\ekvpNewParser{ekvc@setup@splitkeys}
+\ekvpDefType{ekvc@setup@splitkeys}{short}
+ {%
+ \let\ekvc@long\ekv@empty
+ \expandafter\ekvc@SetupSplitKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefType{ekvc@setup@splitkeys}{long}
+ {%
+ \let\ekvc@long\long
+ \let\ekvc@any@long\long
+ \expandafter\ekvc@SetupSplitKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefNoType{ekvc@setup@splitkeys}
+ {%
+ \let\ekvc@long\ekv@empty
+ \expandafter\ekvc@SetupSplitKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+% \end{macrocode}
+% If no value was provided this could either be an error, or the unknown key
+% forwarding. We have to check this (comparing against |...| inside
+% |\ekvc@tripledots|) and if this is the unknown key list type, set it up
+% accordingly (advancing the key count and setting up the unknown handlers of
+% \expkv). Else we simply throw an error and ignore the incident.
+% \begin{macrocode}
+\ekvpDefNoValue{ekvc@setup@splitkeys}
+ {%
+ \begingroup
+ \edef\ekvc@tmp{\detokenize{#1}}%
+ \expandafter
+ \endgroup
+ \ifx\ekvc@tripledots\ekvc@tmp
+ \advance\ekvc@keycount1
+% \end{macrocode}
+% The |\begingroup\expandafter\endgroup| ensures that the split mark isn't
+% actually defined (even if it just were with meaning |\relax|).
+% \begin{macrocode}
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc@SetupSplitKeys@unknown
+ \csname ekvc@splitmark@\the\ekvc@keycount\endcsname
+ \let\ekvc@any@long\long
+ \else
+ \ekvc@err@value@required{#1}%
+ \fi
+ }
+% \end{macrocode}
+%
+% Now everything is parsed down to the point that we got the key name and its
+% value. We step the key counter and build the mark within a group to not
+% accidentally define the |\csname|.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupSplitKeys@a
+ {%
+ \advance\ekvc@keycount1
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc@SetupSplitKeys@b
+ \csname ekvc@splitmark@\the\ekvc@keycount\endcsname
+ }
+\protected\long\def\ekvc@SetupSplitKeys@b#1#2\ekv@stop#3%
+ {%
+ \long\def\ekvc@tmp##1##2#1##3{##2#1{##1}}%
+% \end{macrocode}
+% The short variant needs a bit of special treatment. The key macro will be
+% short to throw the correct error, but since there might be long macros
+% somewhere the reordering of arguments needs to be long, so for short keys we
+% use a two step approach, first grabbing only the short argument, then
+% reordering.
+% \begin{macrocode}
+ \ifx\ekvc@long\long
+ \else
+ \expandafter\let\csname ekvc@\ekvc@set(#2)\endcsname\ekvc@tmp
+ \edef\ekvc@tmp##1%
+ {%
+ \ekv@unexpanded\expandafter{\csname ekvc@\ekvc@set(#2)\endcsname}%
+ {##1}%
+ }%
+ \fi
+ \ekvlet\ekvc@set{#2}\ekvc@tmp
+ \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{#3}}}%
+ \ekvc@helpers@needed
+ {\expandafter\ekvc@setup@splitmacro\expandafter{\the\ekvc@keycount}}%
+ {}%
+ }
+% \end{macrocode}
+%
+% Here we get everything readily set up, |#1| contains the mark for unknown
+% keys and they only have to do some reordering.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupSplitKeys@unknown#1%
+ {%
+ \long\def\ekvc@tmp##1##2##3##4#1##5{##4#1{##5, {##3} = {##1} }}%
+ \ekvletunknown\ekvc@set\ekvc@tmp
+ \long\def\ekvc@tmp##1##2##3#1##4{##3#1{##4, {##2} }}%
+ \ekvletunknownNoVal\ekvc@set\ekvc@tmp
+ \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{}}}%
+ \ekvc@helpers@needed
+ {\expandafter\ekvc@setup@splitmacro\expandafter{\the\ekvc@keycount}}%
+ {}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@defarggobbler}
+% This is needed to define a macro with 1-9 parameters programmatically.
+% \LaTeX's \cs[no-index]{newcommand} does something similar for example.
+% \begin{macrocode}
+\protected\def\ekvc@defarggobbler#1{\def\ekvc@tmp##1#1##2##{##1#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@setup@splitmacro,
+% \ekvc@split@1, \ekvc@split@2, \ekvc@split@3,
+% \ekvc@split@4, \ekvc@split@5, \ekvc@split@6,
+% \ekvc@split@7
+% }
+% Since the first few split macros are different from the others we manually
+% set those up now. All the others will be defined as needed (always
+% globally). The split macros just read up until the correct split mark, move
+% that argument into a list and reinsert the rest, calling the next split
+% macro afterwards.
+% \begin{macrocode}
+\begingroup
+\edef\ekvc@tmp
+ {%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@1\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ ##2##3%
+ {##3{##1}##2}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@2\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ ##3##4%
+ {##4{##1}{##2}##3}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@3\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ ##4##5%
+ {##5{##1}{##2}{##3}##4}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@4\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
+ ##5##6%
+ {##6{##1}{##2}{##3}{##4}##5}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@5\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
+ ##6##7%
+ {##7{##1}{##2}{##3}{##4}{##5}##6}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@6\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@6\endcsname}##6%
+ ##7##8%
+ {##8{##1}{##2}{##3}{##4}{##5}{##6}##7}%
+ \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@7\endcsname}%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@6\endcsname}##6%
+ \ekv@unexpanded\expandafter{\csname ekvc@splitmark@7\endcsname}##7%
+ ##8##9%
+ {##9{##1}{##2}{##3}{##4}{##5}{##6}{##7}##8}%
+ }
+\ekvc@tmp
+\endgroup
+\protected\def\ekvc@setup@splitmacro#1%
+ {%
+ \ekv@ifdefined{ekvc@split@#1}{}%
+ {%
+ \begingroup
+ \def\ekvc@tmp##1%
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@splitmark@\the\numexpr#1-##1\relax\endcsname}%
+ }%
+ \edef\ekvc@tmp
+ {%
+ \long\gdef
+ \ekv@unexpanded\expandafter{\csname ekvc@split@#1\endcsname}%
+ ####1%
+ \ekvc@tmp{6}####2%
+ \ekvc@tmp{5}####3%
+ \ekvc@tmp{4}####4%
+ \ekvc@tmp{3}####5%
+ \ekvc@tmp{2}####6%
+ \ekvc@tmp{1}####7%
+ \ekvc@tmp{0}####8%
+ ####9%
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@split@\the\numexpr#1-7\relax\endcsname}%
+ ####1{{####2}{####3}{####4}{####5}{####6}{####7}{####8}####9}%
+ }%
+ }%
+ \ekvc@tmp
+ \endgroup
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcHashAndUse}
+% |\ekvcHashAndUse| works just like |\ekvcSplitAndUse|.
+% \begin{macrocode}
+\protected\long\def\ekvcHashAndUse#1#2%
+ {%
+ \let\ekvc@helpers@needed\@firstoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {\ekvcHashAndUse@#1{}{#2}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvcHashAndUse@}
+% This is more or less the same as |\ekvcSplitAndUse@|. Instead of an empty
+% group we place a marker after the initials, we don't use the sorting macros
+% of |split|, but instead pack all the values in one argument.
+% \begin{macrocode}
+\protected\long\def\ekvcHashAndUse@#1#2#3%
+ {%
+ \edef\ekvc@set{\string#1}%
+ \ekvc@SetupHashKeys{#3}%
+ \ekvc@helpers@needed
+ {%
+ \ekvc@any@long\edef#1##1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
+ \ekv@unexpanded{\ekvc@hash@pack@argument}%
+ \ekv@unexpanded\expandafter{\ekvc@initials\ekvc@stop#2}%
+ }%
+ }%
+ {%
+ \ekvc@any@long\edef#1##1%
+ {%
+ \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
+ \ekv@unexpanded{#2}%
+ \ekv@unexpanded\expandafter{\ekvc@initials\ekvc@stop}%
+ }%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcHashAndForward}
+% |\ekvcHashAndForward| works just like |\ekvcSplitAndForward|.
+% \begin{macrocode}
+\protected\long\def\ekvcHashAndForward#1#2#3%
+ {%
+ \let\ekvc@helpers@needed\@firstoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {\ekvcHashAndUse@#1{{#2}}{#3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcHash}
+% |\ekvcHash| does the same as |\ekvcSplit|, but has the advantage of not
+% needing to count arguments, so the definition of the internal macro is a bit
+% more straight forward.
+% \begin{macrocode}
+\protected\long\def\ekvcHash#1#2#3%
+ {%
+ \let\ekvc@helpers@needed\@secondoftwo
+ \ekvc@ifdefined#1%
+ {\ekvc@err@already@defined#1}%
+ {%
+ \expandafter
+ \ekvcHashAndUse@\expandafter#1\csname ekvc@\string#1\endcsname{#2}%
+ \ekvc@any@long\expandafter\def\csname ekvc@\string#1\endcsname
+ ##1\ekvc@stop
+ {#3}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@hash@pack@argument}
+% All this macro does is pack the values into one argument and forward that to
+% the next macro.
+% \begin{macrocode}
+\long\def\ekvc@hash@pack@argument#1\ekvc@stop#2{#2{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@SetupHashKeys,\ekvc@SetupHashKeys@a,\ekvc@SetupHashKeys@b,
+% \ekvc@SetupHashKeys@unknown
+% }
+% This should look awfully familiar as well, since it's just the same as for
+% the split keys with a few other names here and there.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupHashKeys
+ {%
+ \let\ekvc@any@long\ekv@empty
+ \let\ekvc@initials\ekv@empty
+ \ekvpParse@unsafe\ekvp@@p@ekvc@setup@hashkeys
+ }
+\ekvpNewParser{ekvc@setup@hashkeys}
+\ekvpDefType{ekvc@setup@hashkeys}{short}
+ {%
+ \let\ekvc@long\ekv@empty
+ \expandafter\ekvc@SetupHashKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefType{ekvc@setup@hashkeys}{long}
+ {%
+ \let\ekvc@long\long
+ \let\ekvc@any@long\long
+ \expandafter\ekvc@SetupHashKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefNoType{ekvc@setup@hashkeys}
+ {%
+ \let\ekvc@long\ekv@empty
+ \expandafter\ekvc@SetupHashKeys@a\detokenize{#1}\ekv@stop{#3}%
+ }
+\ekvpDefNoValue{ekvc@setup@hashkeys}
+ {%
+ \begingroup
+ \edef\ekvc@tmp{\detokenize{#1}}%
+ \expandafter
+ \endgroup
+ \ifx\ekvc@tripledots\ekvc@tmp
+ \ekvc@SetupHashKeys@unknown
+ \let\ekvc@any@long\long
+ \else
+ \ekvc@err@value@required{#1}%
+ \fi
+ }
+% \end{macrocode}
+% Again we build the marker, this time instead of a numbered one a named
+% hashmark, inside a group to not actually define the macro used as a marker.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupHashKeys@a#1\ekv@stop
+ {%
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc@SetupHashKeys@b\csname ekvc@hashmark@#1\endcsname{#1}%
+ }
+% \end{macrocode}
+% Yes, even the defining macro looks awfully familiar. Instead of numbered we
+% have named marks. Still the key macros grab everything up to their
+% respective mark and reorder the arguments. The same quirk is applied for
+% short keys. And instead of the |\ekvc@setup@splitmacro| we use
+% |\ekvc@setup@hashmacro|.
+% \begin{macrocode}
+\protected\long\def\ekvc@SetupHashKeys@b#1#2#3%
+ {%
+ \long\def\ekvc@tmp##1##2#1##3{##2#1{##1}}%
+ \ifx\ekvc@long\long
+ \else
+ \expandafter\let\csname ekvc@\ekvc@set(#2)\endcsname\ekvc@tmp
+ \edef\ekvc@tmp##1%
+ {%
+ \ekv@unexpanded\expandafter{\csname ekvc@\ekvc@set(#2)\endcsname}%
+ {##1}%
+ }%
+ \fi
+ \ekvlet\ekvc@set{#2}\ekvc@tmp
+ \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{#3}}}%
+ \ekvc@setup@hashmacro{#2}%
+ }
+% \end{macrocode}
+% Another temporary definition, this time to get the hashmarks for the unknown
+% handler without defining them.
+% \begin{macrocode}
+\def\ekvc@SetupHashKeys@unknown#1%
+ {%
+ \protected\def\ekvc@SetupHashKeys@unknown
+ {%
+ \ekvletunknown\ekvc@set\ekvc@hash@unknown@kv
+ \ekvletunknownNoVal\ekvc@set\ekvc@hash@unknown@k
+ \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{}}}%
+ \ekvc@setup@hashmacro{...}%
+ }%
+ \long\def\ekvc@hash@unknown@kv##1##2##3##4#1##5{##4#1{##5, {##3} = {##1} }}%
+ \long\def\ekvc@hash@unknown@k##1##2##3#1##4{##3#1{##4, {##2} }}%
+ }
+\begingroup\expandafter\endgroup
+\expandafter\ekvc@SetupHashKeys@unknown
+ \csname ekvc@hashmark@\ekvc@tripledots\endcsname
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@setup@hashmacro}
+% The safe hash macros will be executed inside of an |\unexpanded| expansion
+% context, so they have to insert braces for that once they are done.
+% Most of the tests which have to be executed will already be done, but we
+% have to play safe if the hash doesn't show up in the hash list. Therefore we
+% use some |\ekvc@mark|s and |\ekvc@stop| to throw errors if the hash isn't
+% found in the right place. The fast variants have an easier life and just
+% return the correct value.
+% \begin{macrocode}
+\protected\def\ekvc@setup@hashmacro#1%
+ {%
+ \ekv@ifdefined{ekvc@fasthash@#1}{}%
+ {%
+ \begingroup
+ \edef\ekvc@tmp
+ {%
+ \long\gdef
+ \ekv@unexpanded\expandafter{\csname ekvc@fasthash@#1\endcsname}%
+ ####1%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@hashmark@#1\endcsname}%
+ ####2####3\ekv@unexpanded{\ekvc@stop}%
+ {####2}%
+ \long\gdef
+ \ekv@unexpanded\expandafter{\csname ekvc@safehash@#1\endcsname}%
+ ####1%
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@@safehash@#1\endcsname}%
+ ####1\ekv@unexpanded{\ekvc@mark}{}%
+ \ekv@unexpanded\expandafter
+ {%
+ \csname ekvc@hashmark@#1\endcsname{}%
+ \ekvc@mark{\ekvc@err@missing@hash{#1}}\ekvc@stop
+ }%
+ }%
+ \long\gdef
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@@safehash@#1\endcsname}%
+ ####1%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@hashmark@#1\endcsname}%
+ ####2####3\ekv@unexpanded{\ekvc@mark}####4####5%
+ \ekv@unexpanded{\ekvc@stop}%
+ {%
+ ####4{####2}%
+ }%
+ \long\gdef\ekv@unexpanded\expandafter
+ {\csname ekvc@fastsplithash@#1\endcsname}%
+ ####1%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@hashmark@#1\endcsname}%
+ ####2####3\ekv@unexpanded{\ekvc@stop}####4%
+ {%
+ ####4{####2}%
+ }%
+ \long\gdef\ekv@unexpanded\expandafter
+ {\csname ekvc@safesplithash@#1\endcsname}####1%
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@@safesplithash@#1\endcsname}%
+ ####1\ekv@unexpanded{\ekvc@mark\ekvc@safe@after@hash}%
+ \ekv@unexpanded\expandafter
+ {%
+ \csname ekvc@hashmark@#1\endcsname{}%
+ \ekvc@mark
+ {\ekvc@err@missing@hash{#1}\ekvc@safe@after@hash}%
+ \ekvc@stop
+ }%
+ }%
+ \long\gdef\ekv@unexpanded\expandafter
+ {\csname ekvc@@safesplithash@#1\endcsname}%
+ ####1%
+ \ekv@unexpanded\expandafter
+ {\csname ekvc@hashmark@#1\endcsname}%
+ ####2####3\ekv@unexpanded{\ekvc@mark}####4####5%
+ \ekv@unexpanded{\ekvc@stop}%
+ {%
+ ####4{####2}%
+ }%
+ }%
+ \ekvc@tmp
+ \endgroup
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcValue}
+% \begin{macro}[internal]{\ekvcValue@}
+% All this does is a few consistency checks on the first argument (not empty,
+% hash macro exists) and then call that hash-grabbing macro that will also
+% test whether the hash is inside of |#2| or not.
+% \begin{macrocode}
+\long\def\ekvcValue#1%
+ {%
+ \ekv@unexpanded
+ \expandafter\ekvcValue@\detokenize{#1}\ekvc@stop
+ }
+\def\ekvcValue@#1\ekvc@stop
+ {%
+ \ekv@ifdefined{ekvc@safehash@#1}%
+ {\csname ekvc@safehash@#1\endcsname}%
+ {\ekvc@err@unknown@hash{#1}\@firstoftwo{{}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcValueFast}
+% To be as fast as possible, this doesn't test for anything, assuming the user
+% knows best.
+% \begin{macrocode}
+\long\def\ekvcValueFast#1#2%
+ {\csname ekvc@fasthash@\detokenize{#1}\endcsname#2\ekvc@stop}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcValueSplit}
+% \begin{macro}[internal]{\ekvcValueSplit@,\ekvcValueSplit@recover}
+% This splits off a single value.
+% \begin{macrocode}
+\long\def\ekvcValueSplit#1%
+ {\expandafter\ekvcValueSplit@\detokenize{#1}\ekvc@stop}
+\def\ekvcValueSplit@#1\ekvc@stop
+ {%
+ \ekv@ifdefined{ekvc@safesplithash@#1}%
+ {\csname ekvc@safesplithash@#1\endcsname}%
+ {\ekvc@err@unknown@hash{#1}\ekvcValueSplit@recover}%
+ }
+\long\def\ekvcValueSplit@recover#1#2{#2{}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@safe@after@hash}
+% \begin{macrocode}
+\long\def\ekvc@safe@after@hash#1#2%
+ {%
+ #2{#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcValueSplitFast}
+% Again a fast approach which doesn't provide too many safety measurements.
+% This needs to build the hash function and expand it before passing the
+% results to the next control sequence. The first step only builds the control
+% sequence.
+% \begin{macrocode}
+\long\def\ekvcValueSplitFast#1#2%
+ {\csname ekvc@fastsplithash@\detokenize{#1}\endcsname#2\ekvc@stop}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@safehash@,\ekvc@fasthash@,
+% \ekvc@safesplithash@,\ekvc@fastsplithash@
+% }
+% At least in the empty hash case we can provide a meaningful error message
+% without affecting performance by just defining the macro that would be build
+% in that case. There is of course a downside to this, the error will not be
+% thrown by |\ekvcValueFast| in three expansion steps. The safe hash variant
+% has to also stop the |\unexpanded| expansion.
+% \begin{macrocode}
+\long\def\ekvc@safehash@#1{\ekvc@err@empty@hash{}}
+\long\def\ekvc@fasthash@#1\ekvc@stop{\ekvc@err@empty@hash}
+\long\def\ekvc@safesplithash@#1#2{\ekvc@err@empty@hash#2{}}
+\long\def\ekvc@fastsplithash@#1\ekvc@stop#2{\ekvc@err@empty@hash#2{}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcSecondaryKeys}
+% \begin{macro}[internal]
+% {\ekvcSecondaryKeys@a,\ekvcSecondaryKeys@b,\ekvcSecondaryKeys@c}
+% Secondary keys use yet another \expkvp\ parser, keys will be set up further
+% down in their own subsection.
+% \begin{macrocode}
+\ekvpNewParser{ekvc@setup@secondary}
+\ekvpValueAlwaysRequired{ekvc@setup@secondary}
+\protected\long\def\ekvcSecondaryKeys#1%
+ {%
+ \edef\ekvc@set{\string#1}%
+ \let\ekvc@long\ekv@empty
+ \ekvpParse@unsafe\ekvp@@p@ekvc@setup@secondary
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcChange}
+% This can be used to change the defaults of an \expkvc\ defined macro. It
+% checks whether there is a set with the correct name and that the macro is
+% defined. If both is true the real work is done by |\ekvc@change|.
+% \begin{macrocode}
+\protected\long\def\ekvcChange#1%
+ {%
+ \ekvifdefinedset{\string#1}%
+ {%
+ \ekvc@ifdefined#1%
+ {\ekvc@change#1}%
+ {\ekvc@err@no@key@macro#1\@gobble}%
+ }%
+ {\ekvc@err@no@key@macro#1\@gobble}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@change ,\ekvc@change@a,\ekvc@change@b,
+% \ekvc@change@c,\ekvc@change@d,\ekvc@change@e
+% }
+% First we need to see whether the macro is currently |\long|. For this we get
+% the meaning and will parse it. |#1| is the macro name in which we want to
+% change the defaults.
+% \begin{macrocode}
+\protected\def\ekvc@change#1%
+ {\expandafter\ekvc@change@a\meaning#1\ekv@stop#1}
+% \end{macrocode}
+% A temporary definition to get the stringified |macro:|. |##1| will be the
+% list of prefixes, we don't care for the exact contents of |##2| and |##3|.
+% \begin{macrocode}
+\def\ekvc@change@a#1%
+ {%
+ \protected\def\ekvc@change@a##1#1##2->##3\ekv@stop
+ {%
+ \ekvc@change@iflong{##1}%
+ {\ekvc@change@b{}}%
+ {\ekvc@change@b{\long}}%
+ }%
+ }
+\expandafter\ekvc@change@a\expandafter{\detokenize{macro:}}
+% \end{macrocode}
+% Next we expand the macro once to get its contents (including the current
+% default values with their markers) and place |\ekvc@stop| instead of an
+% argument as a marker for the last step. |#1| is either |\long| or empty,
+% |#2| is the macro.
+% \begin{macrocode}
+\protected\def\ekvc@change@b#1#2%
+ {\expandafter\ekvc@change@c\expandafter{#2\ekvc@stop}{#1}#2}
+% \end{macrocode}
+% Here we place an unbalanced closing brace after the expansion of the macro.
+% Then we just parse the \kv-list with |\ekvset|, that will exchange the
+% values behind the markers. Once those are changed we give control to
+% |\ekvc@change@d|. The |\ekvset| step might horribly fail if the user defined
+% some keys that don't behave nice. |#1| is the expansion of the macro, |#2|
+% is either |\long| or empty, |#3| is the macro, and |#4| is the \kv-list
+% containing the new defaults.
+% \begin{macrocode}
+\ekv@exparg{\protected\long\def\ekvc@change@c#1#2#3#4}%
+ {%
+ \expandafter\iffalse\expandafter{\expandafter{\expandafter\fi
+ \ekvset{\string#3}{#4}%
+ \ekvc@change@d{#2}{#3}%
+ #1%
+ }}%
+ }
+% \end{macrocode}
+% The final step needs to put an unbalanced opening brace after |\edef|. Also
+% we have to protect everything from further expanding with the exception of
+% the redefined macro's argument, which is why we placed the |\ekvc@stop|
+% earlier. Then we need to also protect the rest of the contents from further
+% expanding using |\unexpanded| with another unbalanced opening brace.
+% |#1| will be either empty or |\long| and |#2| is the macro.
+% \begin{macrocode}
+\protected\def\ekvc@change@d#1#2%
+ {#1\edef#2##1{\expandafter\ekvc@change@e\iffalse}\fi}
+\long\def\ekvc@change@e#1\ekvc@stop
+ {\ekv@unexpanded{#1}##1\ekv@unexpanded\expandafter{\iffalse}\fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@change@iflong,\ekvc@change@iflong@}
+% Checking whether a string contains the string representation of |\long| can
+% be done by gobbling everything up to the first |\long| and checking whether
+% the result is completely empty. We need a temporary macro to get the result
+% of |\string\long| inside the definitions.
+% \begin{macrocode}
+\def\ekvc@change@iflong#1%
+ {%
+ \protected\def\ekvc@change@iflong##1%
+ {\expandafter\ekv@ifempty\expandafter{\ekvc@change@iflong@##1#1}}%
+ \def\ekvc@change@iflong@##1#1{}
+ }
+\expandafter\ekvc@change@iflong\expandafter{\string\long}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcPass}
+% This macro can be used to pass a value to a key of some macro (this way
+% more complicated key codes are possible that in the end pass processed
+% values on to some macro). The implemantation is pretty straight forward.
+% \begin{macrocode}
+\long\def\ekvcPass#1#2%
+ {%
+ \ekvifdefined{\string#1}{#2}%
+ {\csname\ekv@name{\string#1}{#2}\endcsname}%
+ {\ekvc@err@unknown@key@or@macro{#1}{#2}\@gobble}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Secondary Key Types}
+%
+% There is a single prefix named |long| and set up pretty simple.
+% \begin{macrocode}
+\ekvpDefPrefixLet{ekvc@setup@secondary}{long}\ekvc@long\long\ekv@empty
+% \end{macrocode}
+%
+% \begin{macro}[internal]
+% {
+% meta, nmeta,
+% \ekvc@type@meta, \ekvc@type@meta@
+% }
+% The |meta| and |nmeta| key types use |\ekvmorekv| to set other keys in
+% the same macro's \set. If the \kv\ list ist fixed (|nmeta|) we can expand
+% |\ekvmorekv| as far as possible (twice), else we expand it only once. This
+% makes a difference only if the \val\ of the |meta| key isn't forwarded in
+% braces and commas are active at the time of usage, in which case expanding
+% |\ekvmorekv| twice would result in wrong behaviour.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{meta}
+ {\ekvc@type@meta\ekv@exparg\ekvc@long{##1}\ekvlet{#1}{#3}}
+\ekvpDefType{ekvc@setup@secondary}{nmeta}
+ {\ekvc@assert@not@long\ekvc@type@meta\ekv@expargtwice{}{}\ekvletNoVal{#1}{#3}}
+\protected\long\def\ekvc@type@meta#1#2#3#4#5#6%
+ {%
+ #1\ekvc@type@meta@{\ekvmorekv{#6}}{#2}{#3}%
+ #4\ekvc@set{#5}\ekvc@tmp
+ }
+\protected\long\def\ekvc@type@meta@#1#2#3{#2\def\ekvc@tmp#3{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{alias}
+% |alias| just checks whether there is a key and/or |NoVal| key defined with
+% the target name and |\let| the key to those.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{alias}
+ {%
+ \ekvc@assert@not@long
+ \ekvc@assert@k@or@p@defined{#3}%
+ \ekvifdefined\ekvc@set{#3}{\ekvletkv\ekvc@set{#1}\ekvc@set{#3}}{}%
+ \ekvifdefinedNoVal\ekvc@set{#3}{\ekvletkvNoVal\ekvc@set{#1}\ekvc@set{#3}}{}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{default}
+% The |default| key can be used to set a \Nkey\ for an existing \Vkey. It
+% will just pass the \val\ to the key macro of that other key.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{default}
+ {%
+ \ekvc@assert@defined{#1}%
+ \ekvc@assert@not@long
+ \edef\ekvc@tmp
+ {%
+ \ekv@unexpanded\expandafter
+ {\csname\ekv@name\ekvc@set{#1}\endcsname{#3}}%
+ }%
+ \ekvletNoVal\ekvc@set{#1}\ekvc@tmp
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{enum,choice}
+% \begin{macro}[internal]
+% {
+% \ekvc@type@enum,\ekvc@h@enum,\ekvc@h@enum@,\ekvc@enum@name,
+% \ekvc@type@choice@
+% }
+% Enums don't need to apply special trickery to make the parts of the names
+% retrievable, so unlike in \expkvd\ we don't need catcode juggling.
+% The setup of an |enum| requires unpacking the value in two different
+% arguments so we need an auxiliary here.
+% \begin{macrocode}
+\def\ekvc@enum@name#1#2#3{ekvc#1(#2)#3}
+\ekvpDefType{ekvc@setup@secondary}{enum}
+ {\ekvpAssertTwoValues{#3}\ekvc@type@enum\ekvc@type@enum@{#1}#3}
+\ekvpDefType{ekvc@setup@secondary}{choice}
+ {\ekvpAssertTwoValues{#3}\ekvc@type@enum\ekvc@type@choice@{#1}#3}
+\protected\long\def\ekvc@type@enum#1#2#3%
+ {%
+ \ekvc@assert@defined{#3}%
+% \end{macrocode}
+% At run time we need another helper and we need to expand the current
+% |\ekvc@set| now. The helper will build a control sequence from each given
+% value, those will be set up in the |\ekvcsvloop|.
+% \begin{macrocode}
+ \ekvc@long\edef\ekvc@tmp##1%
+ {%
+ \ekv@unexpanded{\expandafter\ekvc@h@enum\detokenize}{##1}%
+ \ekv@unexpanded{\ekvc@stop}%
+ {\ekvc@set}{#2}%
+ }%
+ \ekvlet\ekvc@set{#2}\ekvc@tmp
+ \def\ekvc@tmp{0}%
+ \expandafter\ekvcsvloop\expandafter
+ {\expandafter#1\csname\ekv@name\ekvc@set{#3}\endcsname{#2}}%
+ }
+% \end{macrocode}
+% Here |#1| will be the key-macro of the underlying primary or secondary key,
+% |#2| is the |enum| key's name, and |#3| will be the choice. The rest is
+% pretty obvious.
+% \begin{macrocode}
+\ekv@exparg{\protected\long\def\ekvc@type@enum@#1#2#3}%
+ {%
+ \expandafter\expandafter\expandafter\edef\expandafter
+ \csname\ekvc@enum@name\ekvc@set{#2}{\detokenize{#3}}\endcsname
+ {\ekv@unexpanded{#1}{\ekvc@tmp}}%
+ \edef\ekvc@tmp{\the\numexpr\ekvc@tmp+1\relax}%
+ }
+\ekv@exparg{\protected\long\def\ekvc@type@choice@#1#2#3}%
+ {%
+ \expandafter\expandafter\expandafter\edef\expandafter
+ \csname\ekvc@enum@name\ekvc@set{#2}{\detokenize{#3}}\endcsname
+ {\ekv@unexpanded{#1{#3}}}%
+ }
+% \end{macrocode}
+% The use-time helper will check if the macro for the passed in choice exists,
+% if it doesn't throws an error, else calls that macro which will set the
+% correct value.
+% \begin{macrocode}
+\ekv@if@lastnamedcs
+ {%
+ \ekv@exparg{\def\ekvc@h@enum#1\ekvc@stop#2#3}%
+ {%
+ \expandafter\ifcsname\ekvc@enum@name{#2}{#3}{#1}\endcsname
+ \expandafter\ekvc@h@enum@\lastnamedcs
+ \fi
+ \ekvc@err@unknown@enum{#2}{#3}{#1}%
+ }
+ \def\ekvc@h@enum@#1\fi\ekvc@err@unknown@enum#2#3#4%
+ {%
+ \fi
+ \ifx#1\relax
+ \ekvc@err@unknown@enum{#2}{#3}{#4}%
+ \expandafter\@gobble
+ \fi
+ #1%
+ }
+ }
+ {%
+ \def\ekvc@h@enum#1%
+ {%
+ \def\ekvc@h@enum##1\ekvc@stop##2##3%
+ {%
+ \expandafter\ekvc@h@enum@
+ \csname\ifcsname#1\endcsname#1\else relax\fi\endcsname
+ {##2}{##3}{##1}%
+ }%
+ }
+ \expandafter\ekvc@h@enum\expandafter{\ekvc@enum@name{#2}{#3}{#1}}
+ \def\ekvc@h@enum@#1#2#3#4%
+ {%
+ \ifx#1\relax
+ \ekvc@err@unknown@enum{#2}{#3}{#4}%
+ \expandafter\@gobble
+ \fi
+ #1%
+ }
+ }
+% \end{macrocode}
+% We don't need |\ekvc@enum@name| anymore, so let's undefine it.
+% \begin{macrocode}
+\let\ekvc@enum@name\ekvc@undefined
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{aggregate,e-aggregate}
+% Aggregating isn't easy to define. We'll have to extract the correct mark for
+% the specified key, branch correctly for short and long keys, and use a small
+% hack to have the correct arguments on the user interface (|#1| as the
+% current contents, |#2| as the new value). This is split into a few steps
+% here.
+%
+% First, assert that the user input is well-behaved.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{aggregate}
+ {%
+ \let\ekvc@type@aggregate@ifexpanded\@secondoftwo
+ \ekvc@type@aggregate{#1}{#3}%
+ }
+\ekvpDefType{ekvc@setup@secondary}{e-aggregate}
+ {%
+ \let\ekvc@type@aggregate@ifexpanded\@firstoftwo
+ \ekvc@type@aggregate{#1}{#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvc@type@aggregate,\ekvc@type@aggregate@a,\ekvc@type@aggregate@b}
+% The next step stores the user defined processing in a temporary macro that's
+% used to do the parameter number swapping later. It also builds the names of
+% the key macro and the helper which would be used for processing a short key.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@aggregate#1#2%
+ {%
+ \ekvc@assert@not@long
+ \ekvpAssertTwoValues{#2}%
+ \ekvc@type@aggregate@a
+ \ekvc@type@aggregate@long\ekvc@type@aggregate@short
+ {#1}#2%
+ }
+\protected\long\def\ekvc@type@aggregate@a#1#2#3#4#5%
+ {%
+ \ekvc@assert@defined{#4}%
+ \def\ekvc@type@aggregate@tmp##1##2{#5}%
+ \begingroup\expandafter\endgroup
+ \expandafter\ekvc@type@aggregate@b
+ \csname\ekv@name\ekvc@set{#4}\expandafter\endcsname
+ \csname ekvc@\ekvc@set(#4)\endcsname
+ #1#2%
+ {#3}%
+ }
+\protected\long\def\ekvc@type@aggregate@b#1#2#3#4%
+ {%
+ \ekvc@type@aggregate@check@long#1#2%
+ {#3#1}%
+ {#4#2}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@type@aggregate@check@long,
+% \ekvc@type@aggregate@check@long@a,\ekvc@type@aggregate@check@long@b
+% }
+% To check whether the primary key is long we see whether its |\meaning|
+% contains the helper which would only be there for short keys. For this we
+% have to get the stringified name of the internal (using |\detokenize|),
+% and afterwards get the |\meaning| of the macro. A temporary helper does the
+% real test by gobbling and forwarding the result to |\ekv@ifempty|.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@aggregate@check@long#1#2%
+ {\expandafter\ekvc@type@aggregate@check@long@a\detokenize{#2}\ekv@stop#1}
+\protected\long\def\ekvc@type@aggregate@check@long@a#1\ekv@stop#2%
+ {%
+ \def\ekvc@type@aggregate@check@long@@##1#1{}%
+ \expandafter\ekvc@type@aggregate@check@long@b\meaning#2\ekv@stop{#1}%
+ }
+\protected\def\ekvc@type@aggregate@check@long@b#1\ekv@stop#2%
+ {\expandafter\ekv@ifempty\expandafter{\ekvc@type@aggregate@check@long@@#1#2}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@type@aggregate@long,\ekvc@type@aggregate@long@}
+% The long variant just builds the split mark we extract, uses the hack to
+% swap argument order, and then does the definition via |\ekvlet| and a
+% temporary macro.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@aggregate@long#1%
+ {%
+ \begingroup\expandafter\endgroup\expandafter
+ \ekvc@type@aggregate@long@
+ \csname\ekvc@extract@mark#1\expandafter\endcsname
+ \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
+ }
+\protected\long\def\ekvc@type@aggregate@long@#1#2#3%
+ {%
+ \ekvc@type@aggregate@ifexpanded
+ {%
+ \long\def\ekvc@type@aggregate@tmp##1##2#1##3%
+ {\ekv@expanded{\ekv@unexpanded{##2#1}{#2}}}%
+ }%
+ {\long\def\ekvc@type@aggregate@tmp##1##2#1##3{##2#1{#2}}}%
+ \ekvlet\ekvc@set{#3}\ekvc@type@aggregate@tmp
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvc@type@aggregate@short,\ekvc@type@aggregate@short@}
+% The short variant will have to build the marker and the name of the helper
+% function, and swap the user argument order. Hence here are a few more
+% |\expandafter|s involved. But afterwards we can do the definition of the key
+% and the helper macro directly.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@aggregate@short#1#2%
+ {%
+ \begingroup\expandafter\endgroup\expandafter
+ \ekvc@type@aggregate@short@
+ \csname\ekvc@extract@mark#1\expandafter\endcsname
+ \csname ekvc@\ekvc@set(#2)\expandafter\endcsname
+ \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
+ {#2}%
+ }
+\protected\long\def\ekvc@type@aggregate@short@#1#2#3#4%
+ {%
+ \ekvdef\ekvc@set{#4}{#2{##1}}%
+ \ekvc@type@aggregate@ifexpanded
+ {\long\def#2##1##2#1##3{\ekv@expanded{\ekv@unexpanded{##2#1}{#3}}}}%
+ {\long\def#2##1##2#1##3{##2#1{#3}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{process}
+% The |process| type can reuse much of |aggregate|, just the last step of
+% definition differ.
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{process}
+ {%
+ \ekvpAssertTwoValues{#3}%
+ \ifx\ekvc@long\long
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ {%
+ \ekvc@type@aggregate@a
+ \ekvc@type@process@long\ekvc@type@process@long
+ }%
+ {%
+ \ekvc@type@aggregate@a
+ \ekvc@type@process@short\ekvc@type@process@short
+ }%
+ {#1}#3%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@type@process@long,\ekvc@type@process@long@}
+% This defines a temporary macro to grab the current value (found after the
+% marker |#1|), executes the user code and puts everything back to where it
+% belongs. Then |\ekvlet| is used to assign that meaning to the key macro.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@process@long#1%
+ {%
+ \begingroup\expandafter\endgroup\expandafter
+ \ekvc@type@process@long@
+ \csname\ekvc@extract@mark#1\expandafter\endcsname
+ \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
+ }
+\protected\long\def\ekvc@type@process@long@#1#2#3%
+ {%
+ \long\def\ekvc@type@aggregate@tmp##1##2#1##3{#2##2#1{##3}}%
+ \ekvlet\ekvc@set{#3}\ekvc@type@aggregate@tmp
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@type@process@short,\ekvc@type@process@short@}
+% We define the key macro directly to just grab the argument once and forward
+% it to the auxiliary. That one does essentially the same as the long variant.
+% \begin{macrocode}
+\protected\long\def\ekvc@type@process@short#1#2%
+ {%
+ \begingroup\expandafter\endgroup\expandafter
+ \ekvc@type@process@short@
+ \csname\ekvc@extract@mark#1\expandafter\endcsname
+ \csname ekvc@\ekvc@set(#2)\expandafter\endcsname
+ \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
+ {#2}%
+ }
+\protected\long\def\ekvc@type@process@short@#1#2#3#4%
+ {%
+ \ekvdef\ekvc@set{#4}{#2{##1}}%
+ \long\def#2##1##2#1##3{#3##2#1{##3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{flag-bool}
+% \begin{macrocode}
+\ekvpDefType{ekvc@setup@secondary}{flag-bool}
+ {%
+ \ekvc@assert@not@long
+ \ekvpAssertOneValue{#3}%
+ \ifdefined#3\else\ekvcFlagNew#3\fi
+ \ekvdef\ekvc@set{#1}%
+ {%
+ \ekv@ifdefined{ekvc@flag@set@##1}%
+ {%
+ \csname ekvc@flag@set@##1\expandafter\endcsname
+ \ekvcFlagHeight#3\ekv@stop#3%
+ }%
+ {\ekvc@err@invalid@bool{##1}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{flag-true,flag-false,flag-raise}
+% \begin{macro}[internal]{\ekvc@type@flag}
+% \begin{macrocode}
+\protected\def\ekvc@type@flag#1#2#3%
+ {%
+ \ekvc@assert@not@long
+ \ekvpAssertOneValue{#3}%
+ \ifdefined#3\else\ekvcFlagNew#3\fi
+ \ekv@exparg{\ekvdefNoVal\ekvc@set{#2}}{#1#3}%
+ }
+\ekvpDefType{ekvc@setup@secondary}{flag-true}
+ {\ekvc@type@flag\ekvcFlagSetTrue{#1}{#3}}
+\ekvpDefType{ekvc@setup@secondary}{flag-false}
+ {\ekvc@type@flag\ekvcFlagSetFalse{#1}{#3}}
+\ekvpDefType{ekvc@setup@secondary}{flag-raise}
+ {\ekvc@type@flag\ekvcFlagRaise{#1}{#3}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsubsection{Flags}
+%
+% The basic idea of flags is to store information by the fact that \TeX\
+% expandably assigns the meaning |\relax| to undefined control sequences which
+% were built with |\csname|. This mechanism is borrowed from \pkg{expl3}.
+%
+% \begin{macro}[internal]{\ekvc@flag@name,\ekvc@flag@namescheme}
+% Flags follow a simple naming scheme which we define here. |\ekvc@flag@name|
+% will store the name of an internal function that is used to build names of
+% the second naming scheme defined by |\ekvc@flag@namescheme|.
+% \begin{macrocode}
+\def\ekvc@flag@name{ekvcf\string}
+\def\ekvc@flag@namescheme#1#2{ekvch#2#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagHeight}
+% For semantic reasons we use |\number| with another name.
+% \begin{macrocode}
+\let\ekvcFlagHeight\number
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagNew}
+% This macro defines a new flag. It stores the function build with the
+% |\ekvc@flag@name| naming scheme after the internal function
+% |\ekvc@flag@height| that'll determine the current flag height. It'll also
+% define the macro named via |\ekvc@flag@name| to build names according to
+% |\ekvc@flag@namescheme|.
+% \begin{macrocode}
+\protected\def\ekvcFlagNew#1%
+ {%
+ \edef#1%
+ {%
+ \ekv@unexpanded{\ekvc@flag@height}%
+ \ekv@unexpanded\expandafter{\csname\ekvc@flag@name#1\endcsname}%
+ }%
+ \ekv@expargtwice
+ {\expandafter\def\csname\ekvc@flag@name#1\endcsname##1}%
+ {\expandafter\ekvc@flag@namescheme\expandafter{\string#1}{##1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@flag@height,\ekvc@flag@height@}
+% This macro gets the height of a flag by a simple loop. The first loop
+% iteration differs a bit from the following in that it doesn't have to get
+% the current iteration count. The space at the end of |\ekvc@flag@height|
+% ends the |\number| evaluation.
+% \begin{macrocode}
+\def\ekvc@flag@height#1%
+ {%
+ \ifcsname#10\endcsname
+ \ekvc@flag@height@1\ekv@stop#1%
+ \fi
+ \@firstofone{0} % leave this space
+ }
+\def\ekvc@flag@height@#1\ekv@stop#2\fi\@firstofone#3%
+ {%
+ \fi
+ \ifcsname#2{#1}\endcsname
+ \expandafter\ekvc@flag@height@\the\numexpr#1+1\relax\ekv@stop#2%
+ \fi
+ \@firstofone{#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagRaise}
+% Raising a flag simply means letting the |\ekvc@flag@namescheme| macro for
+% the current height to relax. The result of raising a flag is that its height
+% is bigger by $1$.
+% \begin{macrocode}
+\ekv@exparg{\def\ekvcFlagRaise#1}%
+ {%
+ \expandafter\expandafter\expandafter\@gobble\expandafter
+ \csname\ekvc@flag@namescheme{\string#1}{\ekvcFlagHeight#1}\endcsname
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagSetTrue,\ekvcFlagSetFalse}
+% \begin{macro}[internal]{\ekvc@flag@set@true,\ekvc@flag@set@false}
+% A flag is considered true if its current height is odd, and as false if it
+% is even. Therefore |\ekvcFlagSetTrue| and |\ekvcFlagSetFalse| only need to
+% raise the flag if the opposing boolean value is the current one.
+% \begin{macrocode}
+\def\ekvcFlagSetTrue#1%
+ {\expandafter\ekvc@flag@set@true\ekvcFlagHeight#1\ekv@stop#1}
+\def\ekvcFlagSetFalse#1%
+ {\expandafter\ekvc@flag@set@false\ekvcFlagHeight#1\ekv@stop#1}
+% \end{macrocode}
+% We can expand |\ekvc@flag@namescheme| at definition time here, which is why
+% we're using a temporary definition to set up |\ekvc@flag@set@true| and
+% |\ekvc@flag@set@false|.
+% \begin{macrocode}
+\def\ekvc@flag@set@true#1%
+ {%
+ \def\ekvc@flag@set@true##1\ekv@stop##2%
+ {%
+ \ifodd##1
+ \ekv@fi@gobble
+ \fi
+ \@firstofone{\expandafter\@gobble\csname#1\endcsname}%
+ }%
+ \def\ekvc@flag@set@false##1\ekv@stop##2%
+ {%
+ \ifodd##1
+ \ekv@fi@firstofone
+ \fi
+ \@gobble{\expandafter\@gobble\csname#1\endcsname}%
+ }%
+ }
+\expandafter\ekvc@flag@set@true\expandafter
+ {\ekvc@flag@namescheme{\string#2}{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagIf}
+% As already explained, truthiness is defined as a flag's height being odd, so
+% we just branch accordingly here.
+% \begin{macrocode}
+\def\ekvcFlagIf#1%
+ {%
+ \ifodd#1%
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagIfRaised}
+% This macro uses flags as a switch, if a flag's current height is bigger than
+% $0$ this test yields true.
+% \begin{macrocode}
+\ekv@exparg{\def\ekvcFlagIfRaised#1}%
+ {%
+ \expandafter\ifcsname\ekvc@flag@namescheme{\string#1}0\endcsname
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagReset,\ekvcFlagResetGlobal}
+% \begin{macro}[internal]{\ekvc@flag@reset,\ekvc@flag@reset@}
+% Resetting works by locally letting all the defined internal macros named
+% after |\ekvc@flag@namescheme| to undefined.
+% \begin{macrocode}
+\protected\def\ekvcFlagReset#1%
+ {\expandafter\ekvc@flag@reset\csname\ekvc@flag@name#1\endcsname{}}
+\protected\def\ekvcFlagResetGlobal#1%
+ {\expandafter\ekvc@flag@reset\csname\ekvc@flag@name#1\endcsname\global}
+\protected\def\ekvc@flag@reset#1#2%
+ {%
+ \ifcsname#10\endcsname
+ #2\expandafter\let\csname#10\endcsname\ekvc@undefined
+ \ekvc@flag@reset@1\ekv@stop#1{#2}%
+ \fi
+ }
+\protected\def\ekvc@flag@reset@#1\ekv@stop#2#3\fi
+ {%
+ \fi
+ \ifcsname#2{#1}\endcsname
+ #3\expandafter\let\csname#2{#1}\endcsname\ekvc@undefined
+ \expandafter\ekvc@flag@reset@\the\numexpr#1+1\relax\ekv@stop#2{#3}%
+ \fi
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagGetHeight}
+% \begin{macro}[internal]{\ekvc@flag@get@height@single}
+% These are just small helpers, first getting the height of the flag and then
+% passing it on to the user supplied code.
+% \begin{macrocode}
+\def\ekvcFlagGetHeight#1%
+ {\expandafter\ekvc@flag@get@height@single\ekvcFlagHeight#1\ekv@stop}
+\long\def\ekvc@flag@get@height@single#1\ekv@stop#2{#2{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvcFlagGetHeights}
+% \begin{macro}[internal]
+% {\ekvc@flag@get@heights,\ekvc@flag@get@heights@,\ekvc@flag@get@heights@done}
+% This works by a simple loop that stops at |\ekv@stop|. As long as that
+% marker isn't hit, get the next flags height and put it into a list after
+% |\ekv@stop|. |\ekvc@flag@get@heights@| uses the same marker name for the
+% end of the height, which shouldn't clash in any case. Once we're done we
+% remove the remainder of the current iteration and leave the user supplied
+% code in the input stream with all the flags' heights as a single argument.
+% \begin{macrocode}
+\def\ekvcFlagGetHeights#1%
+ {%
+ \ekvc@flag@get@heights#1\ekv@stop{}%
+ }
+\def\ekvc@flag@get@heights#1%
+ {%
+ \ekv@gobbleto@stop#1\ekvc@flag@get@heights@done\ekv@stop
+ \expandafter\ekvc@flag@get@heights@\ekvcFlagHeight#1\ekv@stop
+ }
+\def\ekvc@flag@get@heights@#1\ekv@stop#2\ekv@stop#3%
+ {\ekvc@flag@get@heights#2\ekv@stop{#3{#1}}}
+\long\def\ekvc@flag@get@heights@done
+ \ekv@stop
+ \expandafter\ekvc@flag@get@heights@\ekvcFlagHeight\ekv@stop\ekv@stop#1#2%
+ {#2{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsubsection{Helper Macros}
+%
+% \begin{macro}[internal]{\ekvc@extract@mark,\ekvc@extract@mark@}
+% This is used to extract the mark of a split or hash key from its definition.
+% This is kind of fragile, it assumes |#1| is always a macro used for hashing
+% or splitting. Also it assumes that the escape character is a backslash.
+% \begin{macrocode}
+\def\ekvc@extract@mark#1{\expandafter\ekvc@extract@mark@\meaning#1\ekv@stop}
+\begingroup
+\lccode`;=`#
+\lccode`/=`\\
+\lowercase{\endgroup
+\def\ekvc@extract@mark@#1:#2/#3 ;#4\ekv@stop{#3}%
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Assertions}
+%
+% \begin{macro}[internal]{\ekvc@assert@not@long}
+% Some keys don't want to be |long| and we have to educate the user, so let's
+% throw an error if someone wanted these to be long.
+% \begin{macrocode}
+\ekv@exparg{\def\ekvc@assert@not@long}%
+ {\ekvpAssertIfNot{\ifx\ekvc@long\long}{`long' not accepted}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@assert@defined,\ekvc@assert@k@or@p@defined}
+% Since some keys interact with existing other keys we need to assert those
+% exist.
+% \begin{macrocode}
+\long\def\ekvc@assert@defined#1%
+ {\ekvpAssertTF{\ekvifdefined\ekvc@set{#1}}{undefined key `#1'}}
+\long\def\ekvc@assert@k@or@p@defined#1%
+ {%
+ \ekvpAssertTF
+ {\ekvifdefined\ekvc@set{#1}\@firstoftwo{\ekvifdefinedNoVal\ekvc@set{#1}}}%
+ {undefined key `#1'}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Messages}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@errm,
+% \ekvc@err@toomany,\ekvc@err@value@required,
+% \ekvc@err@already@defined,\ekvc@err@no@key@macro,
+% }
+% Boring unexpandable error messages.
+% \begin{macrocode}
+\protected\long\def\ekvc@errm#1{\errmessage{expkv-cs Error: #1}}
+\protected\long\def\ekvc@err@toomany#1%
+ {\ekvc@errm{Too many keys for macro `\string#1'}}
+\protected\long\def\ekvc@err@value@required#1%
+ {\ekvc@errm{Missing value for key `\ekv@unexpanded{#1}'}}
+\protected\long\def\ekvc@err@already@defined#1%
+ {\ekvc@errm{Macro `\string#1' already defined}}
+\protected\long\def\ekvc@err@no@key@macro#1%
+ {\ekvc@errm{\string#1 is no key=val macro}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvc@err}
+% We need a way to throw error messages expandably in some contexts.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekvc@err#1}{\ekverr{expkv-cs}{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvc@err@unknown@hash,\ekvc@err@empty@hash,\ekvc@err@missing@hash,
+% \ekvc@err@invalid@bool,\ekvc@err@unknown@key@or@macro,
+% \ekvc@err@unknown@enum
+% }
+% And here are the expandable error messages.
+% \begin{macrocode}
+\long\def\ekvc@err@unknown@hash#1{\ekvc@err{unknown hash `#1'}}
+\long\def\ekvc@err@missing@hash#1{\ekvc@err{hash `#1' not found}}
+\long\def\ekvc@err@empty@hash{\ekvc@err{empty hash}}
+\def\ekvc@err@invalid@bool#1{\ekvc@err{invalid boolean value `#1'}}
+\long\def\ekvc@err@unknown@key@or@macro#1#2%
+ {\ekvc@err{unknown key `#2' for #1}}
+\def\ekvc@err@unknown@enum#1#2#3%
+ {\ekvc@err{unknown choice `#3' for `#2' in #1}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% Now everything that's left is to reset the category code of |@|.
+% \begin{macrocode}
+\catcode`\@=\ekvc@tmp
+% \end{macrocode}
+%
+% \gobbledocstriptag
+%</tex>
+%^^A=<<
diff --git a/macros/generic/expkv-bundle/expkv-def.dtx b/macros/generic/expkv-bundle/expkv-def.dtx
new file mode 100644
index 0000000000..33933425e6
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-def.dtx
@@ -0,0 +1,1369 @@
+% \iffalse meta-comment
+%
+% File: expkv-def.dtx Copyright (C) 2020-2023 Jonathan P. Spratte
+%
+% This work may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this license or
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% ------------------------------------------------------------------------------
+%
+%<*driver>^^A>>=
+\def\expkvDocNoGenerate{}
+\input expkv-bundle.ins
+\generate{\file{expkv-def.sty}{\from{expkv-def.dtx}{pkg}}}
+\generate{\file{expkv-def.tex}{\from{expkv-def.dtx}{tex}}}
+\generate{\file{t-expkv-def.tex}{\from{expkv-def.dtx}{ctx}}}
+\endbatchfile
+%</driver>^^A=<<
+% \fi
+%
+% \section{\expkvd}
+%^^A the LaTeX package >>=
+% \subsection{The \LaTeX\ Package}
+% Just like for \expkv\ we provide a small \LaTeX\ package that sets up things
+% such that we behave nicely on \LaTeX\ packages and files system. It'll
+% |\input| the generic code which implements the functionality.
+% \gobbledocstriptag
+%<*pkg>
+% \begin{macrocode}
+\RequirePackage{expkv-pop}
+\def\ekvd@tmp
+ {%
+ \ProvidesFile{expkv-def.tex}%
+ [\ekvdDate\space v\ekvdVersion\space a key-defining frontend for expkv]%
+ }
+\input{expkv-def.tex}
+\ProvidesPackage{expkv-def}%
+ [\ekvdDate\space v\ekvdVersion\space a key-defining frontend for expkv]
+% \end{macrocode}
+% \gobbledocstriptag
+%</pkg>
+%^^A=<<
+%^^A the ConTeXt module >>=
+% \subsection{The \ConTeXt\ module}
+% \gobbledocstriptag
+%<*ctx>
+% \begin{macrocode}
+\writestatus{loading}{ConTeXt User Module / expkv-def}
+\usemodule[expkv-pop]
+\unprotect
+\input expkv-def.tex
+\writestatus{loading}
+ {ConTeXt User Module / expkv-def / Version \ekvdVersion\space loaded}
+\protect\endinput
+% \end{macrocode}
+% \gobbledocstriptag
+%</ctx>
+%^^A=<<
+%^^A main file >>=
+% \subsection{The Generic Code}
+% The rest of this implementation will be the generic code.
+% \gobbledocstriptag
+%<*tex>
+%
+% Load \expkv\ if the package didn't already do so -- since \expkv\ has
+% safeguards against being loaded twice this does no harm and the overhead
+% isn't that big. Also we reuse some of the internals of \expkv\ to save us from
+% retyping them. Additionally load \expkvp, which aids in defining the type
+% system (and \expkvp\ will actually do the \expkv\ loading).
+% \begin{macrocode}
+\input expkv-pop
+% \end{macrocode}
+%
+% We make sure that \file{expkv-def.tex} is only input once:
+% \begin{macrocode}
+\expandafter\ifx\csname ekvdVersion\endcsname\relax
+\else
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% \begin{macro}{\ekvdVersion,\ekvdDate}
+% We're on our first input, so lets store the version and date in a macro.
+% \begin{macrocode}
+\def\ekvdVersion{1.0}
+\def\ekvdDate{2023-01-23}
+% \end{macrocode}
+% \end{macro}
+%
+% If the \LaTeX\ format is loaded we want to be a good file and report back who
+% we are, for this the package will have defined |\ekvd@tmp| to use
+% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
+% \begin{macrocode}
+\csname ekvd@tmp\endcsname
+% \end{macrocode}
+%
+% Store the category code of |@| to later be able to reset it and change it to
+% 11 for now.
+% \begin{macrocode}
+\expandafter\chardef\csname ekvd@tmp\endcsname=\catcode`\@
+\catcode`\@=11
+% \end{macrocode}
+% |\ekvd@tmp| will be reused later to handle expansion during the key
+% defining. But we don't need it to ever store information long-term after
+% \expkvd\ was initialized.
+%
+% \begin{macro}[internal]{\ekvd@ifprimitive}
+% \begin{macrocode}
+\protected\long\def\ekvd@ifprimitive#1%
+ {%
+ \begingroup
+ \edef\ekvd@tmpa{\string #1}%
+ \edef\ekvd@tmpb{\meaning#1}%
+ \expandafter
+ \endgroup
+ \ifx\ekvd@tmpa\ekvd@tmpb
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvd@long,\ekvd@prot,\ekvd@clear@prefixes,\ekvd@ifalso}
+% \expkvd\ will use |\ekvd@long|, |\ekvd@prot|, and |\ekvd@ifalso| to store
+% whether a key should be defined as |\long| or |\protected| or adds an action
+% to an existing key, and we have to clear them for every new key. By default
+% |long| and |protected| will just be empty, |ifalso| will be
+% |\@secondoftwo|, and |ifnew| will just use its third argument.
+% \begin{macrocode}
+\protected\def\ekvd@clear@prefixes
+ {%
+ \let\ekvd@long\ekv@empty
+ \let\ekvd@prot\ekv@empty
+ \let\ekvd@ifalso\@secondoftwo
+ \let\ekvd@do@new\@gobbletwo
+ }
+\ekvd@clear@prefixes
+% \end{macrocode}
+% \end{macro}
+%
+% We define the parser for our front-facing macro and its \prefix{}es here:
+% \begin{macrocode}
+\ekvpNewParser{ekvd@definekeys}
+\ekvpDefNoValuePrefix{ekvd@definekeys}
+ {\let\ekvd@ifnoarg\@firstoftwo}
+ {\let\ekvd@ifnoarg\@secondoftwo}
+\ekvpDefPrefixLet{ekvd@definekeys}{long} \ekvd@long\long \ekv@empty
+\ekvpDefPrefixLet{ekvd@definekeys}{protected}\ekvd@prot\protected\ekv@empty
+\ekvpDefPrefixLet{ekvd@definekeys}{protect} \ekvd@prot\protected\ekv@empty
+\ekvpDefPrefixLet{ekvd@definekeys}{also}\ekvd@ifalso\@firstoftwo\@secondoftwo
+\ekvpDefPrefixLet{ekvd@definekeys}{new}\ekvd@do@new\ekvd@assert@new\@gobbletwo
+% \end{macrocode}
+% We ease the process of error throwing a bit for now by using our own macro
+% instead of relying on \expkvp's argument forwarding.
+% \begin{macrocode}
+\ekvpDefAutoPrefix{ekvd@definekeys}{\edef\ekvd@cur{\detokenize{#3}}}{}
+% \end{macrocode}
+%
+% \begin{macro}{\ekvdefinekeys}
+% This is the one front-facing macro which provides the interface to define
+% keys. It stores the \set\ for which the keys should be defined in
+% |\ekvd@set| and calls a parser defined with \expkvp.
+% \begin{macrocode}
+\protected\edef\ekvdefinekeys#1%
+ {%
+ \ekv@unexpanded{\def\ekvd@set}{#1}%
+ \ekv@unexpanded{\ekvpParse@unsafe@auto\ekvp@@p@ekvd@definekeys}%
+ \ekv@unexpanded\expandafter{\csname\ekvp@@p@ekvd@definekeys{ppa}\endcsname}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Key Types}
+%
+% \begin{macro}[internal]{\ekvd@def@type,\ekvd@def@type@fwd}
+% To reduce some typing the following is a shortcut to |\ekvpDefType|. The
+% |@fwd| variant will forward the key name and value and remove the
+% unprocessed key. The other variant automatically sets up a helper macro,
+% unfortunately this is necessary due to the design decision of \expkvp\ to
+% not |\detokenize| the key names while \expkvd\ used to do this very early.
+% \begin{macrocode}
+\protected\def\ekvd@def@type#1#2%
+ {%
+ \ekv@exparg{\ekvpDefType{ekvd@definekeys}{#1}}
+ {%
+ \expandafter\expandafter\csname ekvd@th@#1\endcsname
+ \detokenize{##1}\ekv@stop{##2}{##3}%
+ }%
+ \long\expandafter\def\csname ekvd@th@#1\endcsname##1\ekv@stop##2##3{#2}%
+ }
+\protected\long\def\ekvd@def@type@fwd#1#2%
+ {\ekvpDefType{ekvd@definekeys}{#1}{\ekv@exparg{#2}{\detokenize{##1}}{##3}}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{set}
+% \begin{macro}[internal]{\ekvd@type@set}
+% \begin{macrocode}
+\ekvd@def@type{set}
+ {\ekvd@ifnoarg{\ekvd@type@set{#1}{#1}}{\ekvd@type@set{#1}{#3}}}
+\protected\def\ekvd@type@set#1#2%
+ {%
+ \ekvd@assert@not@long
+ \ekvd@assert@not@protected
+ \ekvd@do@new{NoVal}{#1}%
+ \ekv@ifempty{#2}%
+ {\ekvd@err@missing@definition}%
+ {%
+ \ekvd@ifalso
+ {%
+ \ekv@expargtwice{\ekvd@add@noval{#1}}%
+ {\ekvchangeset{#2}}%
+ \ekvd@assert@not@protected@also
+ }%
+ {\ekv@expargtwice{\ekvdefNoVal\ekvd@set{#1}}{\ekvchangeset{#2}}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{noval,enoval}
+% \begin{macro}[internal]{\ekvd@type@noval}
+% Another pretty simple type, |noval| just needs to assert that there is a
+% definition and that |long| wasn't specified.
+% There are types where the difference in the variants is so small, that we
+% define a common handler for them, those common handlers are named with
+% |@type@|. |noval| and |enoval| are so similar that we can use such a |@type@|
+% macro, even if we could've done |noval| in a slightly faster way without it.
+% \begin{macrocode}
+\ekvd@def@type@fwd{noval}{\ekvd@type@noval\def}
+\ekvd@def@type@fwd{enoval}{\ekvd@type@noval\edef}
+\protected\long\def\ekvd@type@noval#1#2#3%
+ {%
+ \ekvd@do@new{NoVal}{#2}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@long
+ \ekvd@prot#1\ekvd@tmp{#3}%
+ \ekvd@ifalso
+ {\ekv@exparg{\ekvd@add@noval{#2}}\ekvd@tmp{}}%
+ {\ekvletNoVal\ekvd@set{#2}\ekvd@tmp}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{code,ecode}
+% \begin{macro}[internal]{\ekvd@type@code}
+% |code| is simple as well, |ecode| has to use |\edef| on a temporary macro,
+% since \expkv\ doesn't provide an |\ekvedef|.
+% \begin{macrocode}
+\ekvd@def@type@fwd{code}{\ekvd@type@code\def}
+\ekvd@def@type@fwd{ecode}{\ekvd@type@code\edef}
+\protected\long\def\ekvd@type@code#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@arg
+ \ekvd@prot\ekvd@long#1\ekvd@tmp##1{#3}%
+ \ekvd@ifalso
+ {\ekv@exparg{\ekvd@add@val{#2}}{\ekvd@tmp{##1}}{}}%
+ {\ekvlet\ekvd@set{#2}\ekvd@tmp}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{default,qdefault,odefault,fdefault,edefault}
+% \begin{macro}[internal]
+% {
+% \ekvd@type@default,\ekvd@t@default,\ekvd@t@qdefault,\ekvd@t@odefault,
+% \ekvd@t@fdefault
+% }
+% |\ekvd@type@default| asserts there was an argument, also the key for which one
+% wants to set a default has to be already defined (this is not so important for
+% |default|, but |qdefault| requires it). If everything is good, |\edef| a
+% temporary macro that expands |\ekvd@set| and the |\csname| for the key.
+% The different expansion variants are implemented via |\ekv@unexpanded| and
+% some |\expandafter|s.
+% \begin{macrocode}
+\ekvd@def@type@fwd{default}{\ekvd@type@default{\ekv@unexpanded\expandafter}{}}
+\ekvd@def@type@fwd{odefault}
+ {\ekvd@type@default{\ekv@unexpanded\expandafter\expandafter\expandafter}{}}
+\ekvpLet{ekvd@definekeys}{type}{qdefault}{odefault}
+\ekvd@def@type@fwd{fdefault}
+ {\ekvd@type@default{\ekv@unexpanded\expandafter}{\romannumeral`\^^@}}
+\protected\long\def\ekvd@type@default#1#2#3#4%
+ {%
+ \ekvd@assert@arg
+ \ekvd@do@new{NoVal}{#3}%
+ \ekvd@assert@not@long
+ \ekvifdefined\ekvd@set{#3}%
+ {%
+ \ekvd@prot\edef\ekvd@tmp
+ {#1{#2\csname\ekv@name\ekvd@set{#3}\endcsname{#4}}}%
+ \ekvd@ifalso
+ {\ekv@exparg{\ekvd@add@noval{#3}}\ekvd@tmp{}}%
+ {\ekvletNoVal\ekvd@set{#3}\ekvd@tmp}%
+ }%
+ {\ekvd@err@undefined@key{#3}}%
+ }
+\ekvd@def@type{edefault}
+ {%
+ \ekvd@assert@arg
+ \ekvd@do@new{NoVal}{#1}%
+ \ekvd@assert@not@long
+ \ekvifdefined\ekvd@set{#1}%
+ {%
+ \ekvd@prot\edef\ekvd@tmp
+ {%
+ \ekv@unexpanded\ekv@expanded
+ {{\csname\ekv@name\ekvd@set{#1}\endcsname{#3}}}%
+ }%
+ \ekvd@ifalso
+ {\ekv@exparg{\ekvd@add@noval{#1}}\ekvd@tmp{}}%
+ {\ekvletNoVal\ekvd@set{#1}\ekvd@tmp}%
+ }%
+ {\ekvd@err@undefined@key{#1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{initial,oinitial,finitial,einitial}
+% \begin{macro}[internal]{\ekvd@type@initial}
+% \begin{macrocode}
+\ekvd@def@type@fwd{initial}{\ekvd@type@initial\@firstofone}
+\ekvd@def@type@fwd{oinitial}{\ekvd@type@initial\ekv@exparg}
+\ekvd@def@type@fwd{einitial}{\ekvd@type@initial\ekv@expandedarg}
+\ekvd@def@type@fwd{finitial}{\ekvd@type@initial\ekv@fexparg}
+\long\def\ekvd@type@initial#1#2#3%
+ {%
+ \ekvd@assert@not@new
+ \ekvd@assert@not@also
+ \ekvd@assert@not@long
+ \ekvd@assert@not@protected
+ \ekvd@ifnoarg
+ {%
+ \ekvifdefinedNoVal\ekvd@set{#2}%
+ {\csname\ekv@name\ekvd@set{#2}N\endcsname}%
+ {\ekvd@err@undefined@noval{#2}}%
+ }%
+ {%
+ \ekvifdefined\ekvd@set{#2}%
+ {#1{\csname\ekv@name\ekvd@set{#2}\endcsname}{#3}}%
+ {\ekvd@err@undefined@key{#2}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{bool,gbool,boolTF,gboolTF,invbool,ginvbool,invboolTF,ginvboolTF}
+% \begin{macro}[internal]{\ekvd@type@bool}
+% The boolean types are a quicker version of a |choice| that accept |true| and
+% |false|, and set up the |NoVal| action to be identical to \texttt{\key=true}.
+% The |true| and |false| actions are always just |\let|ting the macro in |#7| to
+% some other macro (\emph{e.g.}, \cs[no-index]{iftrue}).
+% \begin{macrocode}
+\ekvd@def@type@fwd{bool}{\ekvd@type@bool{}\iftrue\iffalse}
+\ekvd@def@type@fwd{gbool}{\ekvd@type@bool\global\iftrue\iffalse}
+\ekvd@def@type@fwd{boolTF}{\ekvd@type@bool{}\@firstoftwo\@secondoftwo}
+\ekvd@def@type@fwd{gboolTF}{\ekvd@type@bool\global\@firstoftwo\@secondoftwo}
+\ekvd@def@type@fwd{invbool}{\ekvd@type@bool{}\iffalse\iftrue}
+\ekvd@def@type@fwd{ginvbool}{\ekvd@type@bool\global\iffalse\iftrue}
+\ekvd@def@type@fwd{invboolTF}{\ekvd@type@bool{}\@secondoftwo\@firstoftwo}
+\ekvd@def@type@fwd{ginvboolTF}{\ekvd@type@bool\global\@secondoftwo\@firstoftwo}
+\protected\def\ekvd@type@bool#1#2#3#4#5%
+ {%
+ \ekvd@do@new{}{#4}%
+ \ekvd@do@new{NoVal}{#4}%
+ \ekvd@assert@filledarg{#5}%
+ \ekvd@newlet#5#3%
+ \ekvd@type@choice{#4}%
+ \protected\ekvdefNoVal\ekvd@set{#4}{#1\let#5#2}%
+ \protected\expandafter\def
+ \csname\ekvd@choice@name\ekvd@set{#4}{true}\endcsname
+ {#1\let#5#2}%
+ \protected\expandafter\def
+ \csname\ekvd@choice@name\ekvd@set{#4}{false}\endcsname
+ {#1\let#5#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{boolpair,gboolpair,boolpairTF,gboolpairTF}
+% \begin{macro}[internal]{\ekvd@type@boolpair}
+% The boolean pair types are essentially the same as the boolean types, but set
+% two macros instead of one.
+% \begin{macrocode}
+\ekvd@def@type{boolpair}
+ {\ekvd@assert@twoargs{#3}\ekvd@type@boolpair{}\iftrue\iffalse{#1}#3}
+\ekvd@def@type{gboolpair}
+ {\ekvd@assert@twoargs{#3}\ekvd@type@boolpair\global\iftrue\iffalse{#1}#3}
+\ekvd@def@type{boolpairTF}
+ {\ekvd@assert@twoargs{#3}\ekvd@type@boolpair{}\@firstoftwo\@secondoftwo{#1}#3}
+\ekvd@def@type{gboolpairTF}
+ {%
+ \ekvd@assert@twoargs{#3}%
+ \ekvd@type@boolpair\global\@firstoftwo\@secondoftwo{#1}#3%
+ }
+\protected\def\ekvd@type@boolpair#1#2#3#4#5#6%
+ {%
+ \ekvd@do@new{}{#4}%
+ \ekvd@do@new{NoVal}{#4}%
+ \ekvd@newlet#5#3%
+ \ekvd@newlet#6#2%
+ \ekvd@type@choice{#4}%
+ \protected\ekvdefNoVal\ekvd@set{#4}{#1\let#5#2#1\let#6#3}%
+ \protected\expandafter\def
+ \csname\ekvd@choice@name\ekvd@set{#4}{true}\endcsname
+ {#1\let#5#2#1\let#6#3}%
+ \protected\expandafter\def
+ \csname\ekvd@choice@name\ekvd@set{#4}{false}\endcsname
+ {#1\let#5#3#1\let#6#2}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{data,gdata,dataT,gdataT}
+% \begin{macro}[internal]{\ekvd@type@data}
+% \begin{macrocode}
+\ekvd@def@type@fwd{data}
+ {\ekvd@type@data\@secondoftwo\edef{####2}{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{edata}
+ {%
+ \ekvd@type@data\@secondoftwo\edef
+ {####2}{\ekv@unexpanded\ekv@expanded{{##1}}}%
+ }
+\ekvd@def@type@fwd{gdata}
+ {\ekvd@type@data\@secondoftwo\xdef{####2}{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{xdata}
+ {%
+ \ekvd@type@data\@secondoftwo\xdef
+ {####2}{\ekv@unexpanded\ekv@expanded{{##1}}}%
+ }
+\ekvd@def@type@fwd{dataT}{\ekvd@type@data\@gobble\edef{}{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{edataT}
+ {\ekvd@type@data\@gobble\edef{}{\ekv@unexpanded\ekv@expanded{{##1}}}}
+\ekvd@def@type@fwd{gdataT}{\ekvd@type@data\@gobble\xdef{}{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{xdataT}
+ {\ekvd@type@data\@gobble\xdef{}{\ekv@unexpanded\ekv@expanded{{##1}}}}
+\protected\def\ekvd@type@data#1#2#3#4#5#6%
+ {%
+ \ekvd@do@new{}{#5}%
+ \ekvd@assert@filledarg{#6}%
+ \ekvd@newlet#6#1%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#5}{\long#2#6####1#3{####1{#4}}}{}%
+ }%
+ {%
+ \protected\ekvd@long\ekvdef\ekvd@set{#5}%
+ {\long#2#6####1#3{####1{#4}}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{box,gbox}
+% \begin{macro}[internal]{\ekvd@type@box}
+% Set up our boxes. Though we're a generic package we want to be colour safe, so
+% we put an additional grouping level inside the box contents, for the case that
+% someone uses \pkg{color}. |\ekvd@newreg| is a small wrapper which tests
+% whether the first argument is defined and if not does
+% |\csname new#2\endcsname#1|.
+% \begin{macrocode}
+\ekvd@def@type@fwd{box}{\ekvd@type@box{}}
+\ekvd@def@type@fwd{gbox}{\ekvd@type@box\global}
+\protected\def\ekvd@type@box#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{box}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}{#1\setbox#3=\hbox{\begingroup##1\endgroup}}{}%
+ }%
+ {%
+ \protected\ekvd@long\ekvdef\ekvd@set{#2}%
+ {#1\setbox#3=\hbox{\begingroup##1\endgroup}}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{toks,gtoks}
+% \begin{macro}[internal]{\ekvd@type@toks}
+% Similar to |box|, but set the |toks|.
+% \begin{macrocode}
+\ekvd@def@type@fwd{toks}{\ekvd@type@toks{}}
+\ekvd@def@type@fwd{gtoks}{\ekvd@type@toks\global}
+\protected\def\ekvd@type@toks#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{toks}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}{#1#3={##1}}{}%
+ }%
+ {\protected\ekvd@long\ekvdef\ekvd@set{#2}{#1#3={##1}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@type@preapptoks,\ekvd@t@apptoks,\ekvd@t@gapptoks}
+% Just like |toks|, but expand the current contents of the |toks| register to
+% append the new contents.
+% \begin{macrocode}
+\ekvd@ifprimitive\toksapp
+ {%
+ \ekvd@def@type@fwd{apptoks}{\ekvd@type@preapptoks\toksapp}
+ \ekvd@def@type@fwd{gapptoks}{\ekvd@type@preapptoks\gtoksapp}
+ \ekvd@def@type@fwd{pretoks}{\ekvd@type@preapptoks\tokspre}
+ \ekvd@def@type@fwd{gpretoks}{\ekvd@type@preapptoks\gtokspre}
+ \protected\def\ekvd@type@preapptoks#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{toks}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}{#1#3{##1}}{}%
+ }%
+ {\protected\ekvd@long\ekvdef\ekvd@set{#2}{#1#3{##1}}}%
+ }
+ }
+ {%
+ \ekvd@def@type@fwd{apptoks}{\ekvd@type@apptoks{}}
+ \ekvd@def@type@fwd{gapptoks}{\ekvd@type@apptoks\global}
+ \protected\def\ekvd@type@apptoks#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{toks}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}{#1#3=\expandafter{\the#3##1}}{}%
+ }%
+ {%
+ \protected\ekvd@long\ekvdef\ekvd@set{#2}%
+ {#1#3=\expandafter{\the#3##1}}%
+ }%
+ }
+ \ekvd@def@type@fwd{pretoks}{\ekvd@type@pretoks{}}
+ \ekvd@def@type@fwd{gpretoks}{\ekvd@type@pretoks\global}
+ \newtoks\ekvd@toks
+ \protected\def\ekvd@type@pretoks#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@filledarg{#3}%
+ \ekvd@newreg#3{toks}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#2}%
+ {#1#3=\ekv@expanded{{\ekv@unexpanded{##1}\the#3}}}%
+ {}%
+ }%
+ {%
+ \protected\ekvd@long\ekvdef\ekvd@set{#2}%
+ {#1#3=\ekv@expanded{{\ekv@unexpanded{##1}\the#3}}}%
+ }%
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {int,eint,gint,xint,dimen,edimen,gdimen,xdimen,skip,eskip,gskip,xskip}
+% \begin{macro}[internal]{\ekvd@type@register}
+% The |\ekvd@type@register| can handle all the types for which the assignment will
+% just be \texttt{\meta{register}=\meta{value}}.
+% \begin{macrocode}
+\ekvd@def@type@fwd {int}{\ekvd@type@register{count}{}{}}
+\ekvd@def@type@fwd{eint}{\ekvd@type@register{count}{}\numexpr}
+\ekvd@def@type@fwd{gint}{\ekvd@type@register{count}\global{}}
+\ekvd@def@type@fwd{xint}{\ekvd@type@register{count}\global\numexpr}
+\ekvd@def@type@fwd {dimen}{\ekvd@type@register{dimen}{}{}}
+\ekvd@def@type@fwd{edimen}{\ekvd@type@register{dimen}{}\dimexpr}
+\ekvd@def@type@fwd{gdimen}{\ekvd@type@register{dimen}\global{}}
+\ekvd@def@type@fwd{xdimen}{\ekvd@type@register{dimen}\global\dimexpr}
+\ekvd@def@type@fwd {skip}{\ekvd@type@register{skip}{}{}}
+\ekvd@def@type@fwd{eskip}{\ekvd@type@register{skip}{}\glueexpr}
+\ekvd@def@type@fwd{gskip}{\ekvd@type@register{skip}\global{}}
+\ekvd@def@type@fwd{xskip}{\ekvd@type@register{skip}\global\glueexpr}
+\protected\def\ekvd@type@register#1#2#3#4#5%
+ {%
+ \ekvd@do@new{}{#4}%
+ \ekvd@assert@filledarg{#5}%
+ \ekvd@newreg#5{#1}%
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#4}{#2#5=#3##1\relax}{}%
+ }%
+ {\protected\ekvd@long\ekvdef\ekvd@set{#4}{#2#5=#3##1\relax}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{store,gstore,estore,xstore}
+% \begin{macro}[internal]{\ekvd@type@store}
+% The none-expanding |store| types use an |\edef| or |\xdef| and |\unexpanded|
+% to be able to also store |#| easily.
+% \begin{macrocode}
+\ekvd@def@type@fwd{store}{\ekvd@type@store\edef{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{gstore}{\ekvd@type@store\xdef{\ekv@unexpanded{##1}}}
+\ekvd@def@type@fwd{estore}
+ {\ekvd@type@store\edef{\ekv@unexpanded\ekv@expanded{{##1}}}}
+\ekvd@def@type@fwd{xstore}
+ {\ekvd@type@store\xdef{\ekv@unexpanded\ekv@expanded{{##1}}}}
+\protected\def\ekvd@type@store#1#2#3#4%
+ {%
+ \ekvd@do@new{}{#3}%
+ \ekvd@assert@filledarg{#4}%
+ \ekvd@newlet#4\ekv@empty
+ \ekvd@ifalso
+ {%
+ \let\ekvd@prot\protected
+ \ekvd@add@val{#3}{#1#4{#2}}{}%
+ }%
+ {\protected\ekvd@long\ekvdef\ekvd@set{#3}{#1#4{#2}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{meta,nmeta}
+% \begin{macro}[internal]{\ekvd@type@meta}
+% |meta| sets up things such that another instance of |\ekvset| will be run on
+% the argument, with the same \set.
+% \begin{macrocode}
+\ekvd@def@type@fwd{meta}
+ {\ekvd@type@meta{}{##1}\ekvd@add@val{{##1}}{}\ekv@exparg}
+\ekvd@def@type@fwd{nmeta}
+ {%
+ \ekvd@assert@not@long
+ \ekvd@type@meta
+ {NoVal}{}\ekvd@add@noval{}\ekvd@assert@not@long@also\ekv@expargtwice
+ }
+\protected\long\def\ekvd@type@meta#1#2#3#4#5#6#7#8%
+ {%
+ \ekvd@do@new{#1}{#7}%
+ \ekvd@assert@filledarg{#8}%
+ #6{\ekvd@prot\ekvd@long\def\ekvd@tmp#2}{\ekvmorekv{#8}}%
+ \ekvd@ifalso
+ {\ekv@exparg{#3{#7}}{\ekvd@tmp#4}{#5}}%
+ {\csname ekvlet#1\endcsname\ekvd@set{#7}\ekvd@tmp}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{smeta,snmeta}
+% \begin{macro}[internal]
+% {\ekvd@type@smeta,\ekvd@type@smeta@}
+% |smeta| is pretty similar to |meta|, but needs two arguments inside of \val,
+% such that the first is the \set\ for which the sub-|\ekvset| and the second is
+% the \kv\ list.
+% \begin{macrocode}
+\ekvd@def@type@fwd{smeta}{\ekvd@type@smeta{}{##1}\ekvd@add@val{{##1}}{}}
+\ekvd@def@type@fwd{snmeta}
+ {%
+ \ekvd@assert@not@long
+ \ekvd@type@smeta{NoVal}{}\ekvd@add@noval{}\ekvd@assert@not@long@also
+ }
+\protected\long\def\ekvd@type@smeta#1#2#3#4#5#6#7%
+ {%
+ \ekvd@do@new{#1}{#6}%
+ \ekvd@assert@twoargs{#7}%
+ \ekvd@type@smeta@#7{#2}%
+ \ekvd@ifalso
+ {\ekv@exparg{#3{#6}}{\ekvd@tmp#4}{#5}}%
+ {\csname ekvlet#1\endcsname\ekvd@set{#6}\ekvd@tmp}%
+ }
+\protected\long\def\ekvd@type@smeta@#1#2#3%
+ {\ekvd@prot\ekvd@long\ekv@expargtwice{\def\ekvd@tmp#3}{\ekvset{#1}{#2}}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{choice}
+% \begin{macro}[internal]{\ekvd@type@choice,\ekvd@populate@choice}
+% The real key definition of a |choice| type is pretty simple, the heavy
+% lifting is done by a helper macro at run time. Though setting up the choices
+% needs a bit of work. First the key macro definition.
+% \begin{macrocode}
+\protected\def\ekvd@type@choice#1%
+ {%
+ \ekvd@assert@not@long
+ \ekv@expargtwice{\ekvd@prot\def\ekvd@tmp##1}%
+ {%
+ \expandafter\expandafter\expandafter
+ \ekvd@h@choice
+ \expandafter\expandafter\expandafter
+ {\expandafter\ekvd@choice@name\expandafter{\ekvd@set}{#1}{##1}}%
+ }%
+ \ekvd@ifalso
+ {%
+ \ekvd@assert@val{#1}%
+ \ekvd@if@not@already@choice{#1}%
+ {%
+ \ekv@exparg
+ {%
+ \expandafter\ekvd@add@aux
+ \csname\ekv@name\ekvd@set{#1}\endcsname{{##1}}{#1}%
+ }%
+ {\ekvd@tmp{##1}}%
+ {\ekvd@long\ekvdef}\ekvd@assert@not@long@also
+ }%
+ }%
+ {\ekvlet\ekvd@set{#1}\ekvd@tmp}%
+ }
+% \end{macrocode}
+% The set up of different choices is done through another parser, that one
+% needs relatively few types though.
+% \begin{macrocode}
+\ekvpNewParser{ekvd@populate@choice}
+\ekvpValueAlwaysRequired{ekvd@populate@choice}
+\ekvpDefType{ekvd@populate@choice}{protect}
+ {\ekvd@populate@choice\protected{#1}{#3}}
+\ekvpDefType{ekvd@populate@choice}{unprotect}{\ekvd@populate@choice{}{#1}{#3}}
+\ekvpDefNoType{ekvd@populate@choice} {\ekvd@populate@choice{}{#1}{#3}}
+\ekvpLet{ekvd@populate@choice}{type}{protected}{protect}
+\ekvpLet{ekvd@populate@choice}{type}{unprotected}{unprotect}
+% \end{macrocode}
+% The choice definition is done by the following little helper:
+% \begin{macrocode}
+\protected\long\def\ekvd@populate@choice#1#2#3%
+ {%
+ #1\expandafter\edef
+ \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname
+ {\ekv@unexpanded{#3}}%
+ }
+% \end{macrocode}
+% And we define the real type:
+% \begin{macrocode}
+\ekvd@def@type{choice}
+ {%
+ \ekvd@do@new{}{#1}%
+ \ekvd@assert@arg
+ \ekvd@type@choice{#1}%
+ \def\ekvd@set@choice{#1}%
+ \ekvpParse@unsafe\ekvp@@p@ekvd@populate@choice{#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{choice-store,choice-enum}
+% These two types define a special kind of |choice| key and are quite similar,
+% the only difference is what the different choices do (hence they use a
+% shared initialisation which differs in the chosen |populate| step).
+% \begin{macrocode}
+\ekvd@def@type@fwd{choice-store}
+ {\ekvd@type@choicespecial\ekvd@populate@choicestore}
+\ekvd@def@type@fwd{choice-enum}
+ {\ekvd@type@choicespecial\ekvd@populate@choiceenum}
+% \end{macrocode}
+% \begin{macro}[internal]{\ekvd@type@choicespecial}
+% Initialise similar to a |choice| key. The difference is that we require two
+% arguments (which we assert), a macro to store things in, and a |csv|-list
+% containing the allowed values. |#1| is the |populate| macro according to the
+% type used.
+% \begin{macrocode}
+\protected\long\def\ekvd@type@choicespecial#1#2#3%
+ {%
+ \ekvd@do@new{}{#2}%
+ \ekvd@assert@twoargs{#3}%
+ \ekvd@type@choice{#2}%
+ \def\ekvd@set@choice{#2}%
+ #1#3%
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {\ekvd@populate@choicestore,\ekvd@populate@choicestore@}
+% We initialise the storing macro if it doesn't yet exist, and then we loop
+% over the value list. The |\edef|s with |\unexpanded| are both necessary to
+% be able to store macro parameter tokens (the outer protects at define time,
+% the inner at use time).
+% \begin{macrocode}
+\protected\long\def\ekvd@populate@choicestore#1%
+ {%
+ \ekvd@newlet#1\ekv@empty
+ \ekvparse{\ekvd@populate@choicestore@k#1}{\ekvd@populate@choicestore@kv#1}%
+ }
+\protected\long\def\ekvd@populate@choicestore@kv#1#2#3%
+ {%
+ \protected\expandafter\edef
+ \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname
+ {\ekv@unexpanded{\edef#1{\ekv@unexpanded{#3}}}}%
+ }
+\ekv@exparg{\protected\long\def\ekvd@populate@choicestore@k#1#2}%
+ {\ekvd@populate@choicestore@kv{#1}{#2}{#2}}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {\ekvd@populate@choiceenum,\ekvd@populate@choiceenum@}
+% This is similar to the population of a |choice-store| type, but instead of
+% storing the values in a macro this initialises a count and stores the
+% position of the value in the list inside that count (zero-indexed). The
+% space is necessary to terminate the number scanning, which is the reason we
+% use |\@firstofone| (so that the space after the macro name isn't gobbled by
+% \TeX).
+% \begin{macrocode}
+\protected\long\def\ekvd@populate@choiceenum#1%
+ {%
+ \ekvd@newreg#1{count}%
+ \def\ekvd@tmp{0}%
+ \ekvcsvloop{\ekvd@populate@choiceenum@#1}%
+ }
+\protected\long\def\ekvd@populate@choiceenum@#1#2%
+ {%
+ \protected\expandafter\edef
+ \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname
+ {#1=\@firstofone{\ekvd@tmp} }%
+ \edef\ekvd@tmp{\the\numexpr\ekvd@tmp+1\relax}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{unknown-choice}
+% \begin{macrocode}
+\ekvd@def@type{unknown-choice}
+ {%
+ \ekvd@do@new@for@name{\ekvd@unknown@choice@name\ekvd@set{#1}}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@long
+ \ekvd@assert@not@also
+ \ekvd@prot\expandafter
+ \def\csname\ekvd@unknown@choice@name\ekvd@set{#1}\endcsname##1{#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{unknown}
+% \begin{macro}[internal]{\ekvd@type@unknown@code,\ekvd@type@unknown@noval}
+% The |unknown| type has different subtypes which would be the key names for
+% other types. It is first checked whether that subtype is defined, if it
+% isn't throw an error, else use that subtype.
+% \begin{macrocode}
+\ekvd@def@type{unknown}
+ {%
+ \ekv@ifdefined{ekvd@type@unknown@\detokenize{#1}}%
+ {\csname ekvd@type@unknown@\detokenize{#1}\endcsname{#3}}%
+ \ekvd@err@misused@unknown
+ }
+% \end{macrocode}
+% The |unknown noval| type can use |\ekvdefunknownNoVal| directly (after
+% asserting some prefixes).
+% \begin{macrocode}
+\protected\long\def\ekvd@type@unknown@noval#1%
+ {%
+ \ekvd@do@new@for@name{\ekv@name\ekvd@set{}uN}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@also
+ \ekvd@prot\ekvd@long\ekvdefunknownNoVal\ekvd@set{#1}%
+ }
+% \end{macrocode}
+% The |unknown code| type uses some trickery during the definition in order to
+% swap out |#1| and |#2| in the user supplied definition. This is done via a
+% temporary macro that stores the definition but gets the parameter numbers
+% reversed while the real definition is done.
+% \begin{macrocode}
+\protected\long\def\ekvd@type@unknown@code#1%
+ {%
+ \ekvd@do@new@for@name{\ekv@name\ekvd@set{}u}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@also
+ \begingroup
+ \def\ekvd@tmp##1##2##3{#1}%
+ \ekv@exparg
+ {%
+ \endgroup
+ \ekvd@prot\ekvd@long\ekvdefunknown\ekvd@set
+ }%
+ {\ekvd@tmp{##2}{##1}{##3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@type@unknown@redirect,
+% \ekvd@type@unknown@redirect-code,
+% \ekvd@type@unknown@redirect-noval
+% }
+% The |unknown redirect| types also just forward to |\ekvredirectunknown|
+% after asserting some prefixes.
+% \begin{macrocode}
+\protected\edef\ekvd@type@unknown@redirect#1%
+ {%
+ \expandafter\noexpand\csname ekvd@type@unknown@redirect-code\endcsname{#1}%
+ \expandafter\noexpand\csname ekvd@type@unknown@redirect-noval\endcsname{#1}%
+ }
+\protected\expandafter\def\csname ekvd@type@unknown@redirect-code\endcsname#1%
+ {%
+ \ekvd@do@new@for@name{\ekv@name\ekvd@set{}u}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@also
+ \ekvd@assert@not@protected
+ \expandafter\ekvredirectunknown\expandafter{\ekvd@set}{#1}%
+ }
+\protected\expandafter\def\csname ekvd@type@unknown@redirect-noval\endcsname#1%
+ {%
+ \ekvd@do@new@for@name{\ekv@name\ekvd@set{}uN}%
+ \ekvd@assert@arg
+ \ekvd@assert@not@also
+ \ekvd@assert@not@protected
+ \expandafter\ekvredirectunknownNoVal\expandafter{\ekvd@set}{#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Key Type Helpers}
+% There are some keys that might need helpers during their execution (not during
+% their definition, which are gathered as |@type@| macros). These helpers are
+% named |@h@|.
+%
+% \begin{macro}[internal]{\ekvd@h@choice,\ekvd@h@choice@}
+% The |choice| helper will just test whether the given choice was defined, if
+% not throw an error expandably, else call the macro which stores the code for
+% this choice.
+% \begin{macrocode}
+\def\ekvd@h@choice#1%
+ {%
+ \expandafter\ekvd@h@choice@
+ \csname\ifcsname#1\endcsname#1\else relax\fi\endcsname
+ {#1}%
+ }
+\def\ekvd@h@choice@#1#2%
+ {%
+ \ifx#1\relax
+ \ekvd@err@choice@invalid{#2}%
+ \expandafter\@gobble
+ \fi
+ #1%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Handling \texttt{also}}
+%
+% \begin{macro}[internal]
+% {\ekvd@add@val,\ekvd@add@noval,\ekvd@add@aux,\ekvd@add@aux@}
+% \begin{macrocode}
+\protected\long\def\ekvd@add@val#1#2#3%
+ {%
+ \ekvd@assert@val{#1}%
+ \expandafter\ekvd@add@aux\csname\ekv@name\ekvd@set{#1}\endcsname{{##1}}%
+ {#1}{#2}{\ekvd@long\ekvdef}{#3}%
+ }
+\protected\long\def\ekvd@add@noval#1#2#3%
+ {%
+ \ekvd@assert@noval{#1}%
+ \expandafter\ekvd@add@aux\csname\ekv@name\ekvd@set{#1}N\endcsname{}%
+ {#1}{#2}\ekvdefNoVal{#3}%
+ }
+\protected\long\def\ekvd@add@aux#1#2%
+ {%
+ \ekvd@extract@prefixes#1%
+ \expandafter\ekvd@add@aux@\expandafter{#1#2}%
+ }
+% \end{macrocode}
+% Once we're done with adding something to the definition of a key we need to
+% clear the prefixes. Maybe it would be better to only restore them if they
+% were changed by the |\ekvd@extract@prefixes| mechanism, but I think this is
+% fine with just resetting all (there should be no code dependent on any of
+% the prefix storing macros after this was run).
+% \begin{macrocode}
+\protected\long\def\ekvd@add@aux@#1#2#3#4#5%
+ {%
+ #5%
+ \ekvd@prot#4\ekvd@set{#2}{#1#3}%
+ \ekvd@clear@prefixes
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@extract@prefixes,\ekvd@extract@prefixes@,
+% \ekvd@extract@prefixes@long,\ekvd@extract@prefixes@prot
+% }
+% This macro checks which prefixes were used for the definition of a macro and
+% sets |\ekvd@long| and |\ekvd@prot| accordingly.
+% \begin{macrocode}
+\protected\def\ekvd@extract@prefixes#1%
+ {%
+ \expandafter\ekvd@extract@prefixes@\meaning#1\ekvd@stop
+ }
+% \end{macrocode}
+% In the following definition |#1| will get replaced by |macro:|, |#2| by
+% |\long| and |#3| by |\protected| (in each, all tokens will have category
+% other). This allows us to parse the |\meaning| of a macro for those strings.
+% \begin{macrocode}
+\protected\def\ekvd@extract@prefixes@#1#2#3%
+ {%
+ \protected\def\ekvd@extract@prefixes@##1#1##2\ekvd@stop
+ {%
+ \ekvd@extract@prefixes@long
+ ##1\ekvd@mark\@firstofone#2\ekvd@mark\@gobble\ekvd@stop
+ {\let\ekvd@long\long}%
+ \ekvd@extract@prefixes@prot
+ ##1\ekvd@mark\@firstofone#3\ekvd@mark\@gobble\ekvd@stop
+ {\let\ekvd@prot\protected}%
+ }%
+ \protected\def\ekvd@extract@prefixes@long##1#2##2\ekvd@mark##3##4\ekvd@stop
+ {##3}%
+ \protected\def\ekvd@extract@prefixes@prot##1#3##2\ekvd@mark##3##4\ekvd@stop
+ {##3}%
+ }
+% \end{macrocode}
+% We use a temporary macro to expand the three arguments of
+% |\ekvd@extract@prefixes@|, which will set up the real meaning of itself and
+% the parsing for |\long| and |\protected|.
+% \begin{macrocode}
+\begingroup
+\edef\ekvd@tmp
+ {%
+ \endgroup
+ \ekvd@extract@prefixes@
+ {\detokenize{macro:}}%
+ {\string\long}%
+ {\string\protected}%
+ }
+\ekvd@tmp
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsubsection{Tests}
+%
+% \begin{macro}[internal]{\ekvd@newlet,\ekvd@newreg}
+% These macros test whether a control sequence is defined, if it isn't they
+% define it, either via |\let| or via the correct \cs[no-index]{new\meta{reg}}.
+% \begin{macrocode}
+\protected\def\ekvd@newlet#1#2%
+ {%
+ \ifdefined#1%
+ \ifx#1\relax\ekv@fi@gobble\fi\@firstofone
+ \ekv@fi@gobble
+ \fi
+ \@firstofone{\let#1#2}%
+ }
+\protected\def\ekvd@newreg#1#2%
+ {%
+ \ifdefined#1%
+ \ifx#1\relax\ekv@fi@gobble\fi\@firstofone
+ \ekv@fi@gobble
+ \fi
+ \@firstofone{\csname new#2\endcsname#1}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvd@assert@twoargs,\ekvd@ifnottwoargs,\ekvd@ifempty@gtwo}
+% A test for exactly two tokens can be reduced for an empty-test after gobbling
+% two tokens, in the case that there are fewer tokens than two in the argument,
+% only macros will be gobbled that are needed for the true branch, which doesn't
+% hurt, and if there are more this will not be empty.
+% \begin{macrocode}
+\long\def\ekvd@assert@twoargs#1%
+ {\ekvd@ifnottwoargs{#1}{\ekvd@err@missing@definition\ekvpGobbleT}{}}
+\long\def\ekvd@ifnottwoargs#1%
+ {%
+ \ekvd@ifempty@gtwo#1\ekv@ifempty@B
+ \ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ }
+\long\def\ekvd@ifempty@gtwo#1#2{\ekv@ifempty@\ekv@ifempty@A}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@assert@val,\ekvd@assert@val@,\ekvd@assert@noval,\ekvd@assert@noval@,
+% \ekvd@extract@args,\ekvd@extracted@args,\ekvd@one@arg@string
+% }
+% Assert that a given key is defined as a value taking key or a |NoVal| key with
+% the correct argument structure, respectively.
+% \begin{macrocode}
+\protected\def\ekvd@assert@val#1%
+ {%
+ \ekvifdefined\ekvd@set{#1}%
+ {\expandafter\ekvd@assert@val@\csname\ekv@name\ekvd@set{#1}\endcsname}%
+ {%
+ \ekvifdefinedNoVal\ekvd@set{#1}%
+ \ekvd@err@add@val@on@noval
+ {\ekvd@err@undefined@key{#1}}%
+ \ekvpGobbleT
+ }%
+ }
+\protected\def\ekvd@assert@val@#1%
+ {%
+ \expandafter\ekvd@extract@args\meaning#1\ekvd@stop
+ \unless\ifx\ekvd@extracted@args\ekvd@one@arg@string
+ \ekvd@err@unsupported@arg
+ \expandafter\ekvpGobbleT
+ \fi
+ }%
+\protected\def\ekvd@assert@noval#1%
+ {%
+ \ekvifdefinedNoVal\ekvd@set{#1}%
+ {\expandafter\ekvd@assert@noval@\csname\ekv@name\ekvd@set{#1}N\endcsname}%
+ {%
+ \ekvifdefined\ekvd@set{#1}%
+ \ekvd@err@add@noval@on@val
+ {\ekvd@err@undefined@key{#1}}%
+ \ekvpGobbleT
+ }%
+ }
+\protected\def\ekvd@assert@noval@#1%
+ {%
+ \expandafter\ekvd@extract@args\meaning#1\ekvd@stop
+ \unless\ifx\ekvd@extracted@args\ekv@empty
+ \ekvd@err@unsupported@arg
+ \expandafter\ekvpGobbleT
+ \fi
+ }
+\protected\def\ekvd@extract@args#1%
+ {%
+ \protected\def\ekvd@extract@args##1#1##2->##3\ekvd@stop
+ {\def\ekvd@extracted@args{##2}}%
+ }
+\expandafter\ekvd@extract@args\expandafter{\detokenize{macro:}}
+\edef\ekvd@one@arg@string{\string#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@assert@arg,\ekvd@ifnoarg}
+% The |\ekvd@ifnoarg| macro is initialised as |\@secondoftwo|. Each time a key
+% without an argument is encountered it will be set to |\@firstoftwo| for the
+% scope of that key's parsing.
+% \begin{macrocode}
+\def\ekvd@assert@arg{\ekvd@ifnoarg{\ekvd@err@missing@definition\ekvpGobbleT}{}}
+\let\ekvd@ifnoarg\@secondoftwo
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@assert@filledarg,\ekvd@ifnoarg@or@empty}
+% \begin{macrocode}
+\long\def\ekvd@assert@filledarg#1%
+ {\ekvd@ifnoarg@or@empty{#1}{\ekvd@err@missing@definition\ekvpGobbleT}{}}
+\long\def\ekvd@ifnoarg@or@empty#1%
+ {%
+ \ekvd@ifnoarg
+ \@firstoftwo
+ {\ekv@ifempty{#1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@assert@not@long,\ekvd@assert@not@protected,\ekvd@assert@not@also,
+% \ekvd@assert@not@long@also,\ekvd@assert@not@protected@also,
+% \ekvd@assert@new,\ekvd@assert@not@new
+% }
+% Some key-types don't want to be |also|, |\long| or |\protected|, so we provide
+% macros to test this and throw an error, this could be silently ignored but now
+% users will learn to not use unnecessary stuff which slows the compilation
+% down.
+% \begin{macrocode}
+\def\ekvd@assert@not@long{\ifx\ekvd@long\long\ekvd@err@no@prefix{long}\fi}
+\def\ekvd@assert@not@protected
+ {\ifx\ekvd@prot\protected\ekvd@err@no@prefix{protected}\fi}
+\def\ekvd@assert@not@also{\ekvd@ifalso{\ekvd@err@no@prefix{also}}{}}
+\def\ekvd@assert@not@long@also
+ {\ifx\ekvd@long\long\ekvd@err@no@prefix@also{long}\fi}
+\def\ekvd@assert@not@protected@also
+ {\ifx\ekvd@prot\protected\ekvd@err@no@prefix@also{protected}\fi}
+\def\ekvd@assert@new#1#2%
+ {%
+ \csname ekvifdefined#1\endcsname\ekvd@set{#2}%
+ {\ekvd@err@not@new\ekvpGobbleT}%
+ {}%
+ }
+\def\ekvd@assert@not@new
+ {\ifx\ekvd@do@new\ekvd@assert@new\ekvd@err@no@prefix{new}\fi}
+\def\ekvd@do@new@for@name#1%
+ {%
+ \ifx\ekvd@do@new\ekvd@assert@new
+ \ekv@fi@firstofone
+ \fi
+ \@gobble{\ekv@ifdefined{#1}{\ekvd@err@not@new\ekvpGobbleT}{}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@if@not@already@choice, \ekvd@if@not@already@choice@a,
+% \ekvd@if@not@already@choice@b
+% }
+% It is bad to use |also| on a key that already contains a |choice|, as both
+% choices would share the same valid values and thus lead to each callback being
+% used twice. The following is a rudimentary test against this.
+% \begin{macrocode}
+\protected\def\ekvd@if@not@already@choice#1%
+ {%
+ \expandafter\ekvd@if@not@already@choice@a
+ \csname\ekv@name\ekvd@set{#1}\endcsname
+ {}\ekvd@h@choice\ekvd@stop
+ }
+\protected\def\ekvd@if@not@already@choice@a
+ {%
+ \expandafter\ekvd@if@not@already@choice@b
+ }
+\long\protected\def\ekvd@if@not@already@choice@b#1\ekvd@h@choice#2\ekvd@stop
+ {%
+ \ekv@ifempty{#2}\@firstofone\@gobble
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@ifspace,\ekvd@ifspace@}
+% Yet another test which can be reduced to an if-empty, this time by gobbling
+% everything up to the first space.
+% \begin{macrocode}
+\long\def\ekvd@ifspace#1%
+ {%
+ \ekvd@ifspace@#1 \ekv@ifempty@B
+ \ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ }
+\long\def\ekvd@ifspace@#1 % keep this space
+ {%
+ \ekv@ifempty@\ekv@ifempty@A
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Messages}
+%
+% Most messages of \expkvd\ are not expandable, since they only appear during
+% key-definition, which is not expandable anyway.
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@errm,\ekvd@err@missing@definition,
+% \ekvd@err@missing@type,\ekvd@err@undefined@prefix,\ekvd@err@undefined@key,
+% \ekvd@err@no@prefix,\ekvd@err@no@prefix@also,
+% \ekvd@err@add@val@on@noval,\ekvd@err@add@noval@on@val,
+% \ekvd@err@unsupported@arg,\ekvd@err@not@new
+% }
+% The non-expandable error messages are boring, so here they are:
+% \begin{macrocode}
+\protected\long\def\ekvd@errm#1{\errmessage{expkv-def Error: #1}}
+\protected\def\ekvd@err@missing@definition
+ {\ekvd@errm{Missing definition for key `\ekvd@cur'}}
+\protected\def\ekvd@err@missing@type
+ {\ekvd@errm{Missing type prefix for key `\ekvd@cur'}}
+\protected\def\ekvd@err@undefined@prefix#1%
+ {%
+ \ekvd@errm
+ {%
+ Undefined prefix `\ekv@unexpanded{#1}' found while processing
+ `\ekvd@cur'%
+ }%
+ }
+\protected\def\ekvd@err@undefined@key#1%
+ {%
+ \ekvd@errm
+ {Undefined key `\ekv@unexpanded{#1}' found while processing `\ekvd@cur'}%
+ }
+\protected\def\ekvd@err@undefined@noval#1%
+ {%
+ \ekvd@errm
+ {%
+ Undefined noval key `\ekv@unexpanded{#1}' found while processing
+ `\ekvd@cur'%
+ }%
+ }
+\protected\def\ekvd@err@no@prefix#1%
+ {\ekvd@errm{prefix `#1' not accepted in `\ekvd@cur'}}
+\protected\def\ekvd@err@no@prefix@also#1%
+ {\ekvd@errm{`\ekvd@cur' not allowed with a `#1' key}}
+\protected\def\ekvd@err@add@val@on@noval
+ {\ekvd@errm{`\ekvd@cur' not allowed with a NoVal key}}
+\protected\def\ekvd@err@add@noval@on@val
+ {\ekvd@errm{`\ekvd@cur' not allowed with a value taking key}}
+\protected\def\ekvd@err@unsupported@arg
+ {%
+ \ekvd@errm
+ {%
+ Existing key-macro has the unsupported argument string
+ `\ekvd@extracted@args' for key `\ekvd@cur'%
+ }%
+ }
+\protected\def\ekvd@err@not@new
+ {\ekvd@errm{The key for `\ekvd@cur' is already defined}}
+\protected\long\def\ekvd@err@misused@unknown
+ {\ekvd@errm{Misuse of the unknown type found while processing `\ekvd@cur'}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvd@err@choice@invalid,\ekvd@err@choice@invalid@,\ekvd@choice@name,
+% \ekvd@unknown@choice@name
+% }
+% |\ekvd@err@choice@invalid| will have to use this mechanism to throw its
+% message. Also we have to retrieve the name parts of the choice in an easy way,
+% so we use parentheses of catcode 8 here, which should suffice in most cases to
+% allow for a correct separation.
+% \begin{macrocode}
+\def\ekvd@err@choice@invalid#1%
+ {%
+ \ekvd@err@choice@invalid@#1%
+ }
+\begingroup
+\catcode40=8
+\catcode41=8
+\@firstofone{\endgroup
+\def\ekvd@choice@name#1#2#3%
+ {%
+ ekvd#1(#2)\detokenize{#3}%
+ }
+\def\ekvd@unknown@choice@name#1#2%
+ {%
+ ekvd:u:#1(#2)%
+ }
+\def\ekvd@err@choice@invalid@ ekvd#1(#2)\detokenize#3%
+ {%
+ \ekv@ifdefined{\ekvd@unknown@choice@name{#1}{#2}}%
+ {\csname\ekvd@unknown@choice@name{#1}{#2}\endcsname{#3}}%
+ {\ekvd@err{invalid choice `#3' for `#2' in set `#1'}}%
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvd@err}
+% The expandable error messages use |\ekvd@err|, which is just like |\ekv@err|
+% from \expkv. It uses a runaway argument to start the error message.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekvd@err#1}{\ekverr{expkv-def}{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% Now everything that's left is to reset the category code of |@|.
+% \begin{macrocode}
+\catcode`\@=\ekvd@tmp
+% \end{macrocode}
+%
+% \gobbledocstriptag
+%</tex>
+%^^A=<<
diff --git a/macros/generic/expkv-opt/expkv-opt-2020-10-10.dtx b/macros/generic/expkv-bundle/expkv-opt-2020-10-10.dtx
index ab2dcec41a..2bc84dafaa 100644
--- a/macros/generic/expkv-opt/expkv-opt-2020-10-10.dtx
+++ b/macros/generic/expkv-bundle/expkv-opt-2020-10-10.dtx
@@ -1,6 +1,6 @@
% \iffalse meta-comment
%
-% File: expkv-opt.dtx Copyright (C) 2020 Jonathan P. Spratte
+% File: expkv-opt.dtx Copyright (C) 2020-2023 Jonathan P. Spratte
%
% This work may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this license or
@@ -27,7 +27,7 @@ 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
+Copyright (C) 2020-2023 Jonathan P. Spratte
This work may be distributed and/or modified under the conditions of the
LaTeX Project Public License (LPPL), either version 1.3c of this license or
@@ -42,6 +42,8 @@ This work is "maintained" (as per LPPL maintenance status) by
This work consists of the file expkv-opt.dtx
and the derived files expkv-opt.pdf
expkv-opt.sty
+and the file expkv-opt-2020-10-10.dtx
+and the derived file expkv-opt-2020-10-10.sty
\endpreamble
% stop docstrip adding \endinput
@@ -51,7 +53,7 @@ and the derived files expkv-opt.pdf
\ifx\fmtname\nameofplainTeX
\expandafter\endbatchfile
\else
- \expandafter\endgroup
+ \expandafter\endgroup\expandafter\stop
\fi
%
\IfFileExists{expkv-opt.sty}{\RequirePackage{expkv-opt}}{}
@@ -481,7 +483,7 @@ and the derived files expkv-opt.pdf
% \begin{macro}{\ekvoVersion,\ekvoDate}
% Store the packages version and date in two macros.
% \begin{macrocode}
-\newcommand*\ekvoVersion{0.1b}
+\newcommand*\ekvoVersion{0.1c}
\newcommand*\ekvoDate{2020-10-10}
% \end{macrocode}
% \end{macro}
@@ -502,11 +504,12 @@ and the derived files expkv-opt.pdf
% {\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.
+% delimiters for the actual loop. The |\ekv@set@other| is necessary to get a
+% functional |\ekvmorekv| in this loop.
% \begin{macrocode}
\protected\long\def\ekvo@CurrentOption@loop#1#2%
{%
- \ekvo@CurrentOption@loop@#2\ekv@mark#1,\ekv@stop,\ekvo@tail
+ \ekvo@CurrentOption@loop@#2\ekv@set@other\ekv@mark#1,\ekv@stop,\ekvo@tail
}
% \end{macrocode}
% The actual loop checks whether the final element has been read and if so
@@ -514,16 +517,16 @@ and the derived files expkv-opt.pdf
% the macro which parses the list elements called. Then call the next
% iteration.
% \begin{macrocode}
-\long\def\ekvo@CurrentOption@loop@#1#2,%
+\long\def\ekvo@CurrentOption@loop@#1\ekv@set@other#2,%
{%
\ekv@gobble@from@mark@to@stop#2\ekvo@end@loop\ekv@stop
\ekv@ifblank{#2}%
{}%
{%
- \edef\CurrentOption{\unexpanded\expandafter{\@gobble#2}}%
+ \edef\CurrentOption{\unexpanded\expandafter{\ekv@gobble@mark#2}}%
#1{#2}%
}%
- \ekvo@CurrentOption@loop@#1\ekv@mark
+ \ekvo@CurrentOption@loop@#1\ekv@set@other\ekv@mark
}
\long\def\ekvo@end@loop#1\ekvo@tail{}
% \end{macrocode}
@@ -727,10 +730,9 @@ and the derived files expkv-opt.pdf
% \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
+ \ekv@expanded
+ {\ekv@unexpanded{\ekvparse\ekvo@set@k\ekvo@set@kv}\expandafter}%
+ \expandafter{\ekv@gobble@mark#1}\ekvo@tail
}
% \end{macrocode}
% \end{macro}
diff --git a/macros/generic/expkv-bundle/expkv-opt.dtx b/macros/generic/expkv-bundle/expkv-opt.dtx
new file mode 100644
index 0000000000..d2b51d0cb0
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-opt.dtx
@@ -0,0 +1,796 @@
+% \iffalse meta-comment
+%
+% File: expkv-opt.dtx Copyright (C) 2020-2023 Jonathan P. Spratte
+%
+% This work may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this license or
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% ------------------------------------------------------------------------------
+%
+%<*driver>^^A>>=
+\def\expkvDocNoGenerate{}
+\input expkv-bundle.ins
+\generate{\file{expkv-opt.sty}{\from{expkv-opt.dtx}{pkg}}}
+\endbatchfile
+%</driver>^^A=<<
+% \fi
+%
+% \section{\expkvo}
+%
+% \gobbledocstriptag
+%<*pkg>
+%
+% First we check whether the \LaTeXe\ kernel supports raw options. If it doesn't
+% we check whether a specific version was requested, and if that's not the case
+% we manually run |\pkgcls@parse@date@arg| with the last version that supported
+% non-raw options.
+% \begin{macrocode}
+\IfFormatAtLeastTF{2021/05/01}
+ {}
+ {%
+ \ifx\pkgcls@targetlabel\@empty
+ \ifnum\requestedLaTeXdate=\pkgcls@targetdate
+ \pkgcls@parse@date@arg{=v0.1}%
+ \fi
+ \fi
+ }
+% \end{macrocode}
+% Then we tell \LaTeXe\ where to find which release so that the package rollback
+% code of \LaTeXe\ can do its thing.
+% \begin{macrocode}
+\DeclareRelease{v0.1}{2020/10/10}{expkv-opt-2020-10-10.sty}
+\DeclareCurrentRelease{v0.2}{2021/04/04}
+% \end{macrocode}
+%
+% Start the package with the typical \LaTeX\ standards.
+%
+% \begin{macro}{\ekvoVersion,\ekvoDate}
+% Store the package's version and date in two macros.
+% \begin{macrocode}
+\newcommand*\ekvoVersion{1.0}
+\newcommand*\ekvoDate{2023-01-23}
+% \end{macrocode}
+% \end{macro}
+% And we report who we are and what we need.
+% \begin{macrocode}
+\ProvidesPackage{expkv-opt}
+ [%
+ \ekvoDate\space v\ekvoVersion\space
+ parse class and package options with expkv%
+ ]
+\RequirePackage{expkv}
+% \end{macrocode}
+%
+%
+% \subsection{Loop}
+%
+% \begin{macro}[internal]
+% {\ekvo@CurrentOption@loop,\ekvo@CurrentOption@loop@,\ekvo@end@loop}
+% We'll need some loop which can iterate over a comma separated list. The loop
+% is very basic and only works for commas of category~12. First we insert the
+% delimiters for the actual loop. The |\ekv@set@other| is necessary to get a
+% functional |\ekvmorekv| in this loop.
+% \begin{macrocode}
+\protected\long\def\ekvo@CurrentOption@loop#1#2%
+ {%
+ \ekvo@CurrentOption@loop@#2\ekv@set@other\ekv@mark#1,\ekv@stop,\ekvo@tail
+ }
+% \end{macrocode}
+% The actual loop checks whether the final element has been read and if so
+% ends the loop. Else blank elements are ignored, |\CurrentOption| is set and
+% the macro which parses the list elements called. Then call the next
+% iteration.
+% \begin{macrocode}
+\long\def\ekvo@CurrentOption@loop@#1\ekv@set@other#2,%
+ {%
+ \ekv@gobble@from@mark@to@stop#2\ekvo@end@loop\ekv@stop
+ \ekv@ifblank{#2}%
+ {}%
+ {%
+ \edef\CurrentOption{\unexpanded\expandafter{\ekv@gobble@mark#2}}%
+ #1{#2}%
+ }%
+ \ekvo@CurrentOption@loop@#1\ekv@set@other\ekv@mark
+ }
+\long\def\ekvo@end@loop#1\ekvo@tail{}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Tests}
+%
+% \begin{macro}[internal]{\ekvo@ifx@TF,\ekvo@ifx@T,\ekvo@ifx@F}
+% We'll need branching |\ifx| tests so that user input containing unbalanced
+% \TeX\ ifs doesn't break (at least not because of us, everything else is the
+% fault of \LaTeXe).
+% \begin{macrocode}
+\def\ekvo@ifx@TF#1#2{\ifx#1#2\ekv@fi@firstoftwo\fi\@secondoftwo}
+\def\ekvo@ifx@T#1#2{\ifx#1#2\ekv@fi@firstofone\fi\@gobble}
+\def\ekvo@ifx@F#1#2{\ifx#1#2\ekv@fi@gobble\fi\@firstofone}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvo@do@with@set,\ekvo@name,\ekvo@setname}
+% This test checks whether the \set\ is defined. If it is we store it in
+% |\ekvo@setname| and set |\ekvo@name| to a short cut to get the \key's
+% callback name. Next we execute the code in |#2|, if the \set\ isn't defined
+% |#2| is gobbled.
+% \begin{macrocode}
+\protected\def\ekvo@do@with@set#1#2%
+ {%
+ \ekvifdefinedset{#1}%
+ {%
+ \expandafter
+ \let\expandafter\ekvo@name\csname\ekv@undefined@set{#1}\endcsname
+ \def\ekvo@setname{#1}%
+ #2%
+ }%
+ {\ekvo@err@undefined@set{#1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Key handlers}
+%
+% \expkvo\ uses handlers specifying what happens if a parsed \key\ is defined or
+% undefined.
+%
+% \begin{macro}[internal]
+% {\ekvo@handle@undefined@k@pkg,\ekvo@handle@undefined@kv@pkg}
+% The case for undefined keys in a local list of a package is easy, just throw
+% appropriate errors.
+% \begin{macrocode}
+\protected\long\def\ekvo@handle@undefined@k@pkg#1%
+ {%
+ \ekv@ifdefined{\ekvo@name{#1}}%
+ {\ekvo@err@value@required{#1}}%
+ {\ekvo@err@undefined@key{#1}}%
+ }
+\def\ekvo@handle@undefined@kv@pkg#1#2%
+ {%
+ \ekv@ifdefined{\ekvo@name{#1}N}%
+ {\ekvo@err@value@forbidden{#1}}%
+ {\ekvo@err@undefined@key{#1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvo@addto@unused@one,\ekvo@addto@unused@two,
+% \ekvo@rmfrom@unused@one,\ekvo@rmfrom@unused@two
+% }
+% These macros will add or remove the |\CurrentOption| to or from the list of
+% unused global options. Since |\ekvo@do@unusedoptionlist| will have some
+% overhead before calling the list changing macro in filtering the current
+% option, we use an optimization here in that we check whether the list is
+% empty before calling the |rmfrom| function.
+% \begin{macrocode}
+\long\def\ekvo@addto@unused@one#1{\ekvo@do@unusedoptionlist\ekvo@addnewto@list}
+\long\def\ekvo@addto@unused@two#1#2{\ekvo@do@unusedoptionlist\ekvo@addnewto@list}
+\long\def\ekvo@rmfrom@unused@one#1%
+ {%
+ \ekvo@ifx@F\@unusedoptionlist\@empty
+ {\ekvo@do@unusedoptionlist\ekvo@rmfrom@list}%
+ }
+\long\def\ekvo@rmfrom@unused@two#1#2%
+ {%
+ \ekvo@ifx@F\@unusedoptionlist\@empty
+ {\ekvo@do@unusedoptionlist\ekvo@rmfrom@list}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvo@do@unusedoptionlist,
+% \ekvo@prepare@unusedoption,
+% \ekvo@prepare@unusedoption@a,
+% \ekvo@prepare@unusedoption@b,
+% \ekvo@prepare@unusedoption@c
+% }
+% The way the new \LaTeXe\ kernel handles the unused option list changed. Now
+% not the entire |\CurrentOption| is listed, but just everything up to the
+% first equals sign, and spaces got zapped, doesn't matter whether the raw
+% option list gets used or not. So we have to zap spaces and remove everything
+% from the first equals sign onwards. The code used here will fail if the
+% current option contains an |\ekv@mark| or |\ekv@stop| before the first
+% equals sign (this seems rather unlikely).
+% \begin{macrocode}
+\protected\def\ekvo@do@unusedoptionlist#1%
+ {%
+ \let\ekvo@unpreparedCurrentOption\CurrentOption
+ \edef\CurrentOption
+ {\expandafter\ekvo@prepare@unusedoption\CurrentOption=\ekv@mark}%
+ #1\@unusedoptionlist
+ \let\CurrentOption\ekvo@unpreparedCurrentOption
+ }
+\def\ekvo@prepare@unusedoption{\ekvo@prepare@unusedoption@a\@empty}
+\def\ekvo@prepare@unusedoption@a#1%
+ {%
+ \long\def\ekvo@prepare@unusedoption@a##1=##2\ekv@mark
+ {%
+ \ekvo@prepare@unusedoption@b##1\ekv@stop
+ \ekv@mark\ekvo@prepare@unusedoption@b
+ #1\ekv@mark\ekvo@prepare@unusedoption@c
+ }%
+ }
+\ekvo@prepare@unusedoption@a{ }
+\long\def\ekvo@prepare@unusedoption@b#1 #2\ekv@mark#3{#3#1#2\ekv@mark#3}
+\long\def\ekvo@prepare@unusedoption@c
+ #1\ekv@stop
+ \ekv@mark\ekvo@prepare@unusedoption@b\ekv@mark\ekvo@prepare@unusedoption@c
+ {\unexpanded\expandafter{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvo@set@handlers@local,\ekvo@set@handlers@global,
+% \ekvo@set@handlers@list
+% }
+% These macros are boring. They just set up the handlers to respect the rules
+% documented earlier.
+% \begin{macrocode}
+\protected\def\ekvo@set@handlers@local
+ {%
+ \ekvo@if@need@handlers
+ {%
+ \ifx\@currext\@clsextension
+ \ifx\@classoptionslist\relax
+ \let\ekvo@handle@undefined@k\@gobble
+ \let\ekvo@handle@undefined@kv\@gobbletwo
+ \else
+ \expandafter
+ \ifx
+ \csname @raw@opt@\@currname.\@currext\endcsname
+ \@raw@classoptionslist
+ \let\ekvo@handle@undefined@k\ekvo@addto@unused@one
+ \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two
+ \unless\ifx\@unusedoptionlist\@empty
+ \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one
+ \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two
+ \fi
+ \else
+ \let\ekvo@handle@undefined@k\@gobble
+ \let\ekvo@handle@undefined@kv\@gobbletwo
+ \fi
+ \fi
+ \else
+ \let\ekvo@handle@undefined@k\ekvo@handle@undefined@k@pkg
+ \let\ekvo@handle@undefined@kv\ekvo@handle@undefined@kv@pkg
+ \fi
+ }%
+ }
+\protected\def\ekvo@set@handlers@global
+ {%
+ \unless\ifx\@unusedoptionlist\@empty
+ \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one
+ \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two
+ \fi
+ \ekvo@if@need@handlers
+ {%
+ \let\ekvo@handle@undefined@k\@gobble
+ \let\ekvo@handle@undefined@kv\@gobbletwo
+ }%
+ }
+\protected\def\ekvo@set@handlers@list
+ {%
+ \ekvo@if@need@handlers
+ {%
+ \let\ekvo@handle@undefined@k\@gobble
+ \let\ekvo@handle@undefined@kv\@gobbletwo
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvo@if@need@handlers,\ekvo@dont@need@handlers}
+% If the user specifies handlers this macro will be let to
+% |\ekvo@dont@need@handlers|, which will act like |\@gobble| and also let it
+% to |\@firstofone| afterwards.
+% \begin{macrocode}
+\let\ekvo@if@need@handlers\@firstofone
+\protected\long\def\ekvo@dont@need@handlers#1%
+ {%
+ \let\ekvo@if@need@handlers\@firstofone
+ }%
+% \end{macrocode}
+% \end{macro}
+%
+% We have to set the default for the handlers of defined keys, because they
+% don't necessarily get defined before a list is parsed.
+% \begin{macrocode}
+\let\ekvo@handle@defined@k\@gobble
+\let\ekvo@handle@defined@kv\@gobbletwo
+% \end{macrocode}
+%
+%
+% \subsection{Processing list elements}
+%
+% \begin{macro}[internal]{\ekvo@process@common}
+% All the key processing frontend macros use the same basic structure. |#1|
+% will be a simple test, deciding whether the list will really be parsed or
+% not, |#3| will be the \set, and |#2| will be the individual code of the
+% frontend macro which should be executed if both the test in |#1| is true and
+% the \set\ is defined.
+% \begin{macrocode}
+\protected\def\ekvo@process@common#1#2#3%
+ {%
+ #1{\ekvo@do@with@set{#3}{#2}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvo@process@list}
+% This macro only expands the list holding macro and forwards it to the
+% loop macro.
+% \begin{macrocode}
+\protected\def\ekvo@process@list#1%
+ {%
+ \expandafter\ekvo@CurrentOption@loop\expandafter{#1}\ekvo@parse
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekvo@parse,
+% \ekvo@parse@kv,\ekvo@parse@kv@,\ekvo@expansion@kv,\ekvo@expansion@kv@,
+% \ekvo@parse@k, \ekvo@parse@k@, \ekvo@expansion@k, \ekvo@expansion@k@
+% }
+% This macro calls internals of \expkv\ such that the input is split at an
+% equals sign of category other.
+% \begin{macrocode}
+\long\def\ekvo@parse#1%
+ {%
+ \ekv@eq@other#1\ekv@nil\ekv@mark\ekvo@parse@kv
+ =\ekv@mark\ekvo@parse@k
+ }
+% \end{macrocode}
+% If there was an equals sign, this will be called and remove the remainder of
+% the split. Afterwards the \expnotation\ is checked and possibly executed,
+% and the \kv\ pair is set. While reinsertion works via the |Rr|
+% \expansion-rule, it might affect the unused global option list.
+% \begin{macrocode}
+\long\def\ekvo@parse@kv#1\ekv@stop#2\ekv@nil=\ekv@mark\ekvo@parse@k
+ {\ekv@strip{#2}{\ekv@strip{#1}\ekvo@parse@kv@}}
+\long\def\ekvo@parse@kv@#1#2%
+ {%
+ \ekv@ifexp{#1}%
+ {\ekvo@expansion@kv{#2}}%
+ {\ekvo@set@kv{#1}{#2}}%
+ }
+% \end{macrocode}
+% Check for \expansion-rules was true, now we need to execute them, and use
+% the result in |\ekvo@set@kv|. Also we have to handle the key as if it was a
+% defined key if the |\r| \expansion-rule was found (which potentially removes
+% it from the list of global unused options).
+% \begin{macrocode}
+\long\def\ekvo@expansion@kv#1#2#3#4%
+ {%
+ \ekv@expansion@rule@{#1}#2\ekv@mark\ekv@stop{#3}{}%
+ {\ekvo@handle@defined@kv{#3}{#1}\ekvmorekv}%
+ \ekvo@expansion@kv@
+ }
+\long\def\ekvo@expansion@kv@#1#2{\ekvo@set@kv{#1}{#2}}
+% \end{macrocode}
+% And basically the same two biggish steps, but for the case that no equals
+% sign is found.
+% \begin{macrocode}
+\long\def\ekvo@parse@k#1\ekv@nil\ekv@mark\ekvo@parse@kv\ekv@stop\ekv@mark
+ {\ekv@strip{#1}\ekvo@parse@k@}
+\long\def\ekvo@parse@k@#1%
+ {%
+ \ekv@ifexp{#1}%
+ \ekvo@expansion@k
+ {\ekvo@set@k{#1}}%
+ }
+\long\def\ekvo@expansion@k#1#2#3%
+ {%
+ \ekv@expansion@rule@{#2}#1\ekv@mark\ekv@stop{}{}%
+ {\ekvo@handle@defined@k{#2}\ekvmorekv}%
+ \ekvo@expansion@k@
+ }
+\long\def\ekvo@expansion@k@#1#2{\ekvo@set@k{#2}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvo@set@k,\ekvo@set@kv}
+% These two macros check whether the key is defined and if so call the handler
+% for defined keys and execute the key, else the handler for undefined keys is
+% called.
+% \begin{macrocode}
+\protected\def\ekvo@set@k#1%
+ {%
+ \ekv@ifdefined{\ekvo@name{#1}N}%
+ {%
+ \ekvo@handle@defined@k{#1}%
+ \csname\ekvo@name{#1}N\endcsname
+ }%
+ {\ekvo@handle@undefined@k{#1}}%
+ }
+\protected\def\ekvo@set@kv#1#2%
+ {%
+ \ekv@ifdefined{\ekvo@name{#1}}%
+ {%
+ \ekvo@handle@defined@kv{#1}{#2}%
+ \csname\ekvo@name{#1}\endcsname{#2}%
+ }%
+ {\ekvo@handle@undefined@kv{#1}{#2}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{List variable helpers}
+%
+% \begin{macro}[internal]{\ekvo@addto@list}
+% This macro is rather simple. If the list to which the |\CurrentOption|
+% should be added is empty we can just let the list to the |\CurrentOption|.
+% Else we have to expand the list once and the |\CurrentOption| once.
+% \begin{macrocode}
+\protected\def\ekvo@addto@list#1%
+ {%
+ \ekvo@ifx@TF#1\@empty
+ {\let#1\CurrentOption}%
+ {%
+ \edef#1%
+ {%
+ \unexpanded\expandafter{#1},%
+ \unexpanded\expandafter{\CurrentOption}%
+ }%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvo@addnewto@list}
+% This works just like |\ekvo@addto@list|, but it only adds elements which are
+% not yet part of the list, hence we check if the option is already in the
+% list.
+% \begin{macrocode}
+\protected\def\ekvo@addnewto@list#1%
+ {%
+ \ekvo@ifx@TF#1\@empty
+ {\let#1\CurrentOption}%
+ {%
+ \ekvo@if@in@list#1%
+ {}%
+ {%
+ \edef#1%
+ {%
+ \unexpanded\expandafter{#1},%
+ \unexpanded\expandafter{\CurrentOption}%
+ }%
+ }%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekvo@if@in@list,\ekvo@if@in@list@,\ekvo@if@in@list@result}
+% This is a slow but robust test whether some option is already contained in a
+% list. Using argument gobbling logic would be faster, but that way wouldn't
+% be robust for elements containing |{|, |}|, or |#|. Just loop over the code
+% and compare each element, end early if a match is found.
+% \begin{macrocode}
+\protected\def\ekvo@if@in@list#1%
+ {%
+ \ekvo@ifx@TF#1\@empty
+ \@secondoftwo
+ {%
+ \let\ekvo@curropt\CurrentOption
+ \let\ekvo@if@in@list@result\@secondoftwo
+ \expandafter\ekvo@CurrentOption@loop\expandafter{#1}\ekvo@if@in@list@
+ \let\CurrentOption\ekvo@curropt
+ \ekvo@if@in@list@result
+ }%
+ }
+\protected\long\def\ekvo@if@in@list@#1%
+ {%
+ \ekvo@ifx@T\ekvo@curropt\CurrentOption
+ {%
+ \let\ekvo@if@in@list@result\@firstoftwo
+ \ekvo@end@loop
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvo@rmfrom@list,\ekvo@rmfrom@list@}
+% This works by looping over every list item and comparing it to
+% |\ekvo@curropt| which stores the real |\CurrentOption|. This is
+% comparatively slow, but works for items containing braces unlike what
+% \LaTeXe\ does. We could be faster for items not containing braces, though.
+% \begin{macrocode}
+\protected\def\ekvo@rmfrom@list#1%
+ {%
+ \ekvo@ifx@F#1\@empty
+ {%
+ \let\ekvo@tmp@list\@empty
+ \let\ekvo@curropt\CurrentOption
+ \expandafter\ekvo@CurrentOption@loop\expandafter{#1}\ekvo@rmfrom@list@
+ \let\CurrentOption\ekvo@curropt
+ \let#1\ekvo@tmp@list
+ }%
+ }
+\protected\long\def\ekvo@rmfrom@list@#1%
+ {%
+ \ekvo@ifx@F\CurrentOption\ekvo@curropt
+ {\ekvo@addto@list\ekvo@tmp@list}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{Errors}
+%
+% \begin{macro}[internal]
+% {
+% \ekvo@err@undefined@key,\ekvo@err@value@required,
+% \ekvo@err@value@forbidden,\ekvo@err@undefined@set
+% }
+% Just some macros to throw errors in the few cases an error has to be thrown.
+% \begin{macrocode}
+\protected\def\ekvo@err@undefined@key#1%
+ {%
+ \ekvo@pkg@cls@error
+ {Undefined option `\detokenize{#1}'}%
+ {The used option was not defined. Perhaps you misspelled it?}%
+ }
+\protected\def\ekvo@err@value@required#1%
+ {%
+ \ekvo@pkg@cls@error
+ {Missing value for option `\detokenize{#1}'}%
+ {The used option requires a value or you misspelled its name.}%
+ }
+\protected\def\ekvo@err@value@forbidden#1%
+ {%
+ \ekvo@pkg@cls@error
+ {Unwanted value for option `\detokenize{#1}'}%
+ {The used option doesn't support a value or you misspelled its name.}%
+ }
+\protected\def\ekvo@err@undefined@set#1%
+ {%
+ \PackageError{expkv-opt}%
+ {Undefined set `#1'}%
+ {The set for which you try to parse options isn't defined in expkv.}%
+ }
+\protected\def\ekvo@pkg@cls@error
+ {%
+ \ekvo@ifx@TF\@currext\@clsextension
+ \ClassError
+ \PackageError
+ \@currname
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \subsection{User Interface}
+%
+% The user interface macros just put together the bits and pieces.
+%
+% \begin{macro}{\ekvoProcessOptions}
+% First we check if user-defined handlers were used. If that's the case we
+% need to store them and restore them for each list processor. Else just call
+% them sequentially.
+% \begin{macrocode}
+\protected\def\ekvoProcessOptions#1%
+ {%
+ \ekvo@if@need@handlers
+ {%
+ \ekvoProcessGlobalOptions{#1}%
+ \ekvoProcessLocalOptions {#1}%
+ \ekvoProcessFutureOptions{#1}%
+ \@gobbletwo
+ }%
+ \@firstofone
+ {%
+ \let\ekvo@tmpa\ekvo@handle@undefined@k
+ \let\ekvo@tmpb\ekvo@handle@undefined@kv
+ \ekvoUseUnknownHandlers\ekvo@tmpa\ekvo@tmpb
+ \ekvoProcessGlobalOptions{#1}%
+ \ekvoUseUnknownHandlers\ekvo@tmpa\ekvo@tmpb
+ \ekvoProcessLocalOptions {#1}%
+ \ekvoUseUnknownHandlers\ekvo@tmpa\ekvo@tmpb
+ \ekvoProcessFutureOptions{#1}%
+ \let\ekvo@tmpa\ekvo@undefined
+ \let\ekvo@tmpb\ekvo@undefined
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvoProcessLocalOptions}
+% \begin{macrocode}
+\protected\def\ekvoProcessLocalOptions
+ {%
+ \ekvo@process@common
+ {\ekv@ifdefined{@raw@opt@\@currname.\@currext}\@firstofone\@gobble}%
+ {%
+ \ekvo@set@handlers@local
+ \expandafter
+ \ekvo@process@list\csname @raw@opt@\@currname.\@currext\endcsname
+ \AtEndOfPackage{\let\@unprocessedoptions\relax}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvoProcessGlobalOptions}
+% \begin{macrocode}
+\protected\def\ekvoProcessGlobalOptions
+ {%
+ \ekvo@process@common{\ekvo@ifx@F\@classoptionslist\relax}%
+ {%
+ \ekvo@set@handlers@global
+ \ekvo@process@list\@raw@classoptionslist
+ \let\ekvo@handle@defined@k\@gobble
+ \let\ekvo@handle@defined@kv\@gobbletwo
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvoProcessUnusedGlobalOptions}
+% \begin{macrocode}
+\protected\def\ekvoProcessUnusedGlobalOptions#1%
+ {%
+ \PackageError{expkv-opt}%
+ {%
+ \noexpand
+ \ekvoProcessUnusedGlobalOptions no longer works because of changes in%
+ \MessageBreak
+ the LaTeX2e kernel%
+ }%
+ {}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvoProcessFutureOptions}
+% Parsing future options (without patching kernel internals) is only possible
+% with kernel versions after 2022-11-01.
+% The user macro needs to store the user-set handlers for later if
+% |\ekvoUseUnknownHandlers| was used. Then it stores the correct code to
+% process future options in the |opt@handler@| variable.
+% \begin{macrocode}
+\IfFormatAtLeastTF{2022/11/01}
+ {%
+ \protected\def\ekvoProcessFutureOptions#1%
+ {%
+ \ekvo@if@need@handlers\@gobbletwo
+ \@firstofone
+ {%
+ \expandafter\let
+ \csname ekvo@future@undefined@k@\@currname.\@currext\endcsname
+ \ekvo@handle@undefined@k
+ \expandafter\let
+ \csname ekvo@future@undefined@kv@\@currname.\@currext\endcsname
+ \ekvo@handle@undefined@kv
+ }%
+ \protected\expandafter
+ \xdef\csname opt@handler@\@currname.\@currext\endcsname
+ {\ekv@unexpanded{\ekvo@future{#1}}}%
+ }
+% \end{macrocode}
+% \begin{macro}[internal]{\ekvo@future,\ekvo@set@handlers@future}
+% Key parsing is pretty similar to |\ekvoProcessLocalOptions|, only the
+% handlers are defined differently, namely it is checked whether they are
+% user-specified, if not we reuse the undefined handlers for packages (which
+% will throw an error if an unknown key is found).
+% \begin{macrocode}
+ \protected\def\ekvo@future
+ {%
+ \ekvo@process@common
+ {\ekv@ifdefined{@raw@opt@\@currname.\@currext}\@firstofone\@gobble}%
+ {%
+ \ekvo@set@handlers@future
+ \expandafter\ekvo@process@list
+ \csname @raw@opt@\@currname.\@currext\endcsname
+ \AtEndOfPackage{\let\@unprocessedoptions\relax}%
+ }%
+ }
+ \protected\def\ekvo@set@handlers@future
+ {%
+ \expandafter\let\expandafter
+ \ekvo@handle@undefined@k
+ \csname
+ \ekv@ifdefined{ekvo@future@undefined@k@\@currname.\@currext}%
+ {ekvo@future@undefined@k@\@currname.\@currext}%
+ {ekvo@handle@undefined@k@pkg}%
+ \endcsname
+ \expandafter\let\expandafter
+ \ekvo@handle@undefined@kv
+ \csname
+ \ekv@ifdefined{ekvo@future@undefined@kv@\@currname.\@currext}%
+ {ekvo@future@undefined@kv@\@currname.\@currext}%
+ {ekvo@handle@undefined@kv@pkg}%
+ \endcsname
+ }
+% \end{macrocode}
+% \end{macro}
+% \begin{macrocode}
+ }
+ {%
+ \protected\def\ekvoProcessFutureOptions#1%
+ {%
+ \PackageWarning{expkv-opt}%
+ {LaTeX-kernel is too old to process future options.\@gobbletwo}%
+ \protected\gdef\ekvoProcessFutureOptions##1{}%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvoProcessOptionsList}
+% \begin{macrocode}
+\protected\def\ekvoProcessOptionsList#1%
+ {%
+ \ekvo@process@common{\ekvo@ifx@F#1\@empty}%
+ {%
+ \ekvo@set@handlers@list
+ \ekvo@process@list#1%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvoUseUnknownHandlers}
+% \begin{macro}[internal]{\ekvoUseUnknownHandlers@n,\ekvoUseUnknownHandlers@s}
+% \begin{macrocode}
+\protected\def\ekvoUseUnknownHandlers
+ {%
+ \let\ekvo@if@need@handlers\ekvo@dont@need@handlers
+ \@ifstar\ekvoUseUnknownHandlers@s\ekvoUseUnknownHandlers@n
+ }
+\protected\def\ekvoUseUnknownHandlers@s
+ {%
+ \long\def\ekvo@handle@undefined@k##1%
+ {%
+ \ekv@ifdefined{\ekvo@name{}uN}%
+ {%
+ \csname\ekvo@name{}uN\expandafter\endcsname\expandafter
+ {\detokenize{##1}}{##1}%
+ }%
+ {\@gobble}%
+ }%
+ \long\def\ekvo@handle@undefined@kv##1##2%
+ {%
+ \ekv@ifdefined{\ekvo@name{}u}%
+ {%
+ \csname\ekvo@name{}u\ekv@expanded{\endcsname
+ {\ekv@unexpanded{##2}}{\detokenize{##1}}}{##1}%
+ }%
+ {}%
+ }%
+ }
+\protected\def\ekvoUseUnknownHandlers@n#1#2%
+ {%
+ \let\ekvo@handle@undefined@k#1\relax
+ \let\ekvo@handle@undefined@kv#2\relax
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% All user interface macros should be only used in the preamble.
+% \begin{macrocode}
+\@onlypreamble\ekvoProcessOptions
+\@onlypreamble\ekvoProcessLocalOptions
+\@onlypreamble\ekvoProcessGlobalOptions
+\@onlypreamble\ekvoProcessFutureOptions
+\@onlypreamble\ekvoProcessOptionsList
+\@onlypreamble\ekvoUseUnknownHandlers
+% \end{macrocode}
+%
+% \gobbledocstriptag
+%</pkg>
diff --git a/macros/generic/expkv-bundle/expkv-pop.dtx b/macros/generic/expkv-bundle/expkv-pop.dtx
new file mode 100644
index 0000000000..dc05d6bd0b
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv-pop.dtx
@@ -0,0 +1,700 @@
+% \iffalse meta-comment
+%
+% File: expkv-pop.dtx Copyright (C) 2020-2023 Jonathan P. Spratte
+%
+% This work may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this license or
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% ------------------------------------------------------------------------------
+%
+%<*driver>^^A>>=
+\def\expkvDocNoGenerate{}
+\input expkv-bundle.ins
+\generate{\file{expkv-pop.sty}{\from{expkv-pop.dtx}{pkg}}}
+\generate{\file{expkv-pop.tex}{\from{expkv-pop.dtx}{tex}}}
+\generate{\file{t-expkv-pop.tex}{\from{expkv-pop.dtx}{ctx}}}
+\endbatchfile
+%</driver>^^A=<<
+% \fi
+%
+% \section{\expkvp}
+%^^A the LaTeX package >>=
+% \subsection{The \LaTeX\ Package}
+% Set up the \LaTeX\ package.
+% \gobbledocstriptag
+%<*pkg>
+% \begin{macrocode}
+\RequirePackage{expkv}
+\def\ekvp@tmp
+ {%
+ \ProvidesFile{expkv-pop.tex}%
+ [\ekvpDate\space v\ekvpVersion\space a prefix oriented parser]%
+ }
+\input{expkv-pop.tex}
+\ProvidesPackage{expkv-pop}%
+ [\ekvpDate\space v\ekvpVersion\space a prefix oriented parser]
+% \end{macrocode}
+% \gobbledocstriptag
+%</pkg>
+%^^A=<<
+%^^A the ConTeXt module >>=
+% \subsection{The \ConTeXt\ module}
+% Set up the \ConTeXt\ module.
+% \gobbledocstriptag
+%<*ctx>
+% \begin{macrocode}
+\writestatus{loading}{ConTeXt User Module / expkv-pop}
+\usemodule[expkv]
+\unprotect
+\input expkv-pop.tex
+\writestatus{loading}
+ {ConTeXt User Module / expkv-pop / Version \ekvpVersion\space loaded}
+\protect\endinput
+% \end{macrocode}
+% \gobbledocstriptag
+%</ctx>
+%^^A=<<
+%^^A main file >>=
+% \subsection{The Generic Code}
+% And another generic code package we need to set up.
+% \gobbledocstriptag
+%<*tex>
+%
+% Loading the generic \expkv\ package if it wasn't already loaded, utilizing
+% that \expkv\ prevents itself from loading multiple times.
+% \begin{macrocode}
+\input expkv
+% \end{macrocode}
+%
+% Introduce an own guard against being loaded multiple times:
+% \begin{macrocode}
+\expandafter\ifx\csname ekvpVersion\endcsname\relax
+\else
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% \begin{macro}{\ekvpVersion,\ekvpDate}
+% Specify the own version and date
+% \begin{macrocode}
+\def\ekvpVersion{1.0}
+\def\ekvpDate{2023-01-23}
+% \end{macrocode}
+% \end{macro}
+%
+% Reporting back who we are for \LaTeX\ (the package will have set up things for
+% us).
+% \begin{macrocode}
+\csname ekvp@tmp\endcsname
+% \end{macrocode}
+%
+% Package internal category code setup (stored to restore it at the end -- we
+% have to be careful to not lose this definition of |\ekvp@tmp| inside the
+% package).
+% \begin{macrocode}
+\expandafter\chardef\csname ekvp@tmp\endcsname=\catcode`\@
+\catcode`\@=11
+% \end{macrocode}
+%
+% \subsubsection{Parsing}^^A>>=
+%
+% \begin{macro}{\ekvpParse}
+% \begin{macro}[internal]
+% {
+% \ekvpParse@a,\ekvpParse@b,\ekvpParse@c,
+% \ekvpParse@unsafe,\ekvpParse@unsafe@auto
+% }
+% Parsing should be done in two steps of expansion, hence we put
+% |\unexpanded\expanded| around it. Next we check whether the parser is
+% defined, and afterwards run |\ekvparse|. For that we expand it once and
+% remove the |\unexpanded| which it uses itself.
+% \begin{macrocode}
+\long\def\ekvpParse#1#2%
+ {%
+ \ekv@unexpanded\ekv@expanded
+ {{\expandafter\ekvpParse@a\detokenize{#1}\ekv@mark{#2}}}%
+ }
+\def\ekvpParse@a#1\ekv@mark
+ {%
+ \ekv@ifdefined{ekvp@@p@#1}%
+ {\expandafter\ekvpParse@b\csname ekvp@@p@#1\endcsname}%
+ {\ekvp@err@unknownparser{#1}\@gobble}%
+ }
+\def\ekvpParse@b#1%
+ {%
+ \ekv@ifdefined{#1{ppa}}%
+ {%
+ \expandafter\ekvpParse@c\expandafter
+ {\expandafter#1\csname#1{ppa}\endcsname}%
+ }%
+ {\ekvpParse@c{#1{}}}%
+ }
+\def\ekvpParse@c#1#2#3{#2#3}
+\ekv@expargtwice{\long\def\ekvpParse@c#1#2}%
+ {\expandafter\ekvpParse@c\ekvparse{\ekvp@k#1}{\ekvp@p#1}{#2}}
+\long\def\ekvpParse@unsafe#1#2#3{\ekv@unexpanded\ekv@expanded{{#2#3}}}
+\ekv@expargtwice{\long\def\ekvpParse@unsafe@auto#1#2#3}
+ {\expandafter\ekvpParse@unsafe\ekvparse{\ekvp@k#1#2}{\ekvp@p#1#2}{#3}}
+\ekv@expargtwice{\long\def\ekvpParse@unsafe#1#2}%
+ {\expandafter\ekvpParse@unsafe\ekvparse{\ekvp@k#1{}}{\ekvp@p#1{}}{#2}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvp@k}
+% For |NoVal| we use the parser specific rule.
+% \begin{macrocode}
+\def\ekvp@k#1{\csname #1k\endcsname#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvp@ifspace,\ekvp@ifspace@}
+% This checks whether a space is inside its argument (gobbling up to the first
+% space and checking for an empty remainder).
+% \begin{macrocode}
+\long\def\ekvp@ifspace#1%
+ {%
+ \ekvp@ifspace@#1 \ekv@ifempty@B\ekv@ifempty@false
+ \ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
+ }
+\long\def\ekvp@ifspace@#1 % keep this space
+ {\ekv@ifempty@\ekv@ifempty@A}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvp@p}
+% \begin{macro}[internal]{\ekvp@prefix}
+% \begin{macro}[internal]{\ekvp@prefix@a,\ekvp@prefix@b}
+% If there should be a prefix there needs to be a space, so we check for one.
+% Then we split the first prefix of the rest.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekvp@prefix#1}%
+ {%
+ \ekvp@ifspace{#1}%
+ {\ekvp@prefix@a#1\ekv@stop}%
+ {\ekvp@noprefix{#1}}%
+ }
+% \end{macrocode}
+% A prefix is parsed with a few additional logical groups. The input |#1| is
+% the parser's name macro, |#2| is the full item which should be parsed. And
+% we place an additional group in which the prefix macros will be collected.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekvp@p#1#2#3}{\ekvp@prefix{#3}#1{#2}{#3}}
+% \end{macrocode}
+% The prefix is |\detokenize|d and forwarded. Then we check whether it's a
+% defined type or prefix.
+% \begin{macrocode}
+\long\def\ekvp@prefix@a#1 % keep this space
+ {\expandafter\ekvp@prefix@b\detokenize{#1}\ekv@mark{#1}}
+\ekv@exparg{\long\def\ekvp@prefix@b#1\ekv@mark#2#3\ekv@stop#4}%
+ {%
+ \ekv@ifdefined{#4{pt}@#1}
+ {\expandafter\ekvp@prefix@pt\csname #4{pt}@#1\endcsname{#1}}%
+ {%
+ \ekv@ifdefined{#4{pp}@#1}%
+ {\expandafter\ekvp@prefix@pp\csname #4{pp}@#1\endcsname}%
+ {\@firstoftwo{\ekvp@noprefix{#2 #3}}}%
+ }%
+ {#3}#4%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvp@prefix@pt,\ekvp@prefix@pt@}
+% A type ends the prefix parsing (every item can only have one type). The
+% argument |#1| is that type macro, and in |#2| is the types name. |#3| then
+% contains the name of the element, |#4| is the parser's name macro (which is
+% no longer needed here), |#5| is the list of prefix macros, |#6| the entire
+% unchanged item, and |#7| is the value provided to the current item. The
+% prefix macro list will be stepped through, each macro will get the type
+% name, element name, and complete unprocessed item, whereas the type macro
+% will not receive the type string (but instead the value), which is why we
+% put a |\@firstoftwo| there to remove the type. |\ekvp@prefix@pt@| is a
+% helper to fetch the first prefix macro (or the type should |#5| be empty).
+% \begin{macrocode}
+\long\def\ekvp@prefix@pt#1#2#3#4#5#6#7%
+ {%
+ \ekvp@prefix@pt@{#2}{#3}{#6}#5{\@firstoftwo#1}{#7}\ekvpEOT
+ \ekv@unexpanded{\ekvpEOA{#6}}%
+ }
+\long\def\ekvp@prefix@pt@#1#2#3#4{#4{#1}{#2}{#3}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvp@prefix@pp}
+% A prefix macro is added to the list of prefixes (argument |#4|) and the next
+% prefix is searched.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekvp@prefix@pp#1#2#3#4}{\ekvp@prefix{#2}#3{#4#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvp@noprefix}
+% If no prefix was found (either because there was no space, or the first
+% space delimited thing wasn't a valid prefix) we check if there is a notype
+% rule or throw an error.
+% \begin{macrocode}
+\long\def\ekvp@noprefix#1#2%
+ {%
+ \ekv@ifdefined{#2{pn}}
+ {\expandafter\ekvp@prefix@pt\csname #2{pn}\endcsname{}{#1}}
+ \ekvp@err@missingtype
+ #2%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+%^^A=<<
+%
+% \subsubsection{Defining Parsers}^^A>>=
+%
+% \begin{macro}{\ekvpNewParser}
+% \begin{macro}[internal]{\ekvpNewParser@}
+% To define a new parser we need to assert that it doesn't already exists (if
+% so we throw an error) and define the parser name. A parser name is defined
+% as the macro \cs[no-index]{ekvp@@p@\meta{name}}, that macro will take one
+% argument and build the name of a prefix or type. Additionally a new parser
+% gets its |NoVal| rule set up as the default rule.
+% \begin{macrocode}
+\protected\long\def\ekvpNewParser#1%
+ {\expandafter\ekvpNewParser@\detokenize{#1}\ekv@mark}
+\protected\def\ekvpNewParser@#1\ekv@mark
+ {%
+ \ekv@ifdefined{ekvp@@p@#1}%
+ {\ekvp@errm{Parser `#1' already defined}}%
+ {%
+ \expandafter\def\csname ekvp@@p@#1\endcsname##1{ekvp@@##1@#1}
+ \expandafter
+ \let\csname\csname ekvp@@p@#1\endcsname k\endcsname\ekvp@k@default
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvpValueAlwaysRequired}
+% \begin{macro}[internal]{\ekvpValueAlwaysRequired@}
+% This just changes the default |NoVal| rule to throw an error.
+% \begin{macrocode}
+\protected\long\def\ekvpValueAlwaysRequired#1%
+ {\ekvp@parser@def{#1}\ekvpValueAlwaysRequired@{}}
+\protected\def\ekvpValueAlwaysRequired@#1%
+ {\expandafter\let\csname#1k\endcsname\ekvp@err@noval}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvpDefNoValue}
+% \begin{macro}[internal]{\ekvpDefNoValue@}
+% \begin{macrocode}
+\protected\long\def\ekvpDefNoValue#1%
+ {\ekvp@parser@def{#1}\ekvpDefNoValue@\@gobble}
+\protected\long\def\ekvpDefNoValue@#1#2%
+ {%
+ \def\ekvp@tmp##1{\ekv@unexpanded{#2}}%
+ \ekv@exparg{\long\expandafter\def\csname#1k\endcsname##1##2##3}%
+ {\ekvp@tmp{##3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvpUseNoValueMarker}
+% \begin{macro}[internal]{\ekvpUseNoValueMarker@}
+%
+% \begin{macrocode}
+\protected\long\def\ekvpUseNoValueMarker#1%
+ {\ekvp@parser@def{#1}\ekvpUseNoValueMarker@\@gobble}
+\protected\long\def\ekvpUseNoValueMarker@#1#2%
+ {%
+ \long\expandafter\edef\csname#1k\endcsname##1##2##3%
+ {\ekv@unexpanded{\ekvp@p}##1{##2}{##3}{\ekv@unexpanded{#2}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvpDefNoValuePrefix}
+% \begin{macro}[internal]{\ekvpDefNoValuePrefix@,\ekvpDefNoValuePrefix@@}
+% This might be the most complicated of the |NoVal|-behaviour changes. The
+% first two steps should be clear.
+% \begin{macrocode}
+\protected\long\def\ekvpDefNoValuePrefix#1%
+ {\ekvp@parser@def{#1}\ekvpDefNoValuePrefix@\@gobbletwo}
+\protected\def\ekvpDefNoValuePrefix@#1%
+ {\expandafter\ekvpDefNoValuePrefix@@\csname#1{ppn}\endcsname#1}
+% \end{macrocode}
+% This step is the complicated one combining the effects of \cs{ekvpDefPrefix}
+% with the standard |NoVal|-rule (but for which the no-value marker might have
+% been changed), so here's what happens:
+% We set up a temporary meaning for the control sequence name
+% forwarded as |#1| to extract the no-value marker of the current parser. Then
+% we set up the |NoVal|-macro of the current parser to expand to the normal
+% parsing route, there we inject |#1| as the first prefix macro in the
+% corresponding first argument of \cs[no-index]{ekvp@p}, and we extract the
+% no-value marker with the |\expandafter#1|-chain. This last step might
+% actually fail badly if \cs{ekvpValueAlwaysRequired} or \cs{ekvpDefNoValue}
+% was used.
+% \begin{macrocode}
+\protected\long\def\ekvpDefNoValuePrefix@@#1#2%
+ {%
+ \long\def#1\ekvp@p##1##2##3%
+ {%
+ \ekv@unexpanded{\ekvp@p}%
+ ####1{####2\ekv@unexpanded{#1}}{####3}{\ekv@unexpanded{##3}}%
+ }%
+ \long\expandafter\edef\csname#2k\endcsname##1##2##3%
+ {\expandafter\expandafter\expandafter#1\csname#2k\endcsname{}{}{}}%
+ \ekvp@parser@def@prefix#1%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvpDefAutoPrefix}
+% \begin{macro}[internal]{\ekvpDefAutoPrefix@}
+% \begin{macrocode}
+\protected\long\def\ekvpDefAutoPrefix#1%
+ {\ekvp@parser@def{#1}\ekvpDefAutoPrefix@\@gobbletwo}
+\protected\long\def\ekvpDefAutoPrefix@#1%
+ {\expandafter\ekvp@parser@def@prefix\csname#1{ppa}\endcsname}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvp@parser@def,\ekvp@parser@def@}
+% This just makes sure that the parser is defined and builds the parser name.
+% |#1| should be the user-level parser name, |#2| the macro that gets the
+% code-level parser forwarded, and |#3| should gobble all additional arguments
+% needed by whichever frontend macro this is used for in case of an error.
+% \begin{macrocode}
+\long\def\ekvp@parser@def#1%
+ {\expandafter\ekvp@parser@def@\detokenize{#1}\ekv@mark}
+\def\ekvp@parser@def@#1\ekv@mark#2#3%
+ {%
+ \ekv@ifdefined{ekvp@@p@#1}%
+ {\ekv@exparg{#2}{\csname ekvp@@p@#1\endcsname}}%
+ {\ekvp@errm{Parser `#1' not defined}#3}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvpDefPrefix}
+% \begin{macro}[internal]{\ekvpDefPrefix@,\ekvp@parser@def@prefix}
+% A prefix is stored as a macro. At first we define a temporary meaning just
+% to make sure that the user uses only the first three arguments.
+% The real macro is a bit more complicated. It places the user provided before
+% action (|#3|) where it currently is, the after action (|#4|) after
+% |\ekvpEOT| (so after the type action). It also fetches the next prefix or
+% the type macro and forwards the arguments to it.
+% \begin{macrocode}
+\protected\long\def\ekvpDefPrefix#1%
+ {\ekvp@parser@def{#1}\ekvpDefPrefix@\@gobblethree}
+\protected\long\def\ekvpDefPrefix@#1#2%
+ {\expandafter\ekvp@parser@def@prefix\csname#1{pp}@\detokenize{#2}\endcsname}
+\protected\long\def\ekvp@parser@def@prefix#1#2#3%
+ {%
+ \def#1##1##2##3{#2#3}%
+ \long\def#1##1##2##3##4##5\ekvpEOT
+ {\ekv@unexpanded{#2}##4{##1}{##2}{##3}##5\ekvpEOT\ekv@unexpanded{#3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvpDefPrefixLet,\ekvpDefPrefixStore}
+% These are just special cases of |\ekvpDefPrefix|, so nothing complicated
+% here.
+% \begin{macrocode}
+\ekv@exparg{\protected\long\def\ekvpDefPrefixLet#1#2#3#4#5}%
+ {\ekvpDefPrefix{#1}{#2}{\ekvpProtect{\let#3= #4}}{\ekvpProtect{\let#3= #5}}}
+\ekv@exparg{\protected\long\def\ekvpDefPrefixStore#1#2#3#4#5}%
+ {%
+ \ekvpDefPrefix{#1}{#2}%
+ {\ekvpProtect{\edef#3{\ekv@unexpanded{#4}}}}%
+ {\ekvpProtect{\edef#3{\ekv@unexpanded{#5}}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvpDefType,\ekvpDefNoType}
+% \begin{macro}[internal]{\ekvpDefType@,\ekvpDefNoType@,\ekvpDefType@NoType}
+% A type macro and a notype-macro are pretty similar, the whole difference is
+% the naming scheme. The macro leaves the user definition in the input and
+% places the |\ekvpEOP| and |\ekvpEOT| markers.
+% \begin{macrocode}
+\protected\long\def\ekvpDefType#1{\ekvp@parser@def{#1}\ekvpDefType@\@gobbletwo}
+\protected\long\def\ekvpDefType@#1#2%
+ {\ekvpDefType@NoType{#1{pt}@\detokenize{#2}}}%
+\protected\long\def\ekvpDefNoType#1{\ekvp@parser@def{#1}\ekvpDefNoType@\@gobble}
+\protected\long\def\ekvpDefNoType@#1{\ekvpDefType@NoType{#1{pn}}}
+\protected\long\def\ekvpDefType@NoType#1#2%
+ {%
+ \long\expandafter\def\csname#1\endcsname##1##2##3\ekvpEOT
+ {\ekv@unexpanded{\ekvpEOP{##2}#2\ekvpEOT{##2}}}%
+ }%
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvpLet}
+% \begin{macro}[internal]{\ekvpLet@a,\ekvpLet@b,\ekvpLet@c,\ekvpLet@d}
+% Letting has an optional argument, so we can't use |\ekvp@parser@def|
+% directly here, first we need to convert the optional argument to a normal
+% one so that we can gobble it normally. Then we check that the two parsers
+% are defined, and afterwards that the copy macro is. If all this is correct
+% we do the |\let|. Since arguments are shuffled around here, I'll list them
+% each time they get reordered (some might be curried).
+%
+% |#1| is the parser name, |#2| the type, |#3| the new \prefix/\type\ name,
+% |#4| the optional other parser name, |#5| the already existing
+% \prefix/\type\ which should be copied.
+% \begin{macrocode}
+\protected\long\def\ekvpLet#1#2#3{\ekvoptarg{\ekvpLet@a{#1}{#2}{#3}}{#1}}
+\protected\long\def\ekvpLet@a#1%
+ {\ekvp@parser@def{#1}\ekvpLet@b{\@firstoftwo\@gobblethree}}
+\protected\long\def\ekvpLet@b#1#2#3#4%
+ {\ekvp@parser@def{#4}\ekvpLet@c{\@firstoftwo\@gobblethree}#1{#2}{#3}}
+% \end{macrocode}
+% |#1| the other parser's macro, |#2| the parser's macro, |#3| the type, |#4|
+% the new \prefix/\type, |#5| the already existing \prefix/\type.
+% \begin{macrocode}
+\protected\long\def\ekvpLet@c#1#2#3%
+ {%
+ \ekv@ifdefined{ekvpLet@@\detokenize{#3}}%
+ {\expandafter\ekvpLet@d\csname ekvpLet@@\detokenize{#3}\endcsname{#1}{#2}}%
+ {\ekvp@errm{unknown type \detokenize{#3}}\@gobbletwo}%
+ }
+% \end{macrocode}
+% |#1| the type's macro, |#2| the other parser's macro, |#3| the parser's
+% macro, |#4| the new \prefix/\type, |#5| the already existing \prefix/\type.
+% \begin{macrocode}
+\protected\long\def\ekvpLet@d#1#2#3#4#5%
+ {%
+ \ekv@ifdefined{#2{#1}@\detokenize{#5}}%
+ {%
+ \expandafter\let
+ \csname#3{#1}@\detokenize{#4}\expandafter\endcsname
+ \csname#2{#1}@\detokenize{#5}\endcsname
+ }%
+ {\ekvp@errm{Undefined prefix/type \detokenize{#5} can't be copied}}%
+ }
+\def\ekvpLet@@prefix{pp}
+\def\ekvpLet@@type{pt}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%^^A=<<
+%
+% \subsubsection{\texttt{NoVal} Handling}^^A>>=
+%
+% The idea of |NoVal| handling is taken from \pkg{expl3}. We define a marker
+% (or directly use \pkg{expl3}'s). The defined test is not as robust as
+% \pkg{expl3}'s, but pretty fast (and based on |\ekv@ifempty|).
+%
+% \begin{macro}{\ekvpIfNoVal}
+% \begin{macro}[internal]{\ekvp@novalflag,\ekvp@ifnoval}
+% \begin{macro}[internal]{\ekvp@k@default}
+% \begin{macrocode}
+\ekv@ifdefined{c_novalue_tl}
+ {\expandafter\let\expandafter\ekvp@novalflag\csname c_novalue_tl\endcsname}
+ {%
+ \begingroup
+ \lccode`\Z=`\-
+ \lccode`\:=`\-
+ \lccode`\N=\z@
+ \lccode`\V=\z@
+ \lowercase{\endgroup\def\ekvp@novalflag{ZNoValue:}}%
+ }
+\def\ekvpIfNoVal#1%
+ {%
+ \long\def\ekvpIfNoVal##1%
+ {%
+ \ekvp@ifnoval{}##1{}?!#1??!\ekv@ifempty@B\ekv@ifempty@true
+ \ekv@ifempty@A\ekv@ifempty@B\@secondoftwo
+ }%
+ \long\def\ekvp@ifnoval##1#1##2?##3?!{\ekv@ifempty@\ekv@ifempty@A##1##2}%
+ \long\def\ekvp@k@default##1##2##3{\ekvp@p##1{##2}{##3}{#1}}%
+ }
+\expandafter\ekvpIfNoVal\expandafter{\ekvp@novalflag}
+\let\ekvp@novalflag\ekvp@undefined
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%^^A=<<
+%
+% \subsubsection{Assertions}^^A>>=
+%
+% Assertions are just wrappers around user provided code to throw errors. Each
+% of them
+%
+% \begin{macro}{\ekvpAssertIf,\ekvpAssertIfNot}
+% \begin{macro}[internal]{\ekvpAssertIf@,\ekvpAssertIf@good,\ekvpAssert@notgood}
+% \begin{macrocode}
+\def\ekvpAssertIf{\romannumeral\ekv@alignsafe\ekvoptarg{\ekvpAssertIf@{}}{EOT}}
+\def\ekvpAssertIfNot
+ {\romannumeral\ekv@alignsafe\ekvoptarg{\ekvpAssertIf@\else}{EOT}}
+\long\def\ekvpAssertIf@#1#2#3%
+ {%
+ #3#1\ekvpAssertIf@good\fi
+ \ekvpAssert@notgood{#2}%
+ }
+\long\def\ekvpAssertIf@good\fi\ekvpAssert@notgood#1#2%
+ {\fi\ekv@endalignsafe\ekv@zero}
+\long\def\ekvpAssert@notgood#1%
+ {%
+ \ekv@ifdefined{ekvpAssert@@#1}%
+ {\csname ekvpAssert@@#1\endcsname}%
+ {\ekvp@err@unknownmarker{#1}\ekvpAssert@@EOA}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvpAssertTF,\ekvpAssertTFNot}
+% \begin{macro}[internal]{\ekvpAssertTF@}
+% \begin{macrocode}
+\def\ekvpAssertTF{\ekvoptarg{\ekvpAssertTF@{}}{EOT}}
+\def\ekvpAssertTFNot{\ekvoptarg{\ekvpAssertTF@{\@secondoftwo\@firstoftwo}}{EOT}}
+\long\def\ekvpAssertTF@#1#2#3%
+ {%
+ \ekv@alignsafe
+ #3#1%
+ {\ekv@endalignsafe\@gobble}%
+ {\romannumeral\ekvpAssert@notgood{#2}}%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \ekvpAssertValue,\ekvpAssertNoValue,\ekvpAssertOneValue,
+% \ekvpAssertTwoValues
+% }
+% \begin{macro}[internal]{\ekvpAssert@further}
+% \begin{macro}[internal]{\ekvp@assert@num@args}
+% These here are special cases of assertions. First we define a helper, the
+% following might look like a recursive call, but we'll redefine the helper
+% later and need this definition only temporary.
+% \begin{macrocode}
+\ekv@exparg{\def\ekvpAssert@further#1#2#3}%
+ {\ekvoptarg{\ekvpAssert@further{#1}{#2}{#3}}{EOT}}
+% \end{macrocode}
+% Now the definitions, we just need to set up the tests and corresponding
+% error messages. All this passes through the \cs{ekvpAssertTF} check (which
+% we shortcut to its internal auxiliary function here).
+% \begin{macrocode}
+\ekv@exparg{\def\ekvpAssertValue}%
+ {\ekvpAssert@further{\@secondoftwo\@firstoftwo}{\ekvpIfNoVal}{missing value}}
+\ekv@exparg{\def\ekvpAssertNoValue}%
+ {\ekvpAssert@further{}{\ekvpIfNoVal}{superfluous value}}
+\ekv@exparg{\def\ekvpAssertOneValue}%
+ {\ekvpAssert@further{}{\ekvp@assert@num@args\@gobble}{argument count != 1}}
+\ekv@exparg{\def\ekvpAssertTwoValues}%
+ {\ekvpAssert@further{}{\ekvp@assert@num@args\@gobbletwo}{argument count != 2}}
+\long\def\ekvp@assert@num@args#1#2%
+ {%
+ \expandafter\ekv@ifempty@\expandafter\ekv@ifempty@A#1#2\ekv@ifempty@B
+ \ekv@ifempty@true\ekv@ifempty@A\ekv@ifempty@B\@secondoftwo
+ }
+% \end{macrocode}
+% And finally redefine our auxiliary that just does a bit of argument
+% reordering for us.
+% \begin{macrocode}
+\long\def\ekvpAssert@further#1#2#3#4#5{\ekvpAssertTF@{#1}{#4}{#2{#5}}{#3}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekvpAssert@@EOP,\ekvpAssert@@EOT,\ekvpAssert@@EOA}
+% \begin{macrocode}
+\def\ekvpAssert@@EOA#1#2%
+ {\long\def#1##1##2#2##3{\ekvp@err{##1 at `##3'}\ekv@endalignsafe\ekv@zero}}
+\ekvpAssert@@EOA\ekvpAssert@@EOP\ekvpEOP
+\ekvpAssert@@EOA\ekvpAssert@@EOT\ekvpEOT
+\ekvpAssert@@EOA\ekvpAssert@@EOA\ekvpEOA
+% \end{macrocode}
+% \end{macro}
+%
+%^^A=<<
+%
+% \subsubsection{Markers}^^A>>=
+%
+% \begin{macro}
+% {\ekvpGobbleP,\ekvpGobbleT,\ekvpGobbleA,\ekvpEOP,\ekvpEOT,\ekvpEOA}
+% Since after the |\ekvpEOT|, \emph{etc.} markers the full element is placed,
+% they are defined as |\@gobble|, and the functions gobbling up to them gobble
+% that argument as well.
+% \begin{macrocode}
+\long\def\ekvpGobbleP#1\ekvpEOP#2{}
+\long\def\ekvpGobbleT#1\ekvpEOT#2{}
+\long\def\ekvpGobbleA#1\ekvpEOA#2{}
+\let\ekvpEOP\@gobble
+\let\ekvpEOT\@gobble
+\let\ekvpEOA\@gobble
+% \end{macrocode}
+% \end{macro}
+%
+%^^A=<<
+%
+% \subsubsection{Miscellaneous Auxiliaries}^^A>>=
+%
+% \begin{macro}{\ekvpProtect}
+% \begin{macro}[internal]{\ekvpProtect@,\ekvpProtect@@}
+% The idea of this macro is pretty simple. In contexts in which a |\protected|
+% macro isn't expanded the |\ekvpProtect@@| expansion will just expand to
+% itself and in the process protect the argument using |\unexpanded|. If a
+% |\protected| macro would be expanded the |\ekvpProtect@| will remove
+% |\ekvpProtect@@| and unpack the argument.
+% \begin{macrocode}
+\def\ekvpProtect{\ekvpProtect@\ekvpProtect@@}
+\protected\long\def\ekvpProtect@\ekvpProtect@@#1{#1}
+\long\def\ekvpProtect@@#1{\ekv@unexpanded{\ekvpProtect@@{#1}}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%^^A=<<
+%
+% \subsubsection{Error messages}^^A>>=
+%
+% \begin{macro}[internal]
+% {
+% \ekvp@err,\ekvp@err@unknownparser,\ekvp@err@noval,\ekvp@err@missingtype,
+% \ekvp@errm
+% }
+% These should be pretty straight forward. We use |\ekverr| to throw
+% expandable errors.
+% \begin{macrocode}
+\protected\long\def\ekvp@errm#1{\errmessage{expkv-pop Error: #1}}
+\ekv@exparg{\long\def\ekvp@err#1}{\ekverr{expkv-pop}{#1}}
+\def\ekvp@err@unknownparser#1{\ekvp@err{unknown parser `#1'}}
+\long\def\ekvp@err@noval#1#2#3{\ekvp@err{missing value for `#3'}}
+\long\def\ekvp@err@missingtype#1#2#3#4{\ekvp@err{missing type in `#3'}}
+\long\def\ekvp@err@unknownmarker#1{\ekvp@err{unknown marker `#1'}}
+% \end{macrocode}
+% \end{macro}
+%
+%^^A=<<
+%
+% Undefine the no longer needed |\ekvp@prefix| and restore the category code of
+% |@|:
+% \begin{macrocode}
+\let\ekvp@prefix\ekvp@undefined
+\catcode`\@=\ekvp@tmp
+% \end{macrocode}
+%
+% \gobbledocstriptag
+%</tex>
+%^^A=<<
diff --git a/macros/generic/expkv-bundle/expkv.dtx b/macros/generic/expkv-bundle/expkv.dtx
new file mode 100644
index 0000000000..1c883b4346
--- /dev/null
+++ b/macros/generic/expkv-bundle/expkv.dtx
@@ -0,0 +1,2375 @@
+% \iffalse meta-comment
+%
+% File: expkv.dtx Copyright (C) 2020-2023 Jonathan P. Spratte
+%
+% This work may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this license or
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% ------------------------------------------------------------------------------
+%
+%<*driver>^^A>>=
+\def\expkvDocNoGenerate{}
+\input expkv-bundle.ins
+\generate{\file{expkv.sty}{\from{expkv.dtx}{pkg}}}
+\generate{\file{expkv.tex}{\from{expkv.dtx}{tex}}}
+\generate{\file{t-expkv.tex}{\from{expkv.dtx}{ctx}}}
+\endbatchfile
+%</driver>^^A=<<
+% \fi
+%
+% \section{\expkv}
+%^^A the LaTeX package >>=
+% \subsection{The \LaTeX\ Package}
+% First we set up the \LaTeX\ package. That one doesn't really do much except
+% |\input|ting the generic code and identifying itself as a package. Additional
+% an |all| option is declared to load all the sub modules in one go.
+% \gobbledocstriptag
+%<*pkg>
+% \begin{macrocode}
+\def\ekv@tmp
+ {%
+ \ProvidesFile{expkv.tex}%
+ [\ekvDate\space v\ekvVersion\space an expandable key=val implementation]%
+ }
+\input{expkv.tex}
+\ProvidesPackage{expkv}%
+ [\ekvDate\space v\ekvVersion\space an expandable key=val implementation]
+\let\ekv@tmp\@empty
+\DeclareOption{all}
+ {%
+ \def\ekv@tmp
+ {\RequirePackage{expkv-pop,expkv-cs,expkv-def,expkv-opt}}%
+ }
+\ProcessOptions\relax
+\ekv@tmp
+% \end{macrocode}
+% \gobbledocstriptag
+%</pkg>
+%^^A=<<
+%^^A the ConTeXt module >>=
+% \subsection{The \ConTeXt\ module}
+% This is pretty straight forward, we just have to change the error throwing
+% mechanism for \ConTeXt\ (the approach taken for plain and \LaTeX\ breaks in
+% \ConTeXt, effectively breaking \ConTeXt, dropping you in an interactive \TeX\
+% session with almost no means of escape).
+% \gobbledocstriptag
+%<*ctx>
+% \begin{macrocode}
+\writestatus{loading}{ConTeXt User Module / expkv}
+\unprotect
+\input expkv.tex
+\long\def\ekv@err@collect#1\par#2%
+ {\directlua{tex.error[[\detokenize{#2} Error: #1]]}}
+\writestatus{loading}
+ {ConTeXt User Module / expkv / Version \ekvVersion\space loaded}
+\protect\endinput
+% \end{macrocode}
+% \gobbledocstriptag
+%</ctx>
+%^^A=<<
+%^^A main file >>=
+% \subsection{The Generic Code}
+% The rest of this implementation will be the generic code.
+% \gobbledocstriptag
+%<*tex>
+%
+% We make sure that it's only input once:
+% \begin{macrocode}
+\expandafter\ifx\csname ekvVersion\endcsname\relax
+\else
+ \expandafter\endinput
+\fi
+% \end{macrocode}
+%
+% Check whether \eTeX\ and |\expanded| are available -- \expkv\ requires \eTeX.
+% \begin{macrocode}
+\begingroup
+ \edef\ekvtmpa{\string\expanded}
+ \edef\ekvtmpb{\meaning\expanded}
+ \expandafter
+\endgroup
+\ifx\ekvtmpa\ekvtmpb
+ \expandafter\let\csname ekv@expanded\endcsname\expanded
+ \expandafter\let\csname ekv@unexpanded\endcsname\unexpanded
+\else
+ \begingroup
+ \edef\ekvtmpa{\string\expanded}
+ \edef\ekvtmpb{\meaning\normalexpanded}
+ \expandafter
+ \endgroup
+ \ifx\ekvtmpa\ekvtmpb
+ \expandafter\let\csname ekv@expanded\endcsname\normalexpanded
+ \expandafter\let\csname ekv@unexpanded\endcsname\normalunexpanded
+ \else
+ \errmessage
+ {expkv Error: e-TeX and the \noexpand\expanded primitive required}%
+ \expandafter\endinput
+ \fi
+\fi
+% \end{macrocode}
+%
+% \begin{macro}{\ekvVersion,\ekvDate}
+% We're on our first input, so lets store the version and date in a macro.
+% \begin{macrocode}
+\def\ekvVersion{2.0}
+\def\ekvDate{2023-01-23}
+% \end{macrocode}
+% \end{macro}
+%
+% If the \LaTeX\ format is loaded we want to be a good file and report back who
+% we are, for this the package will have defined |\ekv@tmp| to use
+% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
+% \begin{macrocode}
+\csname ekv@tmp\endcsname
+% \end{macrocode}
+%
+% Store the category code of |@| to later be able to reset it and change it to
+% 11 for now.
+% \begin{macrocode}
+\expandafter\chardef\csname ekv@tmp\endcsname=\catcode`\@
+\catcode`\@=11
+% \end{macrocode}
+% |\ekv@tmp| might later be reused to gobble any prefixes which might be
+% provided to |\ekvdef| and similar in case the names are invalid, we just
+% temporarily use it here as means to store the current category code of |@| to
+% restore it at the end of the file, we never care for the actual definition of
+% it.
+%
+% \begin{macro}[internal]{\ekv@if@lastnamedcs}
+% If the primitive |\lastnamedcs| is available, we can be a bit faster than
+% without it. So we test for this and save the test's result in this macro.
+% \begin{macrocode}
+\begingroup
+ \edef\ekv@tmpa{\string \lastnamedcs}
+ \edef\ekv@tmpb{\meaning\lastnamedcs}
+ \ifx\ekv@tmpa\ekv@tmpb
+ \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##1}}
+ \else
+ \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##2}}
+ \fi
+ \expandafter
+\endgroup
+\ekv@if@lastnamedcs
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@empty}
+% Sometimes we have to introduce a token to prevent accidental brace stripping.
+% This token would then need to be removed by |\@gobble| or similar. Instead we
+% can use |\ekv@empty| which will just expand to nothing, that is faster than
+% gobbling an argument.
+% \begin{macrocode}
+\def\ekv@empty{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \@gobble,\@gobbletwo,\@gobblethree,
+% \@firstofone,\@firstoftwo,\@secondoftwo,
+% \ekv@fi@gobble,\ekv@fi@firstofone,\ekv@fi@firstoftwo,\ekv@fi@secondoftwo,
+% \ekv@gobble@mark,\ekv@gobbleto@stop,\ekv@gobble@from@mark@to@stop
+% }
+% Since branching tests are often more versatile than |\if...\else...\fi|
+% constructs, we define helpers that are branching pretty fast. Also here are
+% some other utility functions that just grab some tokens. The ones that are
+% also contained in \LaTeX\ don't use the |ekv| prefix. Not all of the ones
+% defined here are really needed by \expkv\ but are provided because packages
+% like \expkvd\ or \expkvo\ need them (and I don't want to define them in each
+% package which might need them).
+% \begin{macrocode}
+\long\def\@gobble#1{}
+\long\def\@gobbletwo#1#2{}
+\long\def\@gobblethree#1#2#3{}
+\long\def\@firstofone#1{#1}
+\long\def\@firstoftwo#1#2{#1}
+\long\def\@secondoftwo#1#2{#2}
+\long\def\ekv@fi@gobble\fi\@firstofone#1{\fi}
+\long\def\ekv@fi@firstofone\fi\@gobble#1{\fi#1}
+\long\def\ekv@fi@firstoftwo\fi\@secondoftwo#1#2{\fi#1}
+\long\def\ekv@fi@secondoftwo\fi\@firstoftwo#1#2{\fi#2}
+\def\ekv@gobble@mark\ekv@mark{}
+\long\def\ekv@gobbleto@stop#1\ekv@stop{}
+\long\def\ekv@gobble@from@mark@to@stop\ekv@mark#1\ekv@stop{}
+% \end{macrocode}
+% \end{macro}
+% As you can see |\ekv@gobbleto@stop| uses a special marker |\ekv@stop|. The
+% package will use three such markers, the one you've seen already, |\ekv@mark|
+% and |\ekv@nil|. Contrarily to how for instance \pkg{expl3} does things, we
+% don't define them, as we don't need them to have an actual meaning. This has
+% the advantage that if they somehow get expanded -- which should never happen
+% if things work out -- they'll throw an error directly.
+%
+% \begin{macro}[internal]
+% {
+% \ekv@ifempty,\ekv@ifempty@,\ekv@ifempty@true,\ekv@ifempty@false,
+% \ekv@ifempty@true@F,\ekv@ifempty@true@F@gobble,
+% \ekv@ifempty@true@F@gobbletwo
+% }
+% We can test for a lot of things building on an if-empty test, so lets define a
+% really fast one. Since some tests might have reversed logic (true if something
+% is not empty) we also set up macros for the reversed branches.
+% \begin{macrocode}
+\long\def\ekv@ifempty#1%
+ {%
+ \ekv@ifempty@\ekv@ifempty@A#1\ekv@ifempty@B\ekv@ifempty@true
+ \ekv@ifempty@A\ekv@ifempty@B\@secondoftwo
+ }
+\long\def\ekv@ifempty@#1\ekv@ifempty@A\ekv@ifempty@B{}
+\long\def\ekv@ifempty@true\ekv@ifempty@A\ekv@ifempty@B\@secondoftwo#1#2{#1}
+\long\def\ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo#1#2{#2}
+\long\def\ekv@ifempty@true@F\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1{}
+\long\def\ekv@ifempty@true@F@gobble\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1#2%
+ {}
+\long\def\ekv@ifempty@true@F@gobbletwo
+ \ekv@ifempty@A\ekv@ifempty@B\@firstofone#1#2#3%
+ {}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekv@ifblank,\ekv@ifblank@,\ekv@ifblank@false,\ekv@ifblank@gobbletrue}
+% The obvious test that can be based on an if-empty is if-blank, meaning a test
+% checking whether the argument is empty or consists only of spaces. But instead
+% of building atop |\ekv@ifempty| our version will utilise the fact that the
+% argument in none of our usages can contain |\ekv@stop| (due to the way we
+% check for end-of-list), and hence we can use an even faster check. This here
+% works due to the fact that \TeX\ will read at least one token (or a group) for
+% an undelimited parameter which might be the end marker of the delimited next
+% parameter. So if |#1| to |\ekv@ifblank| is indeed blank, |#1| of
+% |\ekv@ifblank@| will be the placed |\ekv@stop| and |#2| will be anything until
+% the next |\ekv@stop|. The wrapper |\ekv@ifblank| will not be used by \expkv\
+% for speed reasons but \expkvo\ uses it. Also, not only a |TF| variant is
+% provided but also a rather strange one that assumes that only the |F| branch
+% is provided and that this branch consists only of a single token.
+% \begin{macrocode}
+\long\def\ekv@ifblank#1%
+ {\ekv@ifblank@#1\ekv@stop\ekv@ifblank@false\ekv@stop\@firstoftwo}
+\long\def\ekv@ifblank@\ekv@mark#1#2\ekv@stop{}
+\long\def\ekv@ifblank@false\ekv@stop\@firstoftwo#1#2{#2}
+\def\ekv@ifblank@gobbletrue\ekv@stop#1{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@ifdefined}
+% We'll need to check whether something is defined quite frequently, so why not
+% define a macro that does this. The following test is expandable and pretty
+% fast. The version with |\lastnamedcs| is the fastest version to test for an
+% undefined macro I know of (that considers both undefined macros and those with
+% the meaning |\relax|).
+% \begin{macrocode}
+\ekv@if@lastnamedcs
+ {%
+ \long\def\ekv@ifdefined#1{\ifcsname#1\endcsname\ekv@ifdef@\fi\@secondoftwo}
+ \def\ekv@ifdef@\fi\@secondoftwo
+ {%
+ \fi
+ \expandafter\ifx\lastnamedcs\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ }
+ }
+ {%
+ \long\def\ekv@ifdefined#1%
+ {%
+ \ifcsname#1\endcsname\ekv@ifdef@\fi\ekv@ifdef@false#1\endcsname\relax
+ \ekv@fi@secondoftwo
+ \fi
+ \@firstoftwo
+ }
+ \def\ekv@ifdef@\fi\ekv@ifdef@false{\fi\expandafter\ifx\csname}
+ \long\def\ekv@ifdef@false
+ #1\endcsname\relax\ekv@fi@secondoftwo\fi\@firstoftwo#2#3%
+ {#3}
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@strip,\ekv@strip@a,\ekv@strip@b,\ekv@strip@c}
+% We borrow some ideas of \pkg{expl3}'s \pkg{l3tl} to strip spaces
+% from keys and values. This |\ekv@strip| also strips one level of outer braces
+% \emph{after} stripping spaces, so an input of | {abc} | becomes |abc| after
+% stripping. It should be used with |#1| prefixed by |\ekv@mark|. Also this
+% implementation at most strips \emph{one} space from both sides (which should
+% be fine most of the time, since \TeX\ reads consecutive spaces as a single one
+% during tokenisation).
+% \begin{macrocode}
+\def\ekv@strip#1%
+ {%
+ \long\def\ekv@strip##1%
+ {%
+ \ekv@strip@a
+ ##1\ekv@nil
+ \ekv@mark#1%
+ #1\ekv@nil
+ }%
+ \long\def\ekv@strip@a##1\ekv@mark#1{\ekv@strip@b##1\ekv@mark}%
+ }
+\ekv@strip{ }
+\long\def\ekv@strip@b#1 \ekv@nil{\ekv@strip@c#1\ekv@nil}
+\long\def\ekv@strip@c\ekv@mark#1\ekv@nil\ekv@mark#2\ekv@nil#3{#3{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekv@strip@key,\ekv@strip@key@a,\ekv@strip@key@b,\ekv@strip@key@c}
+% Same idea and code as |\ekv@strip|, but the second argument to
+% |\ekv@strip@key| must be a single token and the result of the stripping will
+% be |\detokenize|d.
+% \begin{macrocode}
+\def\ekv@strip@key#1%
+ {%
+ \long\def\ekv@strip@key##1{\ekv@strip@key@a##1\ekv@nil\ekv@mark#1#1\ekv@nil}
+ \long\def\ekv@strip@key@a##1\ekv@mark#1{\ekv@strip@key@b##1\ekv@mark}
+ }
+\ekv@strip@key{ }
+\long\def\ekv@strip@key@b#1 \ekv@nil{\ekv@strip@key@c#1\ekv@nil}
+\long\def\ekv@strip@key@c\ekv@mark#1\ekv@nil\ekv@mark#2\ekv@nil#3%
+ {\expandafter#3\detokenize{#1}\ekv@mark{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekv@exparg,\ekv@exparg@,
+% \ekv@expandedarg,\ekv@fexparg,\ekv@expandafter
+% \ekv@expargtwice,\ekv@expargtwice@,\ekv@zero
+% }
+% To reduce some code doublets while gaining some speed (and also as convenience
+% for other packages in the family), it is often useful to expand the first
+% token in a definition once. Let's define a wrapper for this. And while we're
+% at it, also define a helper for |f|-~and |e|-expansion as well.
+%
+% Also, to end a |\romannumeral| expansion, we want to use |\z@|, which is
+% contained in both plain \TeX\ and \LaTeX, but we use a private name for it to
+% make it easier to spot and hence easier to manage.
+% \begin{macrocode}
+\let\ekv@zero\z@
+\long\def\ekv@exparg#1#2%
+ {\ekv@expanded{\ekv@unexpanded{#1}\expandafter}\expandafter{#2}}
+\long\def\ekv@expandafter#1{\ekv@expanded{\ekv@unexpanded{#1}\expandafter}}
+\long\def\ekv@exparg@#1#2{#2{#1}}%
+\long\def\ekv@expandedarg#1#2{\ekv@expanded{\ekv@unexpanded{#1}{#2}}}
+\long\def\ekv@fexparg#1#2%
+ {%
+ \ekv@expanded{\ekv@unexpanded{#1}\expandafter}\expandafter
+ {\romannumeral`\^^@#2}%
+ }
+\long\def\ekv@expargtwice#1#2{\expandafter\ekv@expargtwice@\expandafter{#2}{#1}}
+\def\ekv@expargtwice@{\expandafter\ekv@exparg@\expandafter}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcsvloop}
+% \begin{macro}[internal]{\ekv@csv@loop@active,\ekv@csv@loop@active@end}
+% An |\ekvcsvloop| will just loop over a csv list in a simple manner. First we
+% split at active commas (gives better performance this way), next we have to
+% check whether we're at the end of the list (checking for |\ekv@stop|). If
+% not we go on splitting at commas of category other.
+% \begin{macrocode}
+\begingroup
+\def\ekvcsvloop#1{%
+\endgroup
+\long\def\ekvcsvloop##1##2%
+ {\ekv@csv@loop@active{##1}\ekv@mark##2#1\ekv@stop#1}
+% \end{macrocode}
+% This does the same as |\ekv@csv@loop| but for active commas.
+% \begin{macrocode}
+\long\def\ekv@csv@loop@active##1##2#1%
+ {%
+ \ekv@gobble@from@mark@to@stop##2\ekv@csv@loop@active@end\ekv@stop
+ \ekv@csv@loop{##1}##2,\ekv@stop,%
+ }%
+\long\def\ekv@csv@loop@active@end
+ \ekv@stop
+ \ekv@csv@loop##1\ekv@mark\ekv@stop,\ekv@stop,%
+ {}%
+}
+% \end{macrocode}
+% Do the definitions with the weird catcode.
+% \begin{macrocode}
+\catcode`\,=13
+\ekvcsvloop,
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@csv@loop,\ekv@csv@loop@do,\ekv@csv@loop@end}
+% We use temporary macros and an |\expandafter| chain to preexpand
+% |\ekv@strip| here. After splitting at other commas we check again for end
+% the end of the sublist, check for blank elements which should be ignored,
+% and else strip spaces and execute the user code (protecting it from further
+% expanding with |\unexpanded|).
+% \begin{macrocode}
+\def\ekv@csv@loop#1%
+ {%
+ \long\def\ekv@csv@loop##1##2,%
+ {%
+ \ekv@gobble@from@mark@to@stop##2\ekv@csv@loop@end\ekv@stop
+ \ekv@ifblank@##2\ekv@stop\ekv@ifblank@gobbletrue
+ \ekv@stop\ekv@csv@loop@blank
+ #1\ekv@csv@loop@do{##1}%
+ }%
+ }
+\expandafter\ekv@csv@loop\expandafter{\ekv@strip{#2}}
+\long\def\ekv@csv@loop@do#1#2{\ekv@unexpanded{#2{#1}}\ekv@csv@loop{#2}\ekv@mark}
+\def\ekv@csv@loop@end#1%
+ {%
+ \long\def\ekv@csv@loop@end
+ \ekv@stop
+ \ekv@ifblank@\ekv@mark\ekv@stop\ekv@stop\ekv@ifblank@gobbletrue
+ \ekv@stop\ekv@csv@loop@blank
+ #1\ekv@csv@loop@do##1%
+ {\ekv@csv@loop@active{##1}\ekv@mark}%
+ }
+\expandafter\ekv@csv@loop@end\expandafter{\ekv@strip{\ekv@mark\ekv@stop}}
+\long\expandafter\def\expandafter\ekv@csv@loop@blank
+ \ekv@strip{\ekv@mark#1}\ekv@csv@loop@do#2%
+ {\ekv@csv@loop{#2}\ekv@mark}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekv@name,\ekv@name@set,\ekv@name@key}
+% The keys will all follow the same naming scheme, so we define it here.
+% \begin{macrocode}
+\def\ekv@name@set#1{ekv#1(}
+\long\def\ekv@name@key#1{#1)}
+\edef\ekv@name
+ {%
+ \ekv@unexpanded\expandafter{\ekv@name@set{#1}}%
+ \ekv@unexpanded\expandafter{\ekv@name@key{\detokenize{#2}}}%
+ }
+\long\ekv@exparg{\def\ekv@name#1#2}{\ekv@name}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@undefined@set}
+% We can misuse the macro name we use to expandably store the set-name in a
+% single token -- since this increases performance drastically, especially for
+% long set-names -- to throw a more meaningful error message in case a set isn't
+% defined. The name of |\ekv@undefined@set| is a little bit misleading, as it is
+% called in either case inside of |\csname|, but the result will be a control
+% sequence with meaning |\relax| if the set is undefined, hence will break the
+% |\csname| building the key-macro which will throw the error message.
+% \begin{macrocode}
+\def\ekv@undefined@set#1{! expkv Error: Set `#1' undefined.}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@checkvalid}
+% We place some restrictions on the allowed names, though, namely sets and
+% keys are not allowed to be empty -- blanks are fine (meaning \mbox{set-
+% or} key-names consisting of spaces). The |\def\ekv@tmp| gobbles any \TeX\
+% prefixes which would otherwise throw errors. This will, however, break the
+% package if an |\outer| has been gobbled this way. I consider that good,
+% because keys shouldn't be defined |\outer| anyways.
+% \begin{macrocode}
+\edef\ekv@checkvalid
+ {%
+ \ekv@unexpanded\expandafter{\ekv@ifempty{#1}}%
+ \ekv@unexpanded
+ {{%
+ \def\ekv@tmp{}%
+ \ekv@errm{empty set name not allowed}%
+ }}%
+ {%
+ \ekv@unexpanded\expandafter{\ekv@ifempty{#2}}%
+ \ekv@unexpanded
+ {%
+ {%
+ \def\ekv@tmp{}%
+ \ekv@errm{empty key name not allowed}%
+ }%
+ \@secondoftwo
+ }%
+ }%
+ \ekv@unexpanded{\@gobble}%
+ }
+\ekv@exparg{\protected\def\ekv@checkvalid#1#2}{\ekv@checkvalid}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvifdefined,\ekvifdefinedNoVal}
+% And provide user-level macros to test whether a key is defined.
+% \begin{macrocode}
+\ekv@expargtwice{\long\def\ekvifdefined#1#2}%
+ {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}}}
+\ekv@expargtwice{\long\def\ekvifdefinedNoVal#1#2}%
+ {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}N}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal,
+% \ekvdefunknown,\ekvdefunknownNoVal,\ekvletunknown,\ekvletunknownNoVal
+% }
+% Set up the key defining macros |\ekvdef| etc. We use temporary macros to set
+% these up with a few expansions already done.
+% \begin{macrocode}
+\def\ekvdef#1#2#3#4#5#6%
+ {%
+ \protected\long\def\ekvdef##1##2##3%
+ {#1{\expandafter\def\csname#2\endcsname####1{##3}#4}}%
+ \protected\long\def\ekvdefNoVal##1##2##3%
+ {#1{\expandafter\def\csname#2N\endcsname{##3}#4}}%
+ \protected\long\def\ekvlet##1##2##3%
+ {#1{\expandafter\let\csname#2\endcsname##3#4}}%
+ \protected\long\def\ekvletNoVal##1##2##3%
+ {#1{\expandafter\let\csname#2N\endcsname##3#4}}%
+ \ekv@expargtwice{\protected\long\def\ekv@defunknown##1##2##3##4}%
+ {%
+ \romannumeral
+ \ekv@exparg
+ {\ekv@zero\ekv@checkvalid{##3}.}%
+ {%
+ \expandafter\expandafter\expandafter
+ \def\expandafter\csname\ekv@name{##3}{}u##1\endcsname##2{##4}%
+ #6%
+ }%
+ }%
+ \ekv@expargtwice{\protected\long\def\ekv@letunknown##1##2##3}%
+ {%
+ \romannumeral
+ \ekv@exparg
+ {\ekv@zero\ekv@checkvalid{##2}.}%
+ {%
+ \expandafter\expandafter\expandafter
+ \let\expandafter\csname\ekv@name{##2}{}u##1\endcsname##3%
+ #5%
+ }%
+ }%
+ \protected\long\def\ekvletkv##1##2##3##4%
+ {%
+ #1%
+ {%
+ \expandafter\let\csname#2\expandafter\endcsname
+ \csname#3\endcsname
+ #4%
+ }%
+ }%
+ \protected\long\def\ekvletkvNoVal##1##2##3##4%
+ {%
+ #1%
+ {%
+ \expandafter\let\csname#2N\expandafter\endcsname
+ \csname#3N\endcsname
+ #4%
+ }%
+ }%
+ }
+\edef\ekvdefNoVal
+ {%
+ {\ekv@unexpanded\expandafter{\ekv@checkvalid{#1}{#2}}}%
+ {\ekv@unexpanded\expandafter{\ekv@name{#1}{#2}}}%
+ {\ekv@unexpanded\expandafter{\ekv@name{#3}{#4}}}%
+ {%
+ \ekv@unexpanded{\expandafter\ekv@defsetmacro\csname}%
+ \ekv@unexpanded\expandafter{\ekv@undefined@set{#1}\endcsname{#1}}%
+ }%
+ {%
+ \ekv@unexpanded{\expandafter\ekv@defsetmacro\csname}%
+ \ekv@unexpanded\expandafter{\ekv@undefined@set{#2}\endcsname{#2}}%
+ }%
+ {%
+ \ekv@unexpanded{\expandafter\ekv@defsetmacro\csname}%
+ \ekv@unexpanded\expandafter{\ekv@undefined@set{#3}\endcsname{#3}}%
+ }%
+ }
+\expandafter\ekvdef\ekvdefNoVal
+\ekv@exparg{\protected\long\def\ekvdefunknown#1#2}%
+ {\ekv@defunknown{}{##1##2##3}{#1}{#2}}
+\ekv@exparg{\protected\long\def\ekvdefunknownNoVal#1#2}%
+ {\ekv@defunknown{N}{##1##2}{#1}{#2}}
+\ekv@exparg{\protected\long\def\ekvletunknown#1#2}%
+ {\ekv@letunknown{}{#1}{#2}}
+\ekv@exparg{\protected\long\def\ekvletunknownNoVal#1#2}%
+ {\ekv@letunknown{N}{#1}{#2}}
+\let\ekv@defunknown\ekv@undefined
+\let\ekv@letunknown\ekv@undefined
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvredirectunknown,\ekvredirectunknownNoVal}
+% \begin{macro}[internal]
+% {
+% \ekv@defredirectunknown,\ekv@redirectunknown@aux,
+% \ekv@redirectunknownNoVal@aux
+% }
+% The redirection macros prepare the unknown function by looping over the
+% provided list of sets and leaving a |\ekv@redirect@kv| or |\ekv@redirect@k|
+% for each set. Only the first of these internals will receive the \key\ and
+% \val\ as arguments.
+% \begin{macrocode}
+\protected\def\ekv@defredirectunknown#1#2#3#4#5#6%
+ {%
+ \begingroup
+ \edef\ekv@tmp
+ {%
+ \ekvcsvloop#1{#6}%
+ \ekv@unexpanded{#2}%
+ {\ekvcsvloop{}{#5,#6}}%
+ }%
+ \ekv@expargtwice
+ {\endgroup\long#3{#5}}%
+ {\expandafter#4\ekv@tmp\ekv@stop}%
+ }
+\ekv@exparg{\protected\def\ekvredirectunknown#1#2}%
+ {%
+ \ekv@defredirectunknown
+ \ekv@redirect@kv
+ \ekv@err@redirect@kv@notfound
+ \ekvdefunknown
+ \ekv@redirectunknown@aux
+ {#1}{#2}%
+ }
+\ekv@exparg{\protected\def\ekvredirectunknownNoVal#1#2}%
+ {%
+ \ekv@defredirectunknown
+ \ekv@redirect@k
+ \ekv@err@redirect@k@notfound
+ \ekvdefunknownNoVal
+ \ekv@redirectunknownNoVal@aux
+ {#1}{#2}%
+ }
+\def\ekv@redirectunknown@aux#1{#1{##1}{##2}}
+\def\ekv@redirectunknownNoVal@aux#1{#1{##1}}
+\let\ekv@defredirectunknown\ekv@undefined
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekv@redirect@k,\ekv@redirect@k@a,\ekv@redirect@k@a@,
+% \ekv@redirect@k@b,\ekv@redirect@k@c,\ekv@redirect@k@d,
+% \ekv@redirect@kv,\ekv@redirect@kv@a,\ekv@redirect@kv@a@,
+% \ekv@redirect@kv@b,\ekv@redirect@kv@c,\ekv@redirect@kv@d
+% }
+% The redirect code works by some simple loop over all the sets, which we
+% already preprocessed in |\ekv@defredirectunknown|. For some optimisation we
+% blow this up a bit code wise, essentially, all this does is |\ekvifdefined|
+% or |\ekvifdefinedNoVal| in each set, if there is a match gobble the
+% remainder of the specified sets and execute the key macro, else go on with
+% the next set (to which the \key\ and \val\ are forwarded).
+%
+% First we set up some code which is different depending on |\lastnamedcs|
+% being available or not. All this is stored in a temporary macro to have
+% pre-expanded |\ekv@name| constellations ready.
+% \begin{macrocode}
+\def\ekv@redirect@k#1#2#3#4%
+ {%
+ \ekv@if@lastnamedcs
+ {%
+ \def\ekv@redirect@k##1##2##3%
+ {%
+ \ifcsname#1\endcsname\ekv@redirect@k@a\fi
+ ##3{##1}%
+ }%
+ \def\ekv@redirect@k@a\fi{\fi\expandafter\ekv@redirect@k@b\lastnamedcs}%
+ \long\def\ekv@redirect@kv##1##2##3##4%
+ {%
+ \ifcsname#2\endcsname\ekv@redirect@kv@a\fi\@gobble{##1}%
+ ##4{##1}{##2}%
+ }%
+ \def\ekv@redirect@kv@a\fi\@gobble
+ {\fi\expandafter\ekv@redirect@kv@b\lastnamedcs}%
+ }
+ {%
+ \def\ekv@redirect@k##1##2##3%
+ {%
+ \ifcsname#1\endcsname\ekv@redirect@k@a\fi\ekv@redirect@k@a@
+ #1\endcsname
+ ##3{##1}%
+ }%
+ \def\ekv@redirect@k@a@#3\endcsname{}%
+ \def\ekv@redirect@k@a\fi\ekv@redirect@k@a@
+ {\fi\expandafter\ekv@redirect@k@b\csname}%
+ \long\def\ekv@redirect@kv##1##2##3##4%
+ {%
+ \ifcsname#2\endcsname\ekv@redirect@kv@a\fi\ekv@redirect@kv@a@
+ #2\endcsname{##1}%
+ ##4{##1}{##2}%
+ }%
+ \long\def\ekv@redirect@kv@a@#4\endcsname##3{}%
+ \def\ekv@redirect@kv@a\fi\ekv@redirect@kv@a@
+ {\fi\expandafter\ekv@redirect@kv@b\csname}%
+ }%
+ }
+% \end{macrocode}
+% The key name given to this loop will already be |\detokenize|d by |\ekvset|,
+% so we can safely remove the |\detokenize| here for some performance gain.
+% \begin{macrocode}
+\def\ekv@redirect@kv#1\detokenize#2#3\ekv@stop{\ekv@unexpanded{#1#2#3}}
+\edef\ekv@redirect@kv
+ {%
+ {\expandafter\ekv@redirect@kv\ekv@name{#2}{#1}N\ekv@stop}%
+ {\expandafter\ekv@redirect@kv\ekv@name{#3}{#2}\ekv@stop}%
+ {\expandafter\ekv@redirect@kv\ekv@name{#1}{#2}N\ekv@stop}%
+ {\expandafter\ekv@redirect@kv\ekv@name{#1}{#2}\ekv@stop}%
+ }
+% \end{macrocode}
+% Everything is ready to make the real definitions.
+% \begin{macrocode}
+\expandafter\ekv@redirect@k\ekv@redirect@kv
+% \end{macrocode}
+% The remaining macros here are independent on |\lastnamedcs|, starting from
+% the |@b| we know that there is a hash table entry, and get the macro as a
+% parameter. We still have to test whether the macro is |\relax|, depending on
+% the result of that test we have to either remove the remainder of the
+% current test, or the remainder of the set list and invoke the macro.
+% \begin{macrocode}
+\def\ekv@redirect@k@b#1%
+ {\ifx\relax#1\ekv@redirect@k@c\fi\ekv@redirect@k@d#1}
+\def\ekv@redirect@k@c\fi\ekv@redirect@k@d#1{\fi}
+\def\ekv@redirect@k@d#1#2\ekv@stop{#1}
+\def\ekv@redirect@kv@b#1%
+ {\ifx\relax#1\ekv@redirect@kv@c\fi\ekv@redirect@kv@d#1}
+\long\def\ekv@redirect@kv@c\fi\ekv@redirect@kv@d#1#2{\fi}
+\long\def\ekv@redirect@kv@d#1#2#3\ekv@stop{#1{#2}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@defsetmacro}
+% In order to enhance the speed the set name given to |\ekvset| will be turned
+% into a control sequence pretty early, so we have to define that control
+% sequence.
+% \begin{macrocode}
+\edef\ekv@defsetmacro
+ {%
+ \ekv@unexpanded{\ifx#1\relax\edef#1##1}%
+ {%
+ \ekv@unexpanded\expandafter{\ekv@name@set{#2}}%
+ \ekv@unexpanded\expandafter{\ekv@name@key{##1}}%
+ }%
+ \ekv@unexpanded{\fi}%
+ }
+\ekv@exparg{\protected\def\ekv@defsetmacro#1#2}{\ekv@defsetmacro}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvifdefinedset}
+% \begin{macrocode}
+\ekv@expargtwice{\def\ekvifdefinedset#1}%
+ {\expandafter\ekv@ifdefined\expandafter{\ekv@undefined@set{#1}}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@ifexp}
+% We want to be able to include expansion control. This is started by a
+% specific structure, namely if the stuff to the left of the equals sign
+% contains a colon followed by a space followed by at least one non-space
+% token. There is an additional rule namely the contents in front of the
+% \verb*|: | marker mustn't contain spaces outside of braces, but
+% unfortunately we can test this only after we did the real split and not as
+% part of a fast test. The temporary meaning we set up here will get
+% \tkn{:}{13}\vissp{ } and \tkn{:}{11}\vissp{ } as |#1| and |#2|.
+%
+% The real definition will take three arguments (two curried), namely the
+% un-|\detokenize|d name as |#1|, what should be done if the \expnotation\
+% should start as |#2|, and what should be done if no \expnotation\ is found
+% as |#3|.
+% \begin{macrocode}
+\def\ekv@ifexp#1#2%
+ {%
+% \end{macrocode}
+% In the following explanations I use \tkn{:}{12}, \tkn{:}{13}, and
+% \tkn{:}{11}, but I always mean that token followed by a space.
+% \begin{macro}[internal]{\ekv@ifexp@split@o@or@other}
+% \tkn{:}{12} splitter also used to test for \tkn{:}{13} and \tkn{:}{11}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@split@o@or@other
+ ##1: ##2\ekv@stop##3%
+ ##4#1##5\ekv@stop##6%
+ ##7#2##8\ekv@stop##9%
+ {##9##6##3##1\ekv@stop##2}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]{\ekv@ifexp@split@a@or@l}
+% \tkn{:}{13} splitter also used to test for \tkn{:}{11}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@split@a@or@l
+ ##1#1##2\ekv@stop##3%
+ ##4#2##5\ekv@stop##6%
+ {##6##3##1\ekv@stop##2}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {\ekv@ifexp@split@a,\ekv@ifexp@split@l}
+% \tkn{:}{13} splitter
+% \begin{macrocode}
+ \long\def\ekv@ifexp@split@a##1#1##2\ekv@stop##3%
+ {##3##1\ekv@stop##2}%
+% \end{macrocode}
+% \tkn{:}{11} splitter
+% \begin{macrocode}
+ \long\def\ekv@ifexp@split@l##1#2##2\ekv@stop##3%
+ {##3##1\ekv@stop##2}%
+% \end{macrocode}
+% \end{macro}
+% To get good performance in the most common case (standard category codes
+% apply) we try to split on \tkn{:}{12}, due to the way this split works there
+% are a few possible outcomes:
+% \begin{enumerate}
+% \item |\ekv@ifexp@none| is the first token if no colon was
+% found at all
+% \item |\ekv@ifexp@o| is the first token if only \tkn{:}{12}
+% were part of \key
+% \item |\ekv@ifexp@a| is put in front of either of the two
+% aforementioned cases if there was at least one \tkn{:}{13} (in that case
+% we don't yet know which was the first colon)
+% \item |\ekv@ifexp@o| is put in front of any of the
+% aforementioned cases if there was at least one \tkn{:}{11} (in which
+% case we also don't know yet which was the first colon)
+% \end{enumerate}
+% \begin{macrocode}
+ \long\def\ekv@ifexp##1%
+ {%
+ \ekv@ifexp@split@o@or@other
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@o
+ : \ekv@stop\ekv@ifexp@none
+ ##1\ekv@stop\ekv@ifexp@a#1\ekv@stop{}%
+ ##1\ekv@stop\ekv@ifexp@l#2\ekv@stop{}%
+ }%
+% \end{macrocode}
+% \begin{macro}[internal]
+% {\ekv@ifexp@o,\ekv@ifexp@none}
+% If any of the next two are called we already know the outcome and can
+% directly expand to it.
+% \begin{macrocode}
+ \long\def\ekv@ifexp@o##1\ekv@stop
+ {\ekv@ifexp@done{##1}\ekv@mark}%
+ \long\def\ekv@ifexp@none
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@o\ekv@stop
+ ##2##3%
+ {##3}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {\ekv@ifexp@a,\ekv@ifexp@a@i,\ekv@ifexp@a@ii}
+% If this is called we know that there was no \tkn{:}{13}, if the first token
+% now is |\ekv@ifexp@none| there was no \tkn{:}{12} as well
+% \begin{macrocode}
+ \def\ekv@ifexp@a##1%
+ {%
+ \ekv@ifexp@a@i
+ ##1\ekv@ifexp@a@ii
+ \ekv@ifexp@none\ekv@ifexp@a@or@o
+ }%
+ \def\ekv@ifexp@a@i##1\ekv@ifexp@none{}%
+% \end{macrocode}
+% Easy route, no \tkn{:}{12}, simply grab and pack
+% \begin{macrocode}
+ \long\def\ekv@ifexp@a@ii
+ \ekv@ifexp@none\ekv@ifexp@a@or@o
+ ##1#1##2\ekv@stop\ekv@ifexp@o\ekv@stop
+ {\ekv@ifexp@done{##1}\ekv@mark##2}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {
+% \ekv@ifexp@a@or@o,
+% \ekv@ifexp@a@not@o,\ekv@ifexp@a@not@o@,
+% \ekv@ifexp@o@not@a
+% }
+% other route, there is a \tkn{:}{12}, re-split at \tkn{:}{13}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@a@or@o##1\ekv@stop
+ {%
+ \ekv@ifexp@split@a
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@a@not@o
+ #1\ekv@stop\ekv@ifexp@o@not@a
+ }%
+% \end{macrocode}
+% \tkn{:}{13} came earlier than \tkn{:}{12}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@a@not@o##1\ekv@stop
+ {\ekv@ifexp@a@not@o@{##1}\ekv@mark}
+ \long\def\ekv@ifexp@a@not@o@
+ ##1##2\ekv@nil#1\ekv@stop\ekv@ifexp@o@not@a
+ {\ekv@ifexp@done{##1}##2: }%
+% \end{macrocode}
+% \tkn{:}{12} came earlier than \tkn{:}{13}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@o@not@a
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@a@not@o\ekv@stop
+ {\ekv@ifexp@done{##1}\ekv@mark}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]{\ekv@ifexp@l,\ekv@ifexp@l@i,\ekv@ifexp@l@ii}
+% Now this is the most complicated case, if |\ekv@ifexp@l| is
+% called there are a few possibilities:
+% \begin{enumerate}
+% \item |#1| is |\ekv@ifexp@none|: easiest route, only
+% \tkn{:}{11} was there
+% \item |#1| is |\ekv@ifexp@o|: complicated route, there was a
+% \tkn{:}{11} and a \tkn{:}{12}
+% \item |#1| is |\ekv@ifexp@a| and after that comes
+% |\ekv@ifexp@none|: more complicated, there was a
+% \tkn{:}{11} and a \tkn{:}{13}
+% \item |#1| is |\ekv@ifexp@a| and after that comes
+% |\ekv@ifexp@o|: cursed route, there were \tkn{:}{11},
+% \tkn{:}{12}, and \tkn{:}{13}
+% \end{enumerate}
+% \begin{macrocode}
+ \def\ekv@ifexp@l##1%
+ {%
+ \ekv@ifexp@l@i
+ ##1\ekv@ifexp@l@ii
+ \ekv@ifexp@none{}%
+ ##1\ekv@ifexp@l@or@o
+ \ekv@ifexp@o
+ \ekv@ifexp@l@or@a
+ }%
+ \def\ekv@ifexp@l@i
+ ##1\ekv@ifexp@none##2%
+ ##3\ekv@ifexp@o
+ {##2}%
+% \end{macrocode}
+% easiest route, just \tkn{:}{11}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@l@ii
+ \ekv@ifexp@l@or@a##1#2##2\ekv@stop
+ \ekv@ifexp@o\ekv@stop#2\ekv@stop##3%
+ {\ekv@ifexp@done{##1}\ekv@mark##2}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {
+% \ekv@ifexp@l@or@o,
+% \ekv@ifexp@l@not@o,\ekv@ifexp@l@not@o@,
+% \ekv@ifexp@o@not@l
+% }
+% slightly harder, \tkn{:}{11} or \tkn{:}{12}, re-split at \tkn{:}{11}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@l@or@o
+ \ekv@ifexp@o\ekv@ifexp@l@or@a
+ ##1\ekv@stop
+ {%
+ \ekv@ifexp@split@l
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@l@not@o
+ #2\ekv@stop\ekv@ifexp@o@not@l
+ }%
+% \end{macrocode}
+% \tkn{:}{11} came earlier than \tkn{:}{12}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@l@not@o##1\ekv@stop
+ {\ekv@ifexp@l@not@o@{##1}\ekv@mark}
+ \long\def\ekv@ifexp@l@not@o@
+ ##1##2\ekv@nil#2\ekv@stop\ekv@ifexp@o@not@l
+ ##3#2\ekv@stop##4%
+ {\ekv@ifexp@done{##1}##2: ##3}%
+% \end{macrocode}
+% \tkn{:}{12} came earlier than \tkn{:}{11}
+% \begin{macrocode}
+ \long\def\ekv@ifexp@o@not@l
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@l@not@o\ekv@stop
+ ##2#2\ekv@stop##3%
+ {\ekv@ifexp@done{##1}\ekv@mark##2}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {
+% \ekv@ifexp@l@or@a,
+% \ekv@ifexp@l@or@a@not@o,
+% \ekv@ifexp@l@not@a,\ekv@ifexp@l@not@a@,
+% \ekv@ifexp@a@not@l
+% }
+% \tkn{:}{13} was in the mix with \tkn{:}{11}, we need to see whether there
+% was a \tkn{:}{12} as well
+% \begin{macrocode}
+ \def\ekv@ifexp@l@or@a##1%
+ {%
+% \end{macrocode}
+% don't get confused by the name, this gobbles until |@none|
+% \begin{macrocode}
+ \ekv@ifexp@a@i
+ ##1\ekv@ifexp@l@or@a@not@o
+ \ekv@ifexp@none
+ \ekv@ifexp@l@or@a@or@o
+ }%
+% \end{macrocode}
+% phew, no \tkn{:}{12} in the mix, we split at \tkn{:}{13} and see whether an
+% earlier \tkn{:}{11} is found
+% \begin{macrocode}
+ \long\def\ekv@ifexp@l@or@a@not@o
+ \ekv@ifexp@none\ekv@ifexp@l@or@a@or@o
+ ##1#1%
+ {%
+ \ekv@ifexp@split@l
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@l@not@a
+ #2\ekv@stop\ekv@ifexp@a@not@l
+ }%
+ \long\def\ekv@ifexp@l@not@a##1\ekv@stop
+ {\ekv@ifexp@l@not@a@{##1}\ekv@mark}%
+ \long\def\ekv@ifexp@l@not@a@
+ ##1##2\ekv@nil#2\ekv@stop\ekv@ifexp@a@not@l
+ ##3\ekv@stop\ekv@ifexp@o\ekv@stop#2\ekv@stop##4%
+ {\ekv@ifexp@done{##1}##2#1##3}%
+ \long\def\ekv@ifexp@a@not@l
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@l@not@a\ekv@stop
+ ##2\ekv@stop\ekv@ifexp@o\ekv@stop#2\ekv@stop##3%
+ {\ekv@ifexp@done{##1}\ekv@mark##2}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {
+% \ekv@ifexp@l@or@a@or@o,\ekv@ifexp@l@or@a@or@o@i,\ekv@ifexp@l@or@a@or@o@ii,
+% \ekv@ifexp@l@or@a@or@o@iii,\ekv@ifexp@l@or@a@or@o@iv,
+% \ekv@ifexp@o@not@l@or@a,
+% \ekv@ifexp@a@not@l@or@o,\ekv@ifexp@a@not@l@or@o@
+% }
+% ooh no, the ugliest path, we got ourself a \tkn{:}{11}, a \tkn{:}{12}, and a
+% \tkn{:}{13}, first grab everything left after splitting the first
+% \tkn{:}{12} and try a \tkn{:}{13} split
+% \begin{macrocode}
+ \long\def\ekv@ifexp@l@or@a@or@o##1\ekv@stop
+ {%
+ \ekv@ifexp@split@a@or@l
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@a@not@l@or@o
+ #1\ekv@stop\ekv@ifexp@o@not@l@or@a
+ ##1\ekv@stop\ekv@ifexp@l@or@a@or@o@i#2\ekv@stop{}%
+ }%
+% \end{macrocode}
+% \tkn{:}{12} splitting was correct
+% \begin{macrocode}
+ \long\def\ekv@ifexp@o@not@l@or@a
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@a@not@l@or@o\ekv@stop
+ ##2#2\ekv@stop##3%
+ {\ekv@ifexp@done{##1}\ekv@mark##2}%
+% \end{macrocode}
+% \tkn{:}{13} split is correct, \tkn{:}{12} has to be reverted
+% \begin{macrocode}
+ \long\def\ekv@ifexp@a@not@l@or@o##1\ekv@stop
+ {\ekv@ifexp@a@not@l@or@o@{##1}\ekv@mark}
+ \long\def\ekv@ifexp@a@not@l@or@o@
+ ##1##2\ekv@nil##3#2\ekv@stop##4%
+ {\ekv@ifexp@done{##1}##2: ##3}%
+% \end{macrocode}
+% there is still a \tkn{:}{11} left, we need to take care of \tkn{:}{13} as
+% well, but \tkn{:}{12} was wrong
+% \begin{macrocode}
+ \def\ekv@ifexp@l@or@a@or@o@i##1%
+ {%
+ \ekv@ifexp@l@or@a@or@o@ii
+ ##1\ekv@ifexp@l@or@a@or@o@iii
+ \ekv@ifexp@o@not@l@or@a
+ \ekv@ifexp@why
+ }%
+ \def\ekv@ifexp@l@or@a@or@o@ii
+ ##1\ekv@ifexp@o@not@l@or@a
+ {}%
+% \end{macrocode}
+% at least it's not absolutely the worst, \tkn{:}{11} is correct, revert the
+% \tkn{:}{12} split
+% \begin{macrocode}
+ \long\def\ekv@ifexp@l@or@a@or@o@iii
+ \ekv@ifexp@o@not@l@or@a\ekv@ifexp@why
+ ##1#2%
+ {\ekv@ifexp@l@or@a@or@o@iv{##1}\ekv@mark}%
+ \long\def\ekv@ifexp@l@or@a@or@o@iv
+ ##1##2\ekv@nil\ekv@stop\ekv@ifexp@a@not@l@or@o\ekv@stop
+ #2\ekv@stop##3##4#2\ekv@stop##5%
+ {\ekv@ifexp@done{##1}##2: ##4}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {
+% \ekv@ifexp@why,
+% \ekv@ifexp@why@l,\ekv@ifexp@why@l@i,\ekv@ifexp@why@l@ii,
+% \ekv@ifexp@why@a
+% }
+% why have you forsaken me? We know \tkn{:}{12} was wrong, but now we have
+% something that might be correctly split at \tkn{:}{13}, but might as well be
+% not
+% \begin{macrocode}
+ \long\def\ekv@ifexp@why##1\ekv@stop
+ {%
+ \ekv@ifexp@split@l
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@why@l
+ #2\ekv@stop\ekv@ifexp@why@a
+ }%
+% \end{macrocode}
+% \tkn{:}{11} is correct, rebuild stuff undoing the wrong \tkn{:}{13} split
+% \begin{macrocode}
+ \long\def\ekv@ifexp@why@l##1\ekv@stop
+ {\ekv@ifexp@why@l@i{##1}\ekv@mark}
+ \long\def\ekv@ifexp@why@l@i
+ ##1##2\ekv@nil#2\ekv@stop\ekv@ifexp@why@a
+ {\ekv@ifexp@why@l@ii{##1}##2#1}
+% \end{macrocode}
+% and undoing the wrong \tkn{:}{12} split
+% \begin{macrocode}
+ \long\def\ekv@ifexp@why@l@ii
+ ##1##2\ekv@nil#2\ekv@stop##3##4#2\ekv@stop##5%
+ {\ekv@ifexp@done{##1}##2: ##4}%
+% \end{macrocode}
+% \tkn{:}{13} is correct, we know there is a \tkn{:}{11} hiding somewhere, so
+% we don't need to protect against brace strip using a two-step grab here,
+% just undoing the wrong \tkn{:}{12} split is enough
+% \begin{macrocode}
+ \long\def\ekv@ifexp@why@a
+ ##1\ekv@nil\ekv@stop\ekv@ifexp@why@l\ekv@stop
+ ##2\ekv@nil#2\ekv@stop##3##4#2\ekv@stop##5%
+ {\ekv@ifexp@done{##1}\ekv@mark##2: ##4}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {
+% \ekv@ifexp@done,\ekv@ifexp@done@,
+% \ekv@ifexp@done@test,
+% \ekv@ifexp@panic
+% }
+% once the colon split is done we need to check that there are no spaces in
+% the now split of part, if there are \emph{panic} (we did all of this for
+% nothing), else we're finally completely done with the splitting business.
+% \begin{macrocode}
+ \ekv@exparg{\long\def\ekv@ifexp@done##1##2\ekv@nil}%
+ {%
+ \@firstofone
+ {\ekv@ifexp@done@test##1\ekv@nil\ekv@ifexp@panic} \ekv@nil{}%
+ ##2\ekv@stop\ekv@ifexp@done@{##1}{##2}\ekv@stop\@secondoftwo
+ }
+ \long\def\ekv@ifexp@done@test##1 ##2\ekv@nil##3##4##5##6\ekv@stop{##3}
+ \ekv@exparg{\long\def\ekv@ifexp@done@##1##2\ekv@stop\@secondoftwo##3}%
+ {\ekv@strip{##2}{##3{##1}}}%
+% \end{macrocode}
+% Panic in this case means give up on expansion parsing, instead the normal
+% action that would've been done if the expansion mark isn't found is
+% executed.
+% \begin{macrocode}
+ \long\def\ekv@ifexp@panic##1\@secondoftwo##2##3{##3}
+ }
+% \end{macrocode}
+% \end{macro}
+% We set up the strange category codes for colons and do the real definition
+% after the temporary one.
+% \begin{macrocode}
+\begingroup
+ \catcode`\~=13
+ \lccode`\~=`\:
+ \catcode`\z=11
+ \lccode`\z=`\:
+\lowercase{\endgroup
+\ekv@ifexp{~ }{z }}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvset}
+% Set up |\ekvset|, which should not be affected by active commas and equal
+% signs. The equal signs are a bit harder to cope with and we'll do that later,
+% but the active commas can be handled by just doing two comma-splitting loops
+% one at actives one at others. That's why we define |\ekvset| here with a
+% temporary meaning just to set up the things with two different category codes.
+% |#1| will be a \texttt{,\textsubscript{13}} and |#2| will be a
+% \texttt{=\textsubscript{13}}.
+% \begin{macrocode}
+\begingroup
+\def\ekvset#1#2{%
+\endgroup
+\ekv@exparg{\long\def\ekvset##1##2}%
+ {%
+ \expandafter\expandafter\expandafter
+ \ekv@set\expandafter\csname\ekv@undefined@set{##1}\endcsname
+ \ekv@mark##2#1\ekv@stop#1{}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@set}
+% |\ekv@set| will split the \kv\ list at active commas. Then it has to check
+% whether there were unprotected other commas and resplit there.
+% \begin{macrocode}
+\long\def\ekv@set##1##2#1%
+ {%
+% \end{macrocode}
+% Test whether we're at the end, if so invoke |\ekv@endset|,
+% \begin{macrocode}
+ \ekv@gobble@from@mark@to@stop##2\ekv@endset\ekv@stop
+% \end{macrocode}
+% else go on with other commas.
+% \begin{macrocode}
+ \ekv@set@other##1##2,\ekv@stop,%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@endset}
+% |\ekv@endset| is a hungry little macro. It will eat everything that remains
+% of |\ekv@set| and unbrace the sneaked stuff.
+% \begin{macrocode}
+\long\def\ekv@endset\ekv@stop\ekv@set@other##1\ekv@mark\ekv@stop,\ekv@stop,##2%
+ {##2}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@eq@other@or@active,\ekv@eq@active}
+% Splitting at equal signs will be done in a way that checks whether there is
+% an equal sign and splits at the same time. This gets quite messy and the
+% code might look complicated, but this is pretty fast (faster than first
+% checking for an equal sign and splitting if one is found). The splitting
+% code will be adapted for |\ekvset| and |\ekvparse| to get the most speed,
+% but some of these macros don't require such adaptions.
+% |\ekv@eq@other@or@active| and |\ekv@eq@active| will split the argument at
+% the first equal sign. |\ekv@eq@active| will insert the macro which comes
+% after the first following |\ekv@mark|, while |\ekv@eq@other@or@active| will
+% also check for an active equals sign or none.
+% Usage should look like this:
+% \begin{syntaxexample*}
+% |\ekv@eq@other@or@active|
+% \indent|#1\ekv@nil\ekv@mark|\meta{code for \tkn{=}{12}}
+% \indent\tkn{=}{12}|\ekv@mark|\meta{code for no equals sign}
+% \indent|#1\ekv@mark|\meta{code for \tkn{=}{13} or mixed}
+% \indent\tkn{=}{13}|\ekv@mark{}|
+% |\ekv@eq@active|
+% \indent|#1\ekv@nil\ekv@mark|\meta{code for \tkn{=}{13}}
+% \indent\tkn{=}{13}|\ekv@mark|\meta{code for no \tkn{=}{13}}
+% \end{syntaxexample*}
+% To prevent accidental brace stripping |#1| should be handed in with a
+% leading |\ekv@mark|, also that's what the |\ekv@nil| after the first |#1| is
+% used for. In |\ekv@eq@other@or@active| four cases are distinguished:
+% \begin{enumerate}
+% \item
+% Only equals signs of category 12 are found, then \meta{code for
+% \tkn{=}{12}} will be inserted.
+% \item
+% No equals sign is found, then \meta{code for no equals sign} will be
+% inserted.
+% \item
+% Only equals signs of category 13 are found, then \meta{code for
+% \tkn{=}{13} or mixed} will be inserted, directly followed by
+% \meta{code for no equals sign}.
+% \item
+% Equals signs of categories 12 and 13 are found, then \meta{code for
+% \tkn{=}{13} or mixed} directly followed by \meta{code for \tkn{=}{12}}
+% will be inserted.
+% \end{enumerate}
+% This allows for fast branching based on \TeX's argument grabbing rules and
+% we don't have to split after the branching if the equal sign was there.
+% \begin{macrocode}
+\long\def\ekv@eq@other@or@active
+ ##1=##2\ekv@mark##3%
+ ##4#2##5\ekv@mark##6%
+ {##6##3##1\ekv@stop\ekv@mark##2}
+\long\def\ekv@eq@other##1=##2\ekv@mark##3{##3##1\ekv@stop\ekv@mark##2}
+\long\def\ekv@eq@active##1#2##2\ekv@mark##3{##3##1\ekv@stop\ekv@mark##2}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@set@other,\ekv@set@next@other}
+% The macro |\ekv@set@other| is guaranteed to get only single \kv\ pairs.
+% \begin{macrocode}
+\long\def\ekv@set@other##1##2,%
+ {%
+% \end{macrocode}
+% First we test whether we're done.
+% \begin{macrocode}
+ \ekv@gobble@from@mark@to@stop##2\ekv@endset@other\ekv@stop
+% \end{macrocode}
+% If not we split at the equal sign of category other.
+% \begin{macrocode}
+ \ekv@eq@other@or@active
+ ##2\ekv@nil\ekv@mark\ekv@set@eq@other
+ =\ekv@mark\ekv@set@noeq
+ ##2\ekv@mark\ekv@set@eq@active
+ #2\ekv@mark{}%
+% \end{macrocode}
+% And put the set name after the splitting.
+% \begin{macrocode}
+ ##1%
+ \ekv@mark
+ }
+% \end{macrocode}
+% The second macro is used as a shortcut to gobble two arguments and do the
+% same as a following |\ekv@set@other|.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@set@next@other##1##2\ekv@set@other##3##4,}%
+ {\ekv@set@other{##3}{##4},}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@endset@other}
+% Breaking the current inner loop for \tkn{,}{12} is done by gobbling all the
+% remaining tokens and grabbing the next split at an active comma
+% (incorporating the next |\ekv@set| call).
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@endset@other
+ \ekv@stop\ekv@eq@other@or@active
+ \ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@set@eq@other
+ =\ekv@mark\ekv@set@noeq
+ \ekv@mark\ekv@stop\ekv@mark\ekv@set@eq@active#2\ekv@mark##1%
+ ##2##3#1}%
+ {\ekv@set{##2}{##3}#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@set@eq@other}
+% If this gets called we know that there is no \tkn{=}{13}, hence are done
+% with the splitting business. This doesn't even need much clean up, we can
+% just strip the \key-name and forward it to |\ekv@set@pair|.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@set@eq@other##1\ekv@stop}%
+ {\ekv@strip@key{##1}\ekv@set@pair}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@set@if@noeq}
+% In the case that there was at least one \tkn{=}{13} we need a way to know
+% whether there also was a \tkn{=}{12}. This here can be used to check this by
+% only looking for |\ekv@set@noeq|.
+% \begin{macrocode}
+\def\ekv@set@if@noeq##1\ekv@set@noeq{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@set@eq@active,\ekv@set@eq@active@}
+% The first token after this will either be |\ekv@set@noeq| or
+% |\ekv@set@eq@other|. We test this and branch accordingly.
+% \begin{macrocode}
+\def\ekv@set@eq@active##1%
+ {\ekv@set@if@noeq##1\ekv@set@eq@active@\ekv@set@noeq\ekv@set@eq@mixed}
+% \end{macrocode}
+% Since we know that there was no \tkn{=}{12} when the next macro is called we
+% can simply do the correct split without any checks and forward to
+% |\ekv@set@pair|.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@set@eq@active@
+ \ekv@set@noeq\ekv@set@eq@mixed
+ ##1#2##2\ekv@mark
+ \ekv@set@eq@other\ekv@stop\ekv@mark#2\ekv@mark##3}%
+ {\ekv@strip@key{##1}\ekv@set@pair\ekv@mark##2}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekv@set@eq@mixed,\ekv@set@eq@mixed@o,\ekv@set@mixed@a}
+% In the mixed case we grab until the first split of \tkn{=}{12} already done,
+% and resplit at \tkn{=}{13} using the conditonal splitter described earlier.
+% \begin{macrocode}
+\long\def\ekv@set@eq@mixed##1\ekv@stop
+ {%
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@set@eq@mixed@a
+ #2\ekv@mark\ekv@set@eq@mixed@o
+ }
+% \end{macrocode}
+% If there actually was no \tkn{=}{13} before the first \tkn{=}{12} everything
+% was fine. We pick up our first split and remove the gibberish left by the
+% conditional splitter.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@set@eq@mixed@o
+ ##1\ekv@nil\ekv@mark\ekv@set@eq@mixed@a\ekv@stop\ekv@mark
+ ##2\ekv@nil#2\ekv@mark##3}%
+ {\ekv@strip@key{##1}\ekv@set@pair##2\ekv@nil}
+% \end{macrocode}
+% |\ekv@set@eq@mixed@a| will trigger if before the first \tkn{=}{12} there was
+% already a \tkn{=}{13}. So we use the new split and revert the erroneous
+% split at \tkn{=}{12}.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@set@eq@mixed@a
+ ##1\ekv@stop
+ ##2\ekv@nil#2\ekv@mark\ekv@set@eq@mixed@o\ekv@mark
+ ##3#2\ekv@mark##4}%
+ {\ekv@strip@key{##1}\ekv@set@pair##2=##3}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@set@noeq,\ekv@set@was@blank}
+% If there was no equals sign the current element might in fact be blank.
+% Blank elements are ignored, hence we need to check for that, else we can
+% call |\ekv@set@key|.
+% \begin{macrocode}
+\ekv@expandedarg
+ {%
+ \long\def\ekv@set@noeq
+ ##1\ekv@nil\ekv@mark\ekv@set@eq@other\ekv@stop\ekv@mark
+ }%
+ {%
+ \ekv@unexpanded
+ {%
+ \ekv@ifblank@##1\ekv@stop\ekv@ifblank@gobbletrue
+ \ekv@stop\ekv@set@was@blank
+ }%
+ \ekv@unexpanded\expandafter{\ekv@strip@key{##1}\ekv@set@key}%
+ }
+% \end{macrocode}
+% If in fact the element was blank we remove the |\ekv@set@key| call and
+% instead do the next iteration of |\ekv@set@other|.
+% \begin{macrocode}
+\ekv@exparg{\long\expandafter\def\expandafter\ekv@set@was@blank
+ \ekv@strip@key{\ekv@mark##1}\ekv@set@key
+ ##2##3,}%
+ {\ekv@set@other{##2}{##3},}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak}
+% Provide macros that can completely stop the parsing of |\ekvset|, who knows
+% what it'll be useful for.
+% \begin{macrocode}
+\long\def\ekvbreak##1##2\ekv@stop#1##3{##1}
+\long\def\ekvbreakPreSneak ##1##2\ekv@stop#1##3{##1##3}
+\long\def\ekvbreakPostSneak##1##2\ekv@stop#1##3{##3##1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvsneak,\ekvsneakPre}
+% One last thing we want to do for |\ekvset| is to provide macros that just
+% smuggle stuff after |\ekvset|'s effects.
+% \begin{macrocode}
+\long\def\ekvsneak##1##2\ekv@stop#1##3{##2\ekv@stop#1{##3##1}}
+\long\def\ekvsneakPre##1##2\ekv@stop#1##3{##2\ekv@stop#1{##1##3}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvparse}
+% Additionally to the |\ekvset| macro we also want to provide an |\ekvparse|
+% macro, that has the same scope as |\keyval_parse:NNn| from \pkg{expl3}.
+% This is pretty analogue to the |\ekvset| implementation, we just put an
+% |\unexpanded| here and there instead of other macros to stop the |\expanded|
+% on our output. The |\unexpanded\expanded{{...}}| ensures that the material
+% is in an alignment safe group at all time, and that it doesn't expand any
+% further in an |\edef| or |\expanded| context.
+% \begin{macrocode}
+\long\def\ekvparse##1##2##3%
+ {%
+ \ekv@unexpanded\ekv@expanded
+ {{\ekv@parse{##1}{##2}\ekv@mark##3#1\ekv@stop#1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse}
+% \begin{macrocode}
+\long\def\ekv@parse##1##2##3#1%
+ {%
+ \ekv@gobble@from@mark@to@stop##3\ekv@endparse\ekv@stop
+ \ekv@parse@other{##1}{##2}##3,\ekv@stop,%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@endparse}
+% \begin{macrocode}
+\long\def\ekv@endparse\ekv@stop\ekv@parse@other##1\ekv@mark\ekv@stop,\ekv@stop,%
+ {}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse@other}
+% \begin{macrocode}
+\long\def\ekv@parse@other##1##2##3,%
+ {%
+ \ekv@gobble@from@mark@to@stop##3\ekv@endparse@other\ekv@stop
+ \ekv@eq@other@or@active
+ ##3\ekv@nil\ekv@mark\ekv@parse@eq@other
+ =\ekv@mark\ekv@parse@noeq
+ ##3\ekv@mark\ekv@parse@eq@active#2\ekv@mark{}%
+ {##1}{##2}%
+ \ekv@mark
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@endparse@other}
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@endparse@other
+ \ekv@stop\ekv@eq@other@or@active
+ \ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@parse@eq@other
+ =\ekv@mark\ekv@parse@noeq
+ \ekv@mark\ekv@stop\ekv@mark\ekv@parse@eq@active#2\ekv@mark##1%
+ ##2##3##4#1}%
+ {\ekv@parse{##2}{##3}{##4}#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse@eq@other}
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@parse@eq@other##1\ekv@stop}%
+ {\ekv@strip{##1}\ekv@parse@pair}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse@if@noeq}
+% \begin{macrocode}
+\def\ekv@parse@if@noeq##1\ekv@parse@noeq{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse@eq@active,\ekv@parse@eq@active@}
+% \begin{macrocode}
+\def\ekv@parse@eq@active##1%
+ {%
+ \ekv@parse@if@noeq##1\ekv@parse@eq@active@\ekv@parse@noeq
+ \ekv@parse@eq@mixed
+ }
+\ekv@exparg{\long\def\ekv@parse@eq@active@
+ \ekv@parse@noeq\ekv@parse@eq@mixed
+ ##1#2##2\ekv@mark
+ \ekv@parse@eq@other\ekv@stop\ekv@mark#2\ekv@mark##3}%
+ {\ekv@strip{##1}\ekv@parse@pair\ekv@mark##2}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekv@parse@eq@mixed,\ekv@parse@eq@mixed@o,\ekv@parse@eq@mixed@a}
+% \begin{macrocode}
+\long\def\ekv@parse@eq@mixed##1\ekv@stop
+ {%
+ \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@parse@eq@mixed@a
+ #2\ekv@mark\ekv@parse@eq@mixed@o
+ }
+\ekv@exparg{\long\def\ekv@parse@eq@mixed@a
+ ##1\ekv@stop
+ ##2\ekv@nil#2\ekv@mark\ekv@parse@eq@mixed@o\ekv@mark
+ ##3#2\ekv@mark##4}%
+ {\ekv@strip{##1}\ekv@parse@pair##2=##3}
+\ekv@exparg{\long\def\ekv@parse@eq@mixed@o
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@mixed@a\ekv@stop\ekv@mark
+ ##2\ekv@nil#2\ekv@mark##3}%
+ {\ekv@strip{##1}\ekv@parse@pair##2\ekv@nil}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse@noeq,\ekv@parse@was@blank}
+% \begin{macrocode}
+\ekv@expandedarg
+ {%
+ \long\def\ekv@parse@noeq
+ ##1\ekv@nil\ekv@mark\ekv@parse@eq@other\ekv@stop\ekv@mark
+ }%
+ {%
+ \ekv@unexpanded
+ {%
+ \ekv@ifblank@##1\ekv@stop\ekv@ifblank@gobbletrue
+ \ekv@stop\ekv@parse@was@blank
+ }%
+ \ekv@unexpanded\expandafter{\ekv@strip{##1}\ekv@parse@key}%
+ }
+\ekv@exparg{\long\expandafter\def\expandafter\ekv@parse@was@blank
+ \ekv@strip{\ekv@mark##1}\ekv@parse@key
+ ##2##3##4,}%
+ {\ekv@parse@other{##2}{##3}{##4},}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse@pair,\ekv@parse@pair@}
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@parse@pair##1##2\ekv@nil}%
+ {\ekv@strip{##2}\ekv@parse@pair@{##1}}
+\ekv@exparg{\long\def\ekv@parse@pair@##1##2##3##4}%
+ {%
+ \ekv@ifexp{##2}%
+ {\ekv@expansion@parse@pair{##1}{##4}}%
+ {\ekv@unexpanded{##4{##2}{##1}}}%
+ \ekv@parse@other{##3}{##4}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@parse@key}
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@parse@key##1##2}%
+ {%
+ \ekv@ifexp{##1}%
+ {\ekv@expansion@parse@key{##2}}%
+ {\ekv@unexpanded{##2{##1}}}%
+ \ekv@parse@other{##2}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% Finally really setting things up with |\ekvset|'s temporary meaning:
+% \begin{macrocode}
+}
+\catcode`\,=13
+\catcode`\==13
+\ekvset,=
+% \end{macrocode}
+%
+% \begin{macro}{\ekvsetSneaked}
+% This macro can be defined just by expanding |\ekvsneak| once after expanding
+% |\ekvset|. To expand everything as much as possible early on we use a
+% temporary definition.
+% \begin{macrocode}
+\edef\ekvsetSneaked
+ {%
+ \ekv@unexpanded{\ekvsneak{#2}}%
+ \ekv@unexpanded\expandafter{\ekvset{#1}{#3}}%
+ }
+\ekv@expargtwice{\long\def\ekvsetSneaked#1#2#3}{\ekvsetSneaked}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvchangeset}
+% Provide a macro that is able to switch out the current \set\ in |\ekvset|.
+% This operation allows something similar to \pkg{pgfkeys}'s
+% \texttt{\meta{key}/.cd} mechanism. However this operation can be more
+% expensive than |/.cd| as we can't just redefine some token to reflect this,
+% but have to switch out the set expandably, so this works similar to the
+% |\ekvsneak| macros reading and reinserting things, but it only has to read and
+% reinsert the remainder of the current key's replacement code.
+% \begin{macrocode}
+\ekv@exparg{\def\ekvchangeset#1}%
+ {%
+ \expandafter\expandafter\expandafter
+ \ekv@changeset\expandafter\csname\ekv@undefined@set{#1}\endcsname\ekv@empty
+ }
+% \end{macrocode}
+% \begin{macro}[internal]{\ekv@changeset}
+% This macro does the real change-out of |\ekvchangeset|. |#2| will have a
+% leading |\ekv@empty| so that braces aren't stripped accidentally, but that
+% will not hurt and just expand to nothing in one step.
+% \begin{macrocode}
+\long\def\ekv@changeset#1#2\ekv@set@other#3{#2\ekv@set@other#1}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekvmorekv}
+% |\ekvmorekv| injects additional keys for consideration without needing a
+% nested |\ekvset|. The issue we're facing here is that we can only inject
+% after the next |\ekv@set@other| to not destroy the order of things, but in
+% theory the argument to |\ekvmorekv| could contain an active comma. Now we
+% have two options:
+% \begin{enumerate}
+% \item reread all keys until the end of the current |\ekv@set@other| loop
+% to change the commas there to an active one and insert |\ekv@set|
+% instead
+% \item loop over the argument of |\ekvmorekv| to remove all top-level
+% active commas and replace them with ones of category 12.
+% \end{enumerate}
+% The following implements the second approach. We use a temporary definition
+% of |\ekvmorekv| to get us |#1| for active commas. For the comma replacement
+% we set up a small loop. The |\ekv@empty| at the end of |\ekvmorekv|'s
+% definition protects against accidental brace loss in user code.
+% \begin{macrocode}
+\def\ekvmorekv#1%
+ {%
+ \long\def\ekvmorekv##1%
+ {%
+ \expandafter\ekv@morekv\ekv@expanded
+ {{\ekv@morekv@loop\ekv@empty##1\ekv@stop\ekv@morekv@done#1}}%
+ \ekv@empty
+ }%
+% \end{macrocode}
+% \begin{macro}[internal]{\ekv@parse@more,\ekv@parse@more@}
+% For the expansion control we also need a way to support reinsertion in
+% |\ekvparse|. Since there no user code is executed this is an internal macro.
+% It works in the same way but the argument order exchange is different. Also,
+% since this is only used internally, we know it is safe to omit the trailing
+% |\ekv@empty|.
+% \begin{macrocode}
+ \long\def\ekv@parse@more##1\@gobble##2%
+ {%
+ \expandafter\ekv@parse@more@\ekv@expanded
+ {{\ekv@morekv@loop\ekv@empty##1\ekv@stop\ekv@morekv@done#1}}%
+ }%
+ \long\def\ekv@parse@more@##1\ekv@parse@other##2##3\ekv@mark
+ {\ekv@parse@other{##2}{##3}\ekv@mark##1,}%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]{\ekv@morekv}
+% This is just a simple change of argument order, injecting the new comma
+% separated list after the current |\ekv@set@other| call.
+% \begin{macrocode}
+ \long\def\ekv@morekv##1##2\ekv@set@other##3\ekv@mark
+ {##2\ekv@set@other##3\ekv@mark##1,}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}[internal]
+% {\ekv@morekv@loop,\ekv@morekv@done,\ekv@morekv@wrap}
+% And here is the heavy lifting of the comma replacement. Each list element
+% until the next active comma is read and left as an argument for
+% |\ekv@morekv@wrap|, that will remove the leading |\ekv@empty|. The trick for
+% a fast end of the loop is that |\ekv@morekv@wrap| will read until the next
+% |\ekv@stop|, of which an additional one is put before |\ekv@morekv@done| so
+% that |wrap| will wrap the real end of the list and then |done| removes the
+% excess code.
+% \begin{macrocode}
+ \long\def\ekv@morekv@loop##1#1%
+ {\ekv@morekv@wrap##1\ekv@stop,\ekv@morekv@loop\ekv@empty}%
+ \long\def\ekv@morekv@wrap##1\ekv@stop{\ekv@unexpanded\expandafter{##1}}%
+ \def\ekv@morekv@done\ekv@stop,\ekv@morekv@loop\ekv@empty{}%
+ }
+\begingroup\catcode`\,=13 \@firstofone{\endgroup\ekvmorekv,}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}[internal]
+% {
+% \ekv@def@expansion@rule,\ekv@def@expansion@rule@ea,
+% \ekv@expansion@rule@,\ekv@expansion@csname
+% }
+% All expansion rules share the same basic structure, they do their expansion
+% step and then call |\ekv@expansion@rule@| (this could be done faster by
+% letting each rule build the macro for the next rule in |\csname|, but that
+% would require a more complex argument grabbing structure of the rules, and
+% we'd need to use |\expanded{\unexpanded{\csname ...\endcsname}\expandafter}|
+% or similar to not do the expansion steps of the \val\ inside of |\csname|).
+% As a result of this the \val\ needs to be grabbed twice per expansion step.
+% \begin{macrocode}
+\protected\def\ekv@def@expansion@rule#1#2#3#4%
+ {%
+ \long\expandafter\def\csname ekv@expansion@rule@#1\endcsname##1#2%
+ {#3\ekv@expansion@rule@#4}%
+ }
+\protected\def\ekv@def@expansion@rule@ea#1#2%
+ {\ekv@def@expansion@rule{#1}{#2}\expandafter}
+% \end{macrocode}
+% Rules follow this naming scheme. Note that for an undefined rule an error is
+% thrown and the result of the |\csname| is |\ekv@expansion@rule@|.
+% \begin{macrocode}
+\long\def\ekv@expansion@csname#1\ekv@stop
+ {%
+ ekv@expansion@rule@%
+ \ifcsname ekv@expansion@rule@#1\endcsname
+ #1%
+ \else
+ \ekv@err@undefined@expansion{#1}%
+ \fi
+ }
+% \end{macrocode}
+% This auxiliary macro simply builds the next rule, it is used to start an
+% expansion chain, as well as for each defined or undefined rule.
+% \begin{macrocode}
+\long\def\ekv@expansion@rule@#1#2%
+ {\csname\expandafter\ekv@expansion@csname\string#2\ekv@stop\endcsname{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@expansion@rule@\ekv@mark}
+% The expansion chain is ended by an internal rule that behaves very different
+% from the others. It'll test whether the |r|-rule was used (in which case the
+% third argument will not be empty, and also execute that reinsertion) or grab
+% the code for the next step after the expansion.
+% \begin{macrocode}
+\ekv@exparg
+ {%
+ \long\expandafter
+ \def\csname ekv@expansion@rule@\string\ekv@mark\endcsname
+ #1\ekv@stop#2#3#4#5%
+ }%
+ {%
+ \romannumeral\ekv@exparg{\expandafter\ekv@zero\ekv@ifempty{#3}{#5{#2}{#1}}}%
+ {\ekv@ifempty{#2}{#4{#1}}{\ekv@err@val@no@reinsert{#2}}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekv@expansion@rule@o,\ekv@expansion@rule@e,\ekv@expansion@rule@c,
+% \ekv@expansion@rule@f,\ekv@expansion@rule@V,\ekv@expansion@rule@v,
+% \ekv@expansion@rule@s,\ekv@expansion@rule@b,\ekv@expansion@rule@\r,
+% \ekv@expansion@rule@g,\ekv@expansion@rule@p,\ekv@expansion@rule@P,
+% \ekv@expansion@rule@r,\ekv@expansion@rule@R
+% }
+% All the expansion rules are executed inside a |\csname| construct, so they
+% have to issue an |\endcsname| after the intended expansion took place. I
+% guess the code is pretty straight forward here.
+% \begin{macrocode}
+\ekv@def@expansion@rule@ea{o}{}{\expandafter{#1}}
+\ekv@def@expansion@rule@ea{e}{}{\ekv@expanded{{#1}}}
+\ekv@def@expansion@rule@ea{c}{}{\csname#1\endcsname}
+\ekv@def@expansion@rule@ea{f}{}{\expandafter{\romannumeral`\^^@#1}}
+\ekv@exparg{\ekv@def@expansion@rule{s}{}}{\ekv@strip{\ekv@mark#1}}{}
+\ekv@def@expansion@rule{b}{}{}{{{#1}}}
+\ekv@def@expansion@rule{\string\r}{#2\ekv@stop#3#4}{}{{#1}#2\ekv@stop{#3}{#4r}}
+\ekv@def@expansion@rule@ea{g}{}{\expandafter{\@gobble#1}}
+\ekv@def@expansion@rule{p}{#2}{}{{#2#1}}
+\ekv@def@expansion@rule{P}{#2}{}{{#1#2}}
+% \end{macrocode}
+% The |V| and |v| rules are a bit more complicated. They use some auxiliaries
+% but otherwise should be more or less obvious as well. The |v| one uses some
+% expansion to get a more meaningful error message in case the resulting
+% control sequence would be undefined (without actually using |\csname|, to
+% not accidentally define anything as |\relax|).
+% \begin{macrocode}
+\long\def\ekv@expansion@rule@V#1%
+ {%
+ \ifx\relax#1\ekv@err@erroneous@variable{#1}\ekv@expansion@@clean@V\fi
+ \ekv@expansion@@V{#1}%
+ }
+\ekv@expandedarg{\long\def\ekv@expansion@rule@v#1}%
+ {%
+ \ekv@unexpanded{\ekv@ifdefined{#1}%
+ {\expandafter\ekv@expansion@@V\csname#1\endcsname}}%
+ {%
+ \ekv@unexpanded{\expandafter\ekv@err@erroneous@variable\ekv@expanded}%
+ {{\expandafter\@gobble\string\\#1}}%
+ \ekv@unexpanded{\ekv@expansion@rule@}{}%
+ }%
+ }
+\ekv@exparg{\long\def\ekv@expansion@rule@r#1#2\ekv@stop#3#4}%
+ {\ekv@expansion@rule@v{#1}#2\ekv@stop{#3}{#4r}}
+\ekv@exparg{\long\def\ekv@expansion@rule@R#1#2\ekv@stop#3#4}%
+ {\ekv@expansion@rule@V{#1}#2\ekv@stop{#3}{#4r}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@expansion@@V,\ekv@expansion@@clean@V}
+% The actual |V| evaluation is pretty much the same as in \pkg{expl3}, but we
+% need to put braces around the expansion result, hence branch slightly
+% differently. In general, a macro will temporarily have the meaning of
+% |\relax| if hit by |\noexpand| and hence the \cs[no-index]{ifx} test will
+% result in false (as the meaning isn't the same now), so we can tell
+% whether it would expand directly. Else we assume this is a register type and
+% use |\the|.
+% \begin{macrocode}
+\long\def\ekv@expansion@@V#1%
+ {%
+ \expandafter\ifx\noexpand#1#1%
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ {\expandafter\ekv@expansion@rule@\expandafter{\the#1}}%
+ {\expandafter\ekv@expansion@rule@\expandafter{#1}}%
+ }
+\long\def\ekv@expansion@@clean@V\fi\ekv@expansion@@V#1%
+ {\fi\ekv@expansion@rule@{}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {\ekv@expansion@rule@\key,\ekv@expansion@rule@\ekv@key@after}
+% The |\key|-rule works by calling a nested expansion chain with swapped \key\
+% and \val. Instead of |\ekv@mark| marking the end of the expansion chain
+% we use a different final step called |\ekv@key@after|, that simply checks
+% whether an |r|-rule was executed (\emph{error}) and ends the current
+% expansion step in the outer chain.
+% \begin{macrocode}
+\ekv@def@expansion@rule{\string\key}{#2#3\ekv@stop#4}%
+ {}{{#4}#2\ekv@key@after\ekv@stop{#1}{}{#3}}
+\ekv@exparg{\ekv@def@expansion@rule{\string\ekv@key@after}{\ekv@stop#2#3#4}}%
+ {\ekv@ifempty{#3}{}\ekv@err@key@no@reinsert}
+ {{#2}#4\ekv@stop{#1}}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}[internal]
+% {
+% \ekv@set@pair,\ekv@set@pair@,
+% \ekv@set@pair@relax,\ekv@set@pair@undefined,
+% \ekv@set@pair@u,\ekv@set@pair@u@relax,\ekv@set@pair@no@u
+% }
+% |\ekv@set@pair| gets invoked with the space and brace stripped key-name as
+% its first, the value as the second (delimited by |\ekv@nil|), and the set
+% name as the third argument. It provides tests for the key-macros and
+% everything to be able to throw meaningful error messages if it isn't
+% defined. We have two routes here, one if |\lastnamedcs| is defined and one
+% if it isn't. The big difference is that if it is we can omit a |\csname| and
+% instead just expand |\lastnamedcs| once to get the control sequence.
+% If the macro is defined the value will be space and brace stripped and the
+% key-macro called. Else branch into the error handling provided by
+% |\ekv@set@pair@undefined|.
+% \begin{macrocode}
+\ekv@if@lastnamedcs
+ {%
+ \long\def\ekv@set@pair#1\ekv@mark#2#3\ekv@nil#4%
+ {%
+ \ifcsname#4{#1}\endcsname\expandafter\ekv@set@pair@\lastnamedcs\fi
+ \ekv@set@pair@undefined{#3}{#1}{#2}%
+ \ekv@set@other#4%
+ }
+ \ekv@exparg{\long\def\ekv@set@pair@undefined#1#2#3\ekv@set@other#4}%
+ {%
+ \romannumeral
+ \ekv@exparg
+ {\expandafter\ekv@zero\ekv@ifexp{#3}}%
+ {\ekv@strip{#1}\ekv@expansion@set@pair}%
+ {%
+ \ifcsname#4{}u\endcsname\expandafter\ekv@set@pair@u\lastnamedcs\fi
+ \ekv@set@pair@no@u{#1}{#2}{#3}%
+ }%
+ \ekv@set@other#4%
+ }
+ }
+ {%
+ \long\def\ekv@set@pair#1\ekv@mark#2#3\ekv@nil#4%
+ {%
+ \ifcsname#4{#1}\endcsname
+ \expandafter\ekv@set@pair@\csname#4{#1}\endcsname
+ \fi
+ \ekv@set@pair@undefined{#3}{#1}{#2}%
+ \ekv@set@other#4%
+ }
+ \ekv@exparg{\long\def\ekv@set@pair@undefined#1#2#3\ekv@set@other#4}%
+ {%
+ \romannumeral
+ \ekv@exparg
+ {\expandafter\ekv@zero\ekv@ifexp{#3}}%
+ {\ekv@strip{#1}\ekv@expansion@set@pair}%
+ {%
+ \ifcsname#4{}u\endcsname
+ \expandafter\ekv@set@pair@u\csname#4{}u\endcsname
+ \fi
+ \ekv@set@pair@no@u{#1}{#2}{#3}%
+ }%
+ \ekv@set@other#4%
+ }
+ }
+\ekv@expandedarg{\long\def\ekv@set@pair@#1\fi\ekv@set@pair@undefined#2}%
+ {%
+ \ekv@unexpanded{\fi\ifx#1\relax\ekv@set@pair@relax\fi}%
+ \ekv@unexpanded\expandafter{\ekv@strip{#2}#1\ekv@set@next@other}%
+ }
+\ekv@expandafter{\long\def\ekv@set@pair@relax\fi}%
+ \ekv@strip{#1}#2\ekv@set@next@other
+ {\fi\ekv@set@pair@undefined{#1}}
+\ekv@expandedarg{\long\def\ekv@set@pair@u#1\fi\ekv@set@pair@no@u#2}%
+ {%
+ \ekv@unexpanded
+ {%
+ \fi
+ \ifx\relax#1%
+ \ekv@set@pair@u@relax
+ \fi
+ }%
+ \ekv@unexpanded\expandafter{\ekv@strip{#2}#1}%
+ }
+\ekv@expandafter{\long\def\ekv@set@pair@u@relax\fi}\ekv@strip{\ekv@mark#1}#2%
+ {\fi\ekv@set@pair@no@u.}
+\long\def\ekv@set@pair@no@u#1#2#3\ekv@set@other#4%
+ {%
+ \ekv@ifdefined{#4{#2}N}%
+ \ekv@err@noarg
+ \ekv@err@unknown
+ #4{#2}{#3}%
+ \ekv@set@other#4%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekv@set@key,\ekv@set@key@,
+% \ekv@set@key@relax,\ekv@set@key@undefined,
+% \ekv@set@key@u,\ekv@set@key@u@relax,\ekv@set@key@no@u
+% }
+% Analogous to |\ekv@set@pair|, |\ekv@set@key| builds the \Nkey-macro and
+% provides an error-branch. It'll test whether the key-macro is defined and if
+% so call it, else there might be some \expnotation, or errors are thrown.
+% \begin{macrocode}
+\ekv@if@lastnamedcs
+ {%
+ \long\def\ekv@set@key#1\ekv@mark#2#3%
+ {%
+ \ifcsname#3{#1}N\endcsname\expandafter\ekv@set@key@\lastnamedcs\fi
+ \ekv@set@key@undefined{#1}{#2}%
+ \ekv@set@other#3%
+ }
+ \ekv@exparg{\long\def\ekv@set@key@undefined#1#2\ekv@set@other#3}%
+ {%
+ \ekv@ifexp{#2}%
+ \ekv@expansion@set@key
+ {%
+ \ifcsname#3{}uN\endcsname\expandafter\ekv@set@key@u\lastnamedcs\fi
+ \ekv@set@key@no@u{#1}{#2}%
+ }%
+ \ekv@set@other#3%
+ }
+ }
+ {%
+ \long\def\ekv@set@key#1\ekv@mark#2#3%
+ {%
+ \ifcsname#3{#1}N\endcsname
+ \expandafter\ekv@set@key@\csname#3{#1}N\endcsname
+ \fi
+ \ekv@set@key@undefined{#1}{#2}%
+ \ekv@set@other#3%
+ }
+ \ekv@exparg{\long\def\ekv@set@key@undefined#1#2\ekv@set@other#3}%
+ {%
+ \ekv@ifexp{#2}%
+ \ekv@expansion@set@key
+ {%
+ \ifcsname#3{}uN\endcsname
+ \expandafter\ekv@set@key@u\csname#3{}uN\endcsname
+ \fi
+ \ekv@set@key@no@u{#1}{#2}%
+ }%
+ \ekv@set@other#3%
+ }
+ }
+\long\def\ekv@set@key@#1\fi\ekv@set@key@undefined
+ {\fi\ifx#1\relax\ekv@set@key@relax\fi#1\ekv@set@next@other}
+\long\def\ekv@set@key@relax\fi#1\ekv@set@next@other{\fi\ekv@set@key@undefined}
+\long\def\ekv@set@key@u#1\fi\ekv@set@key@no@u
+ {\fi\ifx\relax#1\ekv@set@key@u@relax\fi#1}
+\def\ekv@set@key@u@relax\fi#1{\fi\ekv@set@key@no@u}
+\long\def\ekv@set@key@no@u#1#2\ekv@set@other#3%
+ {%
+ \ekv@ifdefined{#3{#1}}%
+ \ekv@err@reqval
+ \ekv@err@unknown
+ #3{#1}{#2}%
+ \ekv@set@other#3%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekv@expansion@set@key,\ekv@expansion@set@key@,
+% \ekv@expansion@set@pair,\ekv@expansion@set@pair@
+% }
+% These macros just pick up the pieces of the \expansion\ prefix as separate
+% arguments. The \val\ for the \expansion-rules is left empty. Once expansion
+% is done we loop back to |\ekv@set@key|, that'll pick up the processed \key\
+% and set it if it's now defined. The same trick is used for a \kv\ pair.
+% \begin{macrocode}
+\long\def\ekv@expansion@set@key#1#2#3%
+ {%
+ \ekv@expansion@rule@{#2}#1\ekv@mark\ekv@stop{}{}\ekvmorekv
+ \ekv@expansion@set@key@
+ }
+\long\def\ekv@expansion@set@key@#1#2\ekv@set@other#3%
+ {\expandafter\ekv@set@key\detokenize{#2}\ekv@mark{#2}#3}
+\long\def\ekv@expansion@set@pair#1#2#3#4%
+ {%
+ \ekv@expansion@rule@{#1}#2\ekv@mark\ekv@stop{#3}{}\ekvmorekv
+ \ekv@expansion@set@pair@
+ }
+\long\def\ekv@expansion@set@pair@#1#2\ekv@set@other#3%
+ {\expandafter\ekv@set@pair\detokenize{#1}\ekv@mark{#1}\ekv@mark{#2}\ekv@nil#3}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekv@expansion@parse@key,\ekv@expansion@parse@key@,
+% \ekv@expansion@parse@pair,\ekv@expansion@parse@pair@
+% }
+% In |\ekvparse| we don't need to resort to looping back into |\ekv@parse@key|
+% or the like, we can simply leave the result via |\ekv@unexpanded|.
+% \begin{macrocode}
+\long\def\ekv@expansion@parse@key#1#2#3#4%
+ {%
+ \ekv@expansion@rule@{#3}#2\ekv@mark\ekv@stop{}{}\ekv@parse@more
+ \ekv@expansion@parse@key@\@gobble{#1}%
+ }
+\long\def\ekv@expansion@parse@key@#1#2\@gobble#3{\ekv@unexpanded{#3{#2}}}
+\long\def\ekv@expansion@parse@pair#1#2#3#4#5%
+ {%
+ \ekv@expansion@rule@{#1}#3\ekv@mark\ekv@stop{#4}{}\ekv@parse@more
+ \ekv@expansion@parse@pair@\@gobble{#2}%
+ }
+\long\def\ekv@expansion@parse@pair@#1#2\@gobble#3{\ekv@unexpanded{#3{#1}{#2}}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvsetdef}
+% Provide a macro to define a shorthand to use |\ekvset| on a specified \set.
+% To gain the maximum speed |\ekvset| is expanded twice by
+% |\ekv@exparg| so that during runtime the macro storing the set name
+% is already built and one |\expandafter| doesn't have to be used.
+% \begin{macrocode}
+\ekv@expargtwice{\protected\def\ekvsetdef#1#2}%
+ {%
+ \romannumeral
+ \ekv@exparg{\ekv@zero\ekv@exparg{\def#1##1}}%
+ {\ekvset{#2}{##1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvsetSneakeddef,\ekvsetdefSneaked}
+% And do the same for |\ekvsetSneaked| in the two possible ways, with a fixed
+% sneaked argument and with a flexible one.
+% \begin{macrocode}
+\ekv@expargtwice{\protected\def\ekvsetSneakeddef#1#2}%
+ {%
+ \romannumeral
+ \ekv@exparg{\ekv@zero\ekv@exparg{\long\def#1##1##2}}%
+ {\ekvsetSneaked{#2}{##1}{##2}}%
+ }
+\ekv@expargtwice{\protected\def\ekvsetdefSneaked#1#2#3}%
+ {%
+ \romannumeral
+ \ekv@exparg{\ekv@zero\ekv@exparg{\long\def#1##1}}%
+ {\ekvsetSneaked{#2}{#3}{##1}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@alignsafe,\ekv@endalignsafe}
+% These macros protect the usage of ampersands inside of alignment contexts.
+% \begin{macrocode}
+\begingroup
+\catcode`\^^@=2
+\@firstofone{\endgroup
+ \def\ekv@alignsafe{\romannumeral\iffalse{\fi`^^@ }
+}
+\def\ekv@endalignsafe{\ifnum`{=\ekv@zero}\fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvoptarg,\ekvoptargTF}
+% Provide macros to expandably collect an optional argument in brackets. The
+% macros here are pretty simple in nature compared to \pkg{xparse}'s
+% possibilities (they don't care for nested bracket levels).
+%
+% We start with a temporary definition to pre-expand |\ekv@alignsafe| (will be
+% |#1|) and |\ekv@endalignsafe| (will be |#2|). As |\ekv@alignsafe| starts with
+% a |\romannumeral| we use that to also control the number of steps needed
+% instead of adding another |\romannumeral|. For this we have to remove the
+% space token from the end of |\ekv@alignsafe|'s definition.
+% \begin{macrocode}
+\begingroup
+\def\ekvoptarg#1#2{%
+\endgroup
+% \end{macrocode}
+% The real definition starts an expansion context and afterwards grabs the
+% arguments. |#1| will be the next step, |#2| the default value, and |#3| might
+% be an opening bracket, or the mandatory argument. We check for the opening
+% bracket, if it is found grab the optional argument, else leave |#1{#2}| in the
+% input stream after ending the expansion context.
+% \begin{macrocode}
+\def\ekvoptarg{#1\ekv@optarg@a}
+\long\def\ekv@optarg@a##1##2##3%
+ {%
+ \ekv@optarg@if\ekv@mark##3\ekv@mark\ekv@optarg@b\ekv@mark[\ekv@mark
+ #2%
+ \@firstofone{ ##1}{##2}{##3}%
+ }%
+% \end{macrocode}
+% The other variant of this will do roughly the same. Here, |#1| will be the
+% next step if an optional argument is found, |#2| the next step else, and |#3|
+% might be the opening bracket or mandatory argument.
+% \begin{macrocode}
+\def\ekvoptargTF{#1\ekv@optargTF@a}
+\long\def\ekv@optargTF@a##1##2##3%
+ {%
+ \ekv@optarg@if\ekv@mark##3\ekv@mark\ekv@optargTF@b{##1}\ekv@mark[\ekv@mark
+ #2%
+ \@firstofone{ ##2}{##3}%
+ }
+% \end{macrocode}
+% The two macros to grab the optional argument have to remove the remainder of
+% the test and the wrong next step as well as grabbing the argument.
+% \begin{macrocode}
+\long\def\ekv@optarg@b\ekv@mark[\ekv@mark\ifnum`##1\fi\@firstofone##2##3##4##5]%
+ {#2##2{##5}}
+\long\def\ekv@optargTF@b
+ ##1\ekv@mark[\ekv@mark\ifnum`##2\fi\@firstofone##3##4##5]%
+ {#2 ##1{##5}}
+}
+% \end{macrocode}
+% Do the definitions and add the test macro. We use |\ekv@strip| to remove the
+% trailing space from the definition of |\ekv@alignsafe|.
+% \begin{macrocode}
+\ekv@exparg
+ {%
+ \expandafter\ekv@strip\expandafter
+ {\expandafter\ekv@mark\ekv@alignsafe}%
+ \ekvoptarg
+ }%
+ \ekv@endalignsafe
+\long\def\ekv@optarg@if#1\ekv@mark[\ekv@mark{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@ifstar}
+% Internal helper to get an expandable |ifstar| implementation. This is pretty
+% straight forward.
+% \begin{macrocode}
+\long\def\ekv@ifstar#1#2#3%
+ {%
+ \if*\string#3%
+ \ekv@fi@firstoftwo
+ \fi
+ \@secondoftwo
+ {#1}%
+ {#2{#3}}%
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ekvcompile}
+% The idea of key-compilation is to preparse some list into a form that sets
+% that list very fast (but is frozen), in our case this means we do everything
+% except expanding the key's code. There are two levels of expansion possible,
+% either expand until the key-macro or expand the key-macro once as well (the
+% latter might break if the key-macros take additional arguments). The
+% following supports both by using a starred form.
+% \begin{macrocode}
+\protected\long\def\ekvcompile
+ {%
+ \ekv@alignsafe
+ \ekv@ifstar{\ekv@compile{}}{\ekv@compile{\expandafter\expandafter}}%
+ }
+% \end{macrocode}
+% \begin{macro}[internal]
+% {\ekv@compile,\ekv@compile@,\ekv@compile@key,\ekv@compile@pair}
+% |\ekvparse| starts with an |\unexpanded| that we don't need. Hence we use a
+% temporary definition to remove that. Else this is pretty straight forward.
+% There is a minor indirection (the parsing step of |\ekv@compile|) which is
+% necessary to grab any argument specification.
+% \begin{macrocode}
+\def\ekv@compile#1#2#3#{\ekv@compile@{#1}{#2#3}}
+\def\ekv@compile@#1#2#3{#2#3}
+\ekv@exparg{\protected\long\def\ekv@compile@#1#2#3#4}%
+ {%
+ \expandafter\ekv@expanded\expandafter
+ {%
+ \romannumeral\ekv@expargtwice{\ekv@zero\def\ekv@unexpanded{#2}}%
+ {%
+ \expandafter\ekv@compile@
+ \ekvparse
+ {\ekv@compile@key{#1}{#3}}%
+ {\ekv@compile@pair{#1}{#3}}%
+ {#4}%
+ }%
+ }%
+ \ekv@endalignsafe
+ }
+% \end{macrocode}
+% The compilation step just checks whether the keys are defined and leaves
+% their code (maybe expanded once).
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@compile@key#1#2#3}%
+ {%
+ \ekvifdefinedNoVal{#2}{#3}%
+ {\ekv@unexpanded#1\expandafter{\csname\ekv@name{#2}{#3}N\endcsname}}%
+ {%
+ \ekv@ifdefined{\ekv@name{#2}{}uN}
+ {%
+ \ekv@unexpanded#1\expandafter
+ {%
+ \csname\ekv@name{#2}{}uN\expandafter\endcsname
+ \expandafter{\detokenize{#3}}{#3}%
+ }%
+ }%
+ {%
+ \ekvifdefined{#2}{#3}%
+ {\ekv@err{missing value for `#3' in set `#2'}}%
+ {\ekv@err{unknown key `#3' in set `#2'}}%
+ }%
+ }%
+ }
+\ekv@exparg{\long\def\ekv@compile@pair#1#2#3#4}%
+ {%
+ \ekvifdefined{#2}{#3}%
+ {\ekv@unexpanded#1\expandafter{\csname\ekv@name{#2}{#3}\endcsname{#4}}}%
+ {%
+ \ekv@ifdefined{\ekv@name{#2}{}u}%
+ {%
+ \ekv@unexpanded#1\expandafter
+ {%
+ \csname\ekv@name{#2}{}u\ekv@expanded{\endcsname
+ {\ekv@unexpanded{#4}}{\detokenize{#3}}}{#3}%
+ }%
+ }%
+ {%
+ \ekvifdefinedNoVal{#2}{#3}%
+ {\ekv@err{unwanted value for `#3' in set `#2'}}%
+ {\ekv@err{unknown key `#3' in set `#2'}}%
+ }%
+ }%
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ekverr}
+% \begin{macro}[internal]{\ekv@err@collect,\ekv@err@cleanup}
+% Since |\ekvset| is fully expandable as long as the code of the keys is (which
+% is unlikely) we want to somehow throw expandable errors, in our case via
+% a runaway argument (to my knowledge the first version of this method was
+% implemented by Jean-François Burnol, many thanks to him). The first step is to
+% ensure that the second argument (which might contain user input) doesn't
+% contain tokens we use as delimiters (in this case |\par|), this will be done
+% by the front facing macro |\ekverr|. But first we set some other things up.
+%
+% We use a temporary definition for |\ekverr| to get multiple consecutive
+% spaces. Then we set up the macro that will collect the error and the macro
+% that will throw the error. The latter will have an unreasonable long name.
+% This way we can convey more information. Though the information in the macro
+% name is static and has to be somewhat general to fit every occurence. The
+% important bit is that the long named macro has a delimited argument and is
+% short which will throw the error at the |\par| at the end of
+% |\ekv@err@collect|. This macro has the drawback that it will only print nicely
+% if the |\newlinechar| is |^^J|.
+% \begin{macrocode}
+\def\ekv@err@cleanup\par{}
+\def\ekv@err@collect#1%
+ {%
+ \def\ekv@err@collect##1\par##2%
+ {%
+ \expandafter
+ \ekv@err@cleanup
+ #1! ##2 Error: ##1\par
+ }%
+ \def#1##1\thanks@jfbu{}%
+ }
+\def\ekverr{ }
+\expandafter\ekv@err@collect\csname <an-expandable-macro>^^J%
+ completed due to above exception. \ekverr If the error^^J%
+ summary is \ekverr not comprehensible \ekverr see the package^^J%
+ documentation.^^J%
+ I will try to recover now. \ekverr If you're in inter-^^J%
+ active mode hit <return> \ekverr at the ? prompt and I^^J%
+ continue hoping recovery\endcsname
+% \end{macrocode}
+% \begin{macrocode}
+\long\def\ekverr#1#2{\expandafter\ekv@err@collect\detokenize{#2}\par{#1}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[internal]{\ekv@err,\ekv@errm}
+% We define shorthands to throw errors in \expkv.
+% \begin{macrocode}
+\ekv@exparg{\long\def\ekv@err#1}{\ekverr{expkv}{#1}}
+\protected\long\def\ekv@errm#1{\errmessage{expkv Error: #1}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[internal]
+% {
+% \ekv@err@common,\ekv@err@common@,
+% \ekv@err@unknown,\ekv@err@noarg,\ekv@err@reqval,
+% \ekv@err@undefined@expansion
+% }
+% Now we can use |\ekv@err| to set up some error messages so that we can later
+% use those instead of the full strings.
+% \begin{macrocode}
+\long\def\ekv@err@common #1#2{\expandafter\ekv@err@common@\string#2{#1}}
+\ekv@exparg{\long\def\ekv@err@common@#1`#2' #3.#4#5}%
+ {\ekv@err{#4 `#5' in set `#2'}}
+\ekv@exparg{\long\def\ekv@err@unknown#1#2}{\ekv@err@common{unknown key}{#1}}
+\ekv@exparg{\long\def\ekv@err@noarg#1#2}
+ {\ekv@err@common{unwanted value for}{#1}}
+\ekv@exparg{\long\def\ekv@err@reqval#1#2}%
+ {\ekv@err@common{missing value for}{#1}}
+\ekv@exparg{\long\def\ekv@err@redirect@kv@notfound#1#2#3\ekv@stop}%
+ {\ekv@err{no key `#2' in sets #3}}
+\ekv@exparg{\def\ekv@err@redirect@k@notfound#1#2\ekv@stop}%
+ {\ekv@err{no NoVal key `#1' in sets #2}}
+\ekv@exparg{\def\ekv@err@undefined@expansion#1\fi}%
+ {\expandafter\fi\ekv@err{Undefined expansion rule `#1'}}%
+\ekv@exparg{\def\ekv@err@erroneous@variable#1}%
+ {\ekv@err{Erroneous variable `#1' used}}
+\ekv@exparg{\def\ekv@err@key@no@reinsert}%
+ {\ekv@err{Reinsertion in \key expansion forbidden}}
+\ekv@exparg{\def\ekv@err@val@no@reinsert#1}%
+ {\ekv@err{Reinsertion with key `#1' forbidden}}
+% \end{macrocode}
+% \end{macro}
+%
+% Now everything that's left is to reset the category code of |@|.
+% \begin{macrocode}
+\catcode`\@=\ekv@tmp
+% \end{macrocode}
+%
+% \gobbledocstriptag
+%</tex>
+%^^A=<<
diff --git a/macros/generic/expkv-bundle/impatient.tex b/macros/generic/expkv-bundle/impatient.tex
new file mode 100644
index 0000000000..b3d62b07fa
--- /dev/null
+++ b/macros/generic/expkv-bundle/impatient.tex
@@ -0,0 +1,56 @@
+\addsec{\expkvbundle\ for the Impatient}
+
+This section gives a very brief and non-exhaustive overview over the contents of
+the \expkvbundle. For more information (and more functionality) you'll have to
+read the sections of the packages you're interested in.
+
+\expkvbundle\ supports expansion control in \kv\ lists. The corresponding
+syntax and features are documented in \autoref{sec:expkv:expansion}.
+
+The following user interface macros (and more) are available in the different
+packages of the bundle:
+\paragraph{Defining keys}
+\begin{itemize}
+ \item \cs[no-index]{ekvdefinekeys}\marg{set}\texttt{\kvarg}
+ defines the keys in the \kv\ list, many common key types are available
+ (\autoref{sec:d:macros} and for the types \autoref{sec:d:types}).
+ \item \cs[no-index]{ekvdef}\marg{set}\marg{key}\marg{code}
+ defines the behaviour of a \Vkey\ (\autoref{sec:expkv:setup}).
+ \item \cs[no-index]{ekvdefNoVal}\marg{set}\marg{key}\marg{code}
+ defines the behaviour of a \Nkey\ (\autoref{sec:expkv:setup}).
+\end{itemize}
+\paragraph{Parsing \kv\ lists}
+\begin{itemize}
+ \item \cs[no-index]{ekvset}\marg{set}\texttt{\kvarg}
+ sets defined keys (\autoref{sec:expkv:set}).
+ \item \cs[no-index]{ekvparse}\marg{k-code}\marg{kv-code}\texttt{\kvarg}
+ parses the \kv\ list and runs \meta{k-code} or \meta{kv-code} on the
+ elements (\autoref{sec:expkv:parse}).
+\end{itemize}
+\paragraph{Defining expandable \kv\ macros}
+\begin{itemize}
+ \item \cs[no-index]{ekvcSplit}\meta{cs}\texttt{\kvarg}\marg{code}
+ defines a fully expandable macro with the keys in the \kv\ list,
+ values are accessed by |#1| to |#9| (\autoref{sec:c:split}).
+ \item \cs[no-index]{ekvcHash}\meta{cs}\texttt{\kvarg}\marg{code}
+ defines a fully expandable macro with the keys in the \kv\ list,
+ values are accessed using \cs[no-index]{ekvcValue}\hskip0pt\marg{key}|{#1}|
+ (\autoref{sec:c:hash}).
+ \item \cs[no-index]{ekvcSecondaryKeys}\meta{cs}\texttt{\kvarg}
+ defines additional keys of predefined types for a \meta{cs} defined with
+ \cs[no-index]{ekvcSplit} or \cs[no-index]{ekvcHash}
+ (\autoref{sec:c:secondary} and for the types
+ \autoref{sec:c:secondarytypes}).
+\end{itemize}
+\paragraph{Parsing options} (\autoref{sec:o:macros})
+\begin{itemize}
+ \item \cs[no-index]{ekvoProcessOptions}\marg{set}
+ processes the global options, and the options given to the current and
+ all future calls of the package.
+ \item \cs[no-index]{ekvoProcessGlobalOptions}\marg{set}
+ processes the global options.
+ \item \cs[no-index]{ekvoProcessLocalOptions}\marg{set}
+ processes the local options of a package or class.
+ \item \cs[no-index]{ekvoProcessFutureOptions}\marg{set}
+ processes the options of future calls of the package.
+\end{itemize}
diff --git a/macros/generic/expkv-bundle/introduction.tex b/macros/generic/expkv-bundle/introduction.tex
new file mode 100644
index 0000000000..de52d9e584
--- /dev/null
+++ b/macros/generic/expkv-bundle/introduction.tex
@@ -0,0 +1,115 @@
+\addsec{Introduction}
+%The name \expkv\ stands for \emph{exp}andable \emph{k}ey-\emph{v}alue and shall
+%be pronounced \enquote{axe(b) kay vee}.
+
+This bundle consists of different packages the base being \expkv. Most of these
+packages are available for \hologo{plainTeX}, \LaTeXe, and \hologo{ConTeXt}. For
+stylistic reasons the package names are printed as
+\expkvLogoFormat{\textit{$\langle$pkg$\rangle$}}, but the files are named
+\texttt{expkv-\meta{pkg}} (CTAN-rules don't allow \string| in names), so in
+order to load \expkvc\ in \LaTeXe\ you should use
+\begin{enverb}[no-tcb]
+ \usepackage{expkv-cs}
+\end{enverb}
+Each section describing a package of this bundle has next to its heading the
+formats in which they work printed flush right. If more than a single format is
+supported by a package the functionality is defined by the \hologo{plainTeX}
+variant and the other variants only load the generic code in a way suitable for
+the format.
+
+\addssec{Terminology}
+This documentation uses a few terms which always mean specific things:
+\begin{description}
+ \item[\kv\ pair]
+ is one element in a comma separated list which contains at least one equals
+ sign \emph{not} contained in any braces, and the first such equals sign is
+ the separator between the \key\ (with an optional \expansion\ prefix) and
+ the \val.
+ \item[\key]
+ means the entire left-hand side of a \kv\ pair with an optional \expansion\
+ prefix stripped, or if =\val\ is omitted the complete list element, again
+ with an \expansion\ prefix stripped.
+ \item[\key-name]
+ synonymous to \key.
+ \item[\Vkey]
+ describes a \key\ in a \kv\ pair.
+ \item[\Nkey]
+ describes a \key\ for which =\val\ was or should be omitted.
+ \item[\val]
+ is the right-hand side of a \kv\ pair.
+ \item[\kv\ list]
+ is a comma separated list containing \kv\ pairs and \Nkey{}s (each possibly
+ with an \expansion\ prefix).
+ \item[\kvarg]
+ an argument that should get a \kv\ list.
+ \item[\expansion\ prefix]
+ an optional prefix in front of \key\ to specify \expansion-rules (see
+ \autoref{sec:expkv:expansion}), that prefix consists of the \expansion-rules
+ followed by a colon immediately followed by a space.
+ \item[\expansion]
+ a list of tokens specifying expansion steps for \key\ and \val.
+ \item[\expansion-rule]
+ a single expansion step in the \expansion-rules.
+ \item[\expansion-rules]
+ synonymous to \expansion.
+ \item[\expnotation]
+ the notation of \expansion-rules in form of the \expansion\ prefix.
+ \item[key-code]
+ the code that is executed for a given \key.
+ \item[key-macro]
+ the internal macro that stores the key-code.
+\end{description}
+
+Though not really terminology but more typographic representation I want to
+highlight a distinction between two different types of code listings in this
+documentation. I use the following looks to show a code example and its results:
+\begin{enverb}[same-line=0.6]
+ \newcommand*\foo{This is an example.}
+ \foo
+\end{enverb}
+And this is how a syntax summary or a syntax example looks like (this is more
+abstract than an example and contains short meta-descriptions of inputs):
+\begin{syntaxexample}
+ \cs[no-index]{function}\marg{syntax}
+\end{syntaxexample}
+Inside such syntax summaries the following rules usually apply (and \meta{arg}
+would be the meta description here):
+\begin{description}[font=\small\ttfamily]
+ \item[\marg{arg}]
+ a mandatory argument is shown in braces
+ \item[\meta{arg}]
+ a mandatory argument that should be a single token is shown without
+ additional parentheses/braces/brackets
+ \item[\oarg{arg}]
+ an optional argument is shown in brackets (and should be input with
+ brackets)
+ \item[\meta{*}]
+ an optional star is shown like this
+\end{description}
+If other types of arguments are displayed the documentation will explain what
+they mean in this particular place.
+
+\addssec{Category Codes}
+Supporting different category codes of a single character code makes the
+programmer's life harder in \TeX, but there are valid reasons to make some
+active, or letter. Because of this the packages in this bundle support different
+category codes for specific syntax relevant characters (unless otherwise
+documented). This doesn't mean that \expkv\ changes any category codes, only
+that parsing is correct \emph{if} they are changed later (the codes listed
+assume standard category codes of \hologo{plainTeX} and \LaTeXe\ apply while
+\expkv\ is loaded). The supported tokens are:
+\begin{description}
+ \item[=] \tkn{=}{12} and \tkn{=}{13}
+ \item[,] \tkn{,}{12} and \tkn{,}{13}
+ \item[:] (for the \expnotation) \tkn{:}{11}, \tkn{:}{12}, and \tkn{:}{13}
+ \item[*] (for starred macros) \tkn{*}{3}, \tkn{*}{4}, \tkn{*}{6}, \tkn{*}{7},
+ \tkn{*}{8}, \tkn{*}{11}, \tkn{*}{12}, and \tkn{*}{13}
+ \item[{[}] (for |\ekvoptarg|) only \tkn{[}{12}
+ \item[{]}] (for |\ekvoptarg|) only \tkn{]}{12}
+\end{description}
+
+\addssec{Bugs}
+Just like \pkg{keyval}, \expkv\ is bug free. But if you find \pmso{bugs}hidden
+features\footnote{Thanks, David!} you can tell me about them either via mail
+(see the first page) or directly on GitLab if you have an account there:
+\url{https://gitlab.com/islandoftex/texmf/expkv-bundle}
diff --git a/macros/generic/expkv-bundle/pkg-cs.tex b/macros/generic/expkv-bundle/pkg-cs.tex
new file mode 100644
index 0000000000..850b9af620
--- /dev/null
+++ b/macros/generic/expkv-bundle/pkg-cs.tex
@@ -0,0 +1,937 @@
+\genericekv\expkvc{-cs}
+
+\expkvc\ aids in creating fully expandable macros that take a \kv\ argument. It
+implements somewhat efficient solutions to expandable \kv\ parsing without the
+user having to worry too much about the details.
+
+The package supports two main approaches for this. The first is splitting the
+keys up into individual arguments, the second preparses the \kv\ list into a
+single argument in which accessing the value of individual keys is fast. The
+behaviour of the second type is similar to a hash table, so we call that variant
+|Hash|, the first type is called |Split|. Both these variants support a number
+of so called \emph{primary keys} (a primary key matches an argument, roughly
+speaking).
+
+In addition to these methods there is a structured way to define additional keys
+which might build upon the primary keys but not directly relate to an argument.
+These keys are called \emph{secondary keys}. Primary and secondary keys belong
+to a specific macro (the macro name serves as the \emph{set}).
+
+A word of advice you should consider: Macros defined with \expkvc\ are simple to
+create, and there might be good use cases for them (for instance since they
+don't work by assignments but only by argument forwarding logic they have no
+issues with implicit or explicit groups whatsoever). But they don't scale as
+well as established \kv\ interfaces (think of the idiomatic key definitions with
+\pkg{keyval}, or \pkg{l3keys}, or \expkv\ with or without \expkvd), and they are
+slower than idiomatic key definitions in packages with fast \kv\ parsing.
+
+
+\subsection{Defining Macros and Primary Keys}
+
+All macros defined with \expkvc\ have to be previously undefined (or have the
+|\meaning| of |\relax|). There is no way to automatically undefine keys once
+they are set up -- so to make sure there are no conflicts only new definitions
+are allowed. The \emph{set} name (as used by \cs[no-index]{ekvset}) will be
+\cs[no-index]{string}\cs[no-index]{\meta{macro}}.
+
+
+\subsubsection{Primary Keys\label{sec:c:primary}}
+
+The notion of primary keys needs a bit of explanation, or better, the input
+syntax for the argument \meta{primary keys} in the following explanations. The
+\meta{primary keys} argument should be a \kv\ list in which each \key\ will be
+one primary key and \val\ the initial value of said \key\ (and that value is
+mandatory, even if you leave it blank that's fine, but you have to explicitly
+state it). By default all keys are defined short, but you can define |\long|
+keys by prefixing \key\ with |long| (\emph{e.g.},
+|long name=Jonathan P. Spratte| to define a |\long| key called |name|). Due to
+some internal implementations it's worth noting that |\long| keys are a
+microscopic grain faster. The \meta{cs} will only be defined |\long| if at least
+one of the keys was |\long|. For obvious reasons there is no interface in place
+to define something as |\protected|.
+
+To allow keys to start with the word |long| even if you don't want them to be
+|\long| you can also prefix them with |short|. The first found prefix of the two
+will stop the parsing for prefixes and what remains becomes the \key.
+
+These rules culminate in the following:
+
+\begin{enverb}[no-tcb]
+ \ekvcSplit\foo
+ {
+ long short = abc\par
+ ,short long = def
+ }
+ {#1#2}
+\end{enverb}
+will define a macro |\foo| that knows two primary keys, |short| which is defined
+|\long| (so will accept explicit |\par| tokens inside its value at use time),
+and |long| which doesn't accept explicit |\par| tokens (leading to a low level
+\TeX\ error). The description of |\ekvcSplit| follows shortly.
+
+There is one exception to the rule that each \key\ in \meta{primary keys} needs
+to get a value: If you include a key named |...| without a value this will be a
+primary key in which every unknown key will be collected -- and \meta{cs} will
+be defined |\long|. The unknown keys will be stored in a way that \emph{most}
+\kv\ parsers will parse them correctly (but this is no general guarantee, for
+instance \pkg{pgfkeys} can accidentally strip multiple sets of braces at the
+wrong moment). See some examples in \autoref{sec:c:unknown}.
+
+At the moment \expkvc\ doesn't require any internal keys, but I can't foresee
+whether this will be the case in the future as well, as it might turn out that
+some features I deem useful can't be implemented without such internal keys.
+Because of this, please don't use key names starting with "EKVC|" as that
+should be the private name space.
+
+
+\subsubsection{Split\label{sec:c:split}}
+
+The split variants will provide the key values as separate arguments. This
+limits the number of keys for which this is truly useful.
+
+\begin{function}{\ekvcSplit}
+ \begin{syntax}
+ \cs{ekvcSplit}\meta{cs}\marg{primary keys}\marg{definition}
+ \end{syntax}
+ This defines \meta{cs} to be a macro taking one mandatory argument which
+ should contain a \kv\ list. The \meta{primary keys} will be defined for this
+ macro (see \autoref{sec:c:primary}). The \meta{definition} is the code that
+ will be executed. You can access the \val\ of a \key\ by using a macro
+ parameter from |#1| to |#9|. The order of the macro parameters will be the
+ order provided in the \meta{primary keys} list (so |#1| is the \val\ of the
+ \key\ defined first). With \cs{ekvcSplit} you can define macros using at most
+ nine primary keys.
+\end{function}
+\begin{example}{Simple macro with \cs[no-index]{ekvcSplit}}
+ The following defines a macro |\foo| that takes the keys |a| and |b|
+ and outputs their values in a textual form:
+ \begin{enverb}
+ \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
+ \foo{}
+ \foo{b=e}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvcSplitAndForward}
+ \begin{syntax}
+ \cs{ekvcSplitAndForward}\meta{cs}\marg{after}\marg{primary keys}
+ \end{syntax}
+ This defines \meta{cs} to be a macro taking one mandatory argument which
+ should contain a \kv\ list. You can use as many primary keys as you want with
+ this. The primary keys will be forwarded to \meta{after} as braced arguments
+ (as many as necessary for your primary keys). The order of the braced
+ arguments will be the order of your primary key definitions. In \meta{after}
+ you can use just a single control sequence, or some arbitrary stuff which will
+ be left in the input stream before your braced values (with one set of braces
+ stripped from \meta{after}), so both of the following would be fine:
+ \begin{enverb}[no-tcb]
+ \ekvcSplitAndForward\foo\foo@aux{keyA = A, keyB = B}
+ \ekvcSplitAndForward\foo{\foo@aux{more args}}{keyA = A, keyB = B}
+ \end{enverb}
+\end{function}
+\noindent
+In the first case |\foo@aux| should take at least two arguments (|keyA| and
+|keyB|), in the second case at least three (|more args|, |keyA|, and |keyB|).
+
+\begin{function}{\ekvcSplitAndUse}
+ \begin{syntax}
+ \cs{ekvcSplitAndUse}\meta{cs}\marg{primary keys}
+ \end{syntax}
+ This will roughly do the same as \cs{ekvcSplitAndForward}, but instead of
+ specifying what will be used after splitting the keys, \meta{cs} will use what
+ follows the \kv\ list. So its syntax will be
+\end{function}
+\begin{quote}
+ \ttfamily
+ \meta{cs}\kvarg\marg{after}
+\end{quote}
+and the code in |after| should expect at least as many arguments as the number
+of keys defined for \meta{cs}.
+
+
+\subsubsection{Hash\label{sec:c:hash}}
+
+The hash variants will provide the key values as a single argument in which you
+can access specific values using a special macro. The implementation might be
+more convenient and scale better, \emph{but} it is slower (for a rudimentary
+macro with a single key benchmarking was almost 1.7~times slower, the root of
+which being the key access with \cs{ekvcValue}, not the parsing, and for a key
+access using \cs{ekvcValueFast} it was still about 1.2~times slower). Still to
+be future proof, considering the hash variants is a good idea, and to get best
+performance but less maintainable code you can resort to the split approach.
+
+\begin{function}{\ekvcHash}
+ \begin{syntax}
+ \cs{ekvcHash}\meta{cs}\marg{primary keys}\marg{definition}
+ \end{syntax}
+ This defines \meta{cs} to be a macro taking one mandatory argument which
+ should contain a \kv\ list. You can use as many primary keys as you want. The
+ primary keys will be forwarded as a single argument containing every key to
+ the underlying macro. The underlying macro is defined as \meta{definition}, in
+ which you can access the \val\ of a \key\ by using
+ \cs{ekvcValue}\marg{key}|{#1}| (or similar).
+\end{function}
+\begin{example}{Simple macro with \cs[no-index]{ekvcHash}}
+ This defines an equivalent macro to the |\foo| defined with \cs{ekvcSplit}
+ earlier:
+ \begin{enverb}
+ \ekvcHash\foo{a=a,b=b}{a is \ekvcValue{a}{#1}.\par
+ b is \ekvcValue{b}{#1}.\par}
+ \foo{}
+ \foo{b=e}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvcHashAndForward}
+ \begin{syntax}
+ \cs{ekvcHashAndForward}\meta{cs}\marg{after}\marg{primary keys}
+ \end{syntax}
+ This defines \meta{cs} to be a macro taking one mandatory argument which
+ should contain a \kv\ list. You can use as many primary keys as you want. The
+ primary keys will be forwarded as a single argument containing every key to
+ \meta{after}. You can use a single macro for \meta{after} or use some
+ arbitrary stuff, which will be left in the input stream before the hashed \kv\
+ list with one set of braces stripped. In the macro called in \meta{after} you
+ can access the \val\ of a \key\ by using \cs{ekvcValue}\marg{key}|{#1}| (or
+ whichever argument the hashed \kv\ list will be in).
+\end{function}
+\begin{example}{Using \cs[no-index]{ekvcHashAndForward}}
+ This defines a macro |\foo| processing two keys, and passing the result to
+ |\foobar|:
+ \begin{enverb}
+ \ekvcHashAndForward\foo\foobar{a=a,b=b}
+ \newcommand*\foobar[1]{a is \ekvcValue{a}{#1}.\par
+ b is \ekvcValue{b}{#1}.\par}
+ \foo{}
+ \foo{b=e}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvcHashAndUse}
+ \begin{syntax}
+ \cs{ekvcHashAndUse}\meta{cs}\marg{primary keys}
+ \end{syntax}
+ This will roughly do the same as \cs{ekvcHashAndForward}, but instead of
+ specifying what will be used after hashing the keys during the definition,
+ \meta{cs} will use what follows the \kv\ list. So its syntax will be
+ \begin{quote}
+ \ttfamily
+ \meta{cs}\kvarg\marg{after}
+ \end{quote}
+\end{function}
+
+\begin{function}{\ekvcValue}
+ \begin{syntax}
+ \cs{ekvcValue}\marg{key}\marg{key list}
+ \end{syntax}
+ This is a safe way to access your keys in a hash variant. \key\ is the key
+ which's \val\ you want to use out of the \meta{key list}. \meta{key list}
+ should be the key list argument forwarded to your underlying macro by
+ \cs{ekvcHash}, \cs{ekvcHashAndForward}, or \cs{ekvcHashAndUse}. It will be
+ tested whether the hash function to access that \key\ exists, the \key\
+ argument is not empty, and that the \meta{key list} really contains a \val\ of
+ that \key. This macro needs exactly two steps of expansion and if used inside
+ of an |\edef| or |\expanded| context will protect the \val\ from further
+ expanding.
+\end{function}
+
+\begin{function}{\ekvcValueFast}
+ \begin{syntax}
+ \cs{ekvcValueFast}\marg{key}\marg{key list}
+ \end{syntax}
+ This behaves similar to \cs{ekvcValue}, but \emph{without any} safefy tests.
+ As a result this is about 1.4~times faster \emph{but} will throw low level
+ \TeX\ errors eventually if the hash function isn't defined or the \key\ isn't
+ part of the \meta{key list} (\emph{e.g.}, because it was defined as a key for
+ another macro -- all macros share the same hash function per \meta{key} name).
+ Note that this will not only throw low level errors but result in undefined
+ behaviour as well! This macro needs exactly three steps of expansion in the
+ no-error case.
+\end{function}
+
+\begin{function}{\ekvcValueSplit}
+ \begin{syntax}
+ \cs{ekvcValueSplit}\marg{key}\marg{key list}\marg{next}
+ \end{syntax}
+ If you need a specific \key\ from a \meta{key list} more than once, it'll be a
+ good idea to only extract it once and from then on keep it as a separate
+ argument (or if you want to forward this value to another macro). Hence the
+ macro \cs{ekvcValueSplit} will extract one specific \key's \val\ from the list
+ and forward it as an argument to \meta{next}, so the result of this will be
+ \meta{next}\marg{value}. This is roughly as fast as \cs{ekvcValue} and runs
+ the same tests.
+\end{function}
+\begin{example}
+ {Splitting of a key from a hash list using \cs[no-index]{ekvcValueSplit}}
+ The following defines a macro |\foo| which will take three keys. Since the
+ next parsing step will need the value of one of the keys multiple times we
+ split that key off the list (in this example the next step doesn't use the key
+ multiple times for simplicity though), and the entire list is forwarded as the
+ second argument:
+ \begin{enverb}
+ \ekvcHash\foo{a=a,b=b,c=c}
+ {\ekvcValueSplit{a}{#1}\foobar{#1}}
+ \newcommand*\foobar[2]{a is #1.\par
+ b is \ekvcValue{b}{#2}.\par
+ c is \ekvcValue{c}{#2}.\par}
+ \foo{}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvcValueSplitFast}
+ \begin{syntax}
+ \cs{ekvcValueSplitFast}\marg{key}\marg{key list}\marg{next}
+ \end{syntax}
+ This behaves just like \cs{ekvcValueSplit}, but it won't run the safety tests,
+ hence it is faster but more error prone, just like the relation between
+ \cs{ekvcValue} and \cs{ekvcValueFast}.
+\end{function}
+
+
+\subsection{Secondary Keys\label{sec:c:secondary}}
+
+To lift some limitations of each primary key matching one argument or hash
+entry, you can define secondary keys. Those have to be defined for each macro
+individually but it doesn't matter whether that macro was set up as a split or
+hash variant.
+
+Secondary keys can have a \prefix\ (|long|), and must have a \type\
+(like |meta|). Some \types\ might require some \prefix\ while other
+\types\ might forbid the usage of a specific \prefix.
+
+Please keep in mind that key names shouldn't start with "EKVC|".
+
+\begin{function}{\ekvcSecondaryKeys}
+ \begin{syntax}
+ \cs{ekvcSecondaryKeys}\meta{cs}\kvarg
+ \end{syntax}
+ This is the front facing macro to define secondary keys. For the macro
+ \meta{cs} define \key\ to have definition \val. The general syntax for \key\
+ should be
+ \begin{quote}\ttfamily
+ \meta{prefix} \meta{name}
+ \end{quote}
+ Where \meta{prefix} is a space separated list of optional \prefixes\
+ followed by one \type. The syntax of \meta{value} is dependent on the
+ used \type.
+\end{function}
+
+
+\subsubsection{\textit{Prefixes}}
+
+Currently there is only one \prefix\ available, which is
+\begin{function}[module=expkv-cs prefix]{long}
+ The following key will be defined |\long|.
+\end{function}
+
+
+\subsubsection{\textit{Types}\label{sec:c:secondarytypes}}
+
+Compared to \expkvd\ you might notice that the \types\ here are much fewer.
+Unfortunately the expansion only concept doesn't allow for great variety in the
+common key \types.
+
+The syntax examples of the \types\ will show which \prefix\ will be
+automatically used by printing those black (\texttt{\enfprefix{long}}), which
+will be available in grey (\texttt{\allprefix{long}}), and which will be
+disallowed in red (\texttt{\notprefix{long}}). This will be put flush right next
+to the syntax line.
+
+If a secondary key references another key it doesn't matter whether that other
+key is a primary or secondary key (unless explicitly stated otherwise).
+
+\begin{function}[module=expkv-cs type]{meta}
+ \begin{syntax}
+ meta \key\ = \kvarg \prefixes2
+ \end{syntax}
+ With a |meta| key you can set other keys. Whenever \meta{key} is used the keys
+ in the \kv\ list will be set to the values given there. You can use the \val\
+ given to \key\ by using |#1| in the \kv\ list.
+\end{function}
+
+\begin{function}[module=expkv-cs type]{nmeta}
+ \begin{syntax}
+ nmeta \key\ = \kvarg \prefixes3
+ \end{syntax}
+ An |nmeta| key is like a |meta| key, but it doesn't take a value at use time,
+ so the \kv\ list is static.
+\end{function}
+
+\begin{function}[module=expkv-cs type]{alias}
+ \begin{syntax}
+ alias \meta{key} = \marg{key_2} \prefixes3
+ \end{syntax}
+ This assigns the definition of \meta{key_2} to \key. As a result \key\ is an
+ alias for \meta{key_2} behaving just the same. Both the \Vkey\ and the \Nkey\
+ will be copied if they are defined when |alias| is used. Of course,
+ \meta{key_2} has to be defined as at least one of \Nkey\ or \Vkey.
+\end{function}
+
+\begin{function}[module=expkv-cs type]{default}
+ \begin{syntax}
+ default \key\ = \marg{default} \prefixes3
+ \end{syntax}
+ If \key\ is defined as a \Vkey\ you can define a \Nkey\ version with this. The
+ \Nkey\ will behave as if \key\ was given \meta{default} as its \val. Note that
+ this doesn't change the initial values of primary keys set at definition time
+ (see \cs{ekvcChange} in \autoref{sec:c:change} for this). If \key\ isn't yet
+ defined this results in an error.
+\end{function}
+
+\begin{function}[module=expkv-cs type]{enum}
+ \begin{syntax}
+ enum \key\ = \marg{key_2}\kvarg \prefixes2
+ \end{syntax}
+ This defines \key\ to only accept the values given in the list of the second
+ argument of its definition. It forwards the position of \val\ in that list to
+ \meta{key_2} (zero-based). The \meta{key_2} has to already be defined by the
+ time an |enum| key is set up. Each \val\ in the list (and at use time) is
+ |\detokenize|d, so no expansion takes place here.
+
+ If you use |enum| twice on the same \key\ the new values will again start at
+ zero (so it is possible to define multiple values with the same outcome),
+ however since you can't skip values you'll have to use the same as in the
+ first call for values with just a single variant. There is no interface to
+ delete existing values.
+\end{function}
+\begin{example}{Enumerating choices with the \texttt{enum} \type}
+ First a small example that might give you an idea of what the description
+ above could mean:
+ \begin{enverb}
+ \ekvcSplit\foo{k-internal=-1}{#1}
+ \ekvcSecondaryKeys\foo
+ {enum k = {k-internal}{a,b,c}}
+ \foo{}\foo{k=a}\foo{k=b}\foo{k=c}
+ \end{enverb}
+\end{example}
+\begin{example}{A slightly more complicated usage of the \texttt{enum} \type}
+ We can define a choice setup that might do different things based on the
+ choice encountered, and the numeric value is easy to parse using
+ \cs[no-index]{ifcase}:
+ \begin{enverb}
+ \ekvcSplit\foo{k-internal=-1}
+ {%
+ \ifcase#1
+ is\or
+ This\or
+ easy%
+ \else
+ .%
+ \fi
+ }
+ \ekvcSecondaryKeys\foo
+ {enum k = {k-internal}{a,b,c}}
+ \foo{k=b} \foo{k=a} \foo{k=c}\foo{}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-cs type]{choice}
+ \begin{syntax}
+ choice \key\ = \marg{key_2}\kvarg \prefixes2
+ \end{syntax}
+ This is pretty similar to an |enum|, but unlike with |enum| the forwarded
+ \val\ will not be numeric, instead the \val\ as given during the definition
+ time will be forwarded. This means that while the user input has to match in a
+ |\detokenize|d form, the \val\ might still expand further during your macro's
+ expansion (if what you provided as a choice is expandable).
+\end{function}
+\begin{example}{Filtering possible values with the \texttt{choice} \type}
+ We could use this to filter out the possible vertical placements of a \LaTeXe\
+ |tabular|:
+ \begin{enverb}
+ \ekvcSplit\foo{v-internal=c,a=t,b=c,c=b}
+ {%
+ \begin{tabular}[#1]{@{} c @{:} c @{}}
+ a & #2\\
+ b & #3\\
+ c & #4\\
+ \end{tabular}%
+ }
+ \ekvcSecondaryKeys\foo
+ {choice v = {v-internal}{t,c,b}}
+ \foo{} \foo{v=t} \foo{v=c} \foo{v=b}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-cs type]{aggregate,e-aggregate}
+ \begin{syntax}
+ aggregate \key\ = \marg{primary}\marg{definition} \prefixes3
+ \end{syntax}
+ While other key \types\ replace the current value of the associated
+ primary key, with |aggregate| you can create keys that append or prepend (or
+ whatever you like) the new value to the current one. Your definition of an
+ |aggregate| key must be exactly two \TeX\ arguments, where \meta{primary}
+ should be the name of a primary key, and \meta{definition} the way you want to
+ store the current and the new value. Inside \meta{definition} you can use |#1|
+ for the current, and |#2| for the new value. The \meta{definition} will not
+ expand any further during the entire parsing for |aggregate|, whereas in
+ |e-aggregate| everything that ends up in \meta{definition} (so whatever you
+ provide including the values in |#1| and |#2|) will be fully expanded (using
+ the |\expanded| primitive), so use |\noexpand| and |\unexpanded| to protect
+ what shouldn't be expanded.
+ The resulting \meta{key} will inherit being either |short| or |long| from the
+ \meta{primary} key.
+\end{function}
+\begin{example}{Building a list with the \texttt{aggregate} \type}
+ The following defines an internal key (|k-internal|), which is used to build a
+ comma separated list from each call of the user facing key (|k|):
+ \begin{enverb}
+ \ekvcSplit\foo
+ {k-internal=0,color=red}
+ {\textcolor{#2}{#1}}
+ \ekvcSecondaryKeys\foo
+ {aggregate k = {k-internal}{#1,#2}}
+ \foo{}\par
+ \foo{k=1,k=2,k=3,k=4}
+ \end{enverb}
+\end{example}
+\begin{example}{Building a convoluted list with the \texttt{aggregate} \type}
+ But also more strange stuff could end there, like macros or using the same
+ value multiple times:
+ \begin{enverb}[no-tcb]
+ \ekvcSecondaryKeys\foo
+ {aggregate k = {k-internal}{\old{#1}\new{#2\old{#1}}}}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-cs type]{flag-bool}
+ \begin{syntax}
+ flag-bool \key\ = \meta{cs} \prefixes3
+ \end{syntax}
+ This is a secondary \type\ that doesn't involve any of the primary or other
+ secondary keys. This defines \key\ to take a value, which should be either
+ |true| or |false|, and set the flag called \meta{cs} accordingly as a boolean.
+ If \meta{cs} isn't defined yet it will be initialised as a flag. Note that the
+ flag will not be set to a specific state automatically so a flag set in one
+ macro might affect every other macro in the current scope. Please also read
+ \autoref{sec:c:flags}.
+\end{function}
+\begin{example}{Using a Boolean flag with the \texttt{flag-bool} \type}
+ Provide a key |bold| to turn the output of our macro bold if the associated
+ flag is |true|.
+ \begin{enverb}
+ \ekvcSplit\foo{a=a,b=b}
+ {%
+ \ekvcFlagIf\fooFlag
+ {\textbf{a is #1 and b is #2}\par}
+ {a is #1 and b is #2\par}%
+ }
+ \ekvcSecondaryKeys\foo{flag-bool bold = \fooFlag}
+ \foo{}\foo{bold=true}\foo{}\foo{bold=false}\foo{}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-cs type]{flag-true,flag-false}
+ \begin{syntax}
+ flag-true \key\ = \meta{cs} \prefixes3
+ \end{syntax}
+ This is similar to |flag-bool|, but the \meta{key} will be a \Nkey\ and if
+ used will set the flag to either |true| or |false|. If \meta{cs} isn't defined
+ yet it will be initialised as a flag. Note that the flag will not be set to a
+ specific state automatically. Please also read \autoref{sec:c:flags}.
+\end{function}
+
+\begin{function}[module=expkv-cs type]{flag-raise}
+ \begin{syntax}
+ flag-raise \key\ = \meta{cs} \prefixes3
+ \end{syntax}
+ This defines \key\ to be a \Nkey\ that will raise the flag called \meta{cs} on
+ usage. If \meta{cs} isn't defined yet it will be initialised as a flag. Note
+ that the flag will not be set to a specific state automatically. Please also
+ read \autoref{sec:c:flags}.
+\end{function}
+
+
+\subsection{Changing the Initial Values\label{sec:c:change}}
+
+\begin{function}{\ekvcChange}
+ \begin{syntax}
+ \cs{ekvcChange}\meta{cs}\kvarg
+ \end{syntax}
+ This processes the \kv\ list for the macro \meta{cs} to set new defaults for
+ it (meaning the initial values used if you don't provide anything at use time,
+ not those specified with the |default| \type). \meta{cs} should be defined
+ with \expkvc\ (but it doesn't matter if it's a split or hash variant). Inside
+ the \kv\ list both primary and secondary keys can be used. If \meta{cs} was
+ defined |\long| earlier it will still be |\long|, every other \TeX\ prefix
+ will be stripped (but \expkvc\ doesn't support them anywhere else so that
+ should be fine). The resulting new defaults will be stored inside the
+ \meta{cs} locally (just as the original initial values were). If there was an
+ unknown key forwarding added to \meta{cs} (see \autoref{sec:c:unknown}) any
+ unknown key will be stored inside the list of unknown keys as well.
+ \cs{ekvcChange} is not expandable!
+\end{function}
+\begin{example}
+ {Changing the values for future calls using \cs[no-index]{ekvcChange}}
+ With \cs{ekvcChange} we can now do the following:
+ \begin{enverb}
+ \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
+ \begingroup
+ \ekvcChange\foo{b=B}
+ \foo{}
+ \ekvcSecondaryKeys\foo{meta c={a={#1},b={#1}}}
+ \ekvcChange\foo{c=c}
+ \foo{}
+ \endgroup
+ \foo{}
+ \end{enverb}
+\end{example}
+\begin{example}{A typical setup macro for \expkvc\ macros}
+ As a result with this the typical setup macro could be implemented:
+ \begin{enverb}[no-tcb]
+ \ekvcHashAndUse\fooKV{keyA=a,keyB=b}
+ \def\fooA#1{\fooKV{#1}\fooAinternal}
+ \def\fooB#1{\fooKV{#1}\fooBinternal}
+ \protected\def\foosetup{\ekvcChange\fooKV}
+ \end{enverb}
+ Of course the usage is limited to a single macro |\fooKV|, hence this might
+ not be as powerful as similar macros used with other \kv\ interfaces. But at
+ least a few similar macros could be grouped using the same key parsing macro
+ internally like |\fooA| and |\fooB| do in this example.
+\end{example}
+
+
+\subsection{Handling Unknown Keys\label{sec:c:unknown}}
+
+If your macro should handle unknown keys without directly throwing an error you
+can use the special |...| marker in the \meta{primary keys} list. Since those
+keys will be processed once by \expkv\ they will be forwarded normalised: The
+\key\ and the \val\ will be forwarded with one set of surrounding spaces and
+braces, so a \kv\ pair will result in \texttt{\vissp{ \marg{key} = \marg{val} }}
+and a \Nkey\ is forwarded as \texttt{\vissp{ \marg{key} }} (this way most other
+\kv\ implementations should parse the correct input).
+
+The exact behaviour differs slightly between the two variants (as all primary
+keys do). The behaviour inside the split variants will be similar to normal
+primary keys, the $n$-th argument (corresponding to the position of |...| inside
+the primary keys list) will contain any unknown key encountered while parsing
+the argument. And inside the split variant you can use a primary key named |...|
+at the same time (since only the position in the list determines the argument,
+not the name).
+\begin{example}{Using unknown key handlers to wrap another \kv\ enabled macro}
+ The following will forward any unknown key to |\includegraphics| to control
+ the appearance while processing its own keys:
+ \begin{enverb}[same-line=0.6]
+ \newcommand*\foo{\ekvoptarg\fooKV{}}
+ \ekvcSplitAndForward\fooKV\fooOUT
+ {
+ a=a
+ ,...
+ ,b=b
+ ,...={}
+ }
+ \newcommand\fooOUT[5]
+ {%
+ a is #1 and b is #3.\par
+ \includegraphics[{#2}]{#5}\par
+ \texttt{...} is #4.\par
+ }
+ \foo[width=.5\linewidth, b=c,
+ ...={a stupid key name, but works}]
+ {example-image-duck}
+ \end{enverb}
+\end{example}
+
+Inside the hash variants the unknown keys list will be put inside the hash named
+|...| (we have to use some name, and this one seems reasonable). As a
+consequence a primary key named |...| would clash with the unknown key handler.
+If you still used such a key it would remove any unknown key stored there until
+that point and replace the list with its value.
+\begin{example}{Wrapping an existing macro, but with a hash variant}
+ The following is more or less equivalent to the above example, but with the
+ hash variant, and it will not contain the primary |...| key. We have to make
+ sure that |\includegraphics| sees the \kv\ list, so need to expand
+ |\ekvcValue{...}{#1}| before |\includegraphics| parses it.
+ \begin{enverb}[same-line=0.76]
+ \newcommand*\foo{\ekvoptarg\fooKV{}}
+ \ekvcHashAndForward\fooKV\fooOUT
+ {a=a, b=b, ...}
+ \newcommand\fooOUT[2]
+ {%
+ a is \ekvcValue{a}{#1} and
+ b is \ekvcValue{b}{#1}.\par
+ \ekvcValueSplit{...}{#1}{\includegraphics[}]%
+ {#2}\par
+ }
+ \foo[width=\linewidth, b=c]
+ {example-image-duck-portrait}
+ \end{enverb}
+\end{example}
+
+
+\subsection{Flags\label{sec:c:flags}}
+
+The idea of flags is taken from \pkg{expl3}. They provide a way to store
+numerical information expandably, however only incrementing and accessing works
+expandably, decrementing is unexpandable. A flag has a height, which is a
+numerical value, and which can be raised by 1. Flags come at a high
+computational cost (accessing them is slow and they require more memory than
+normal \TeX\ data types like registers, both issues getting linearly worse with
+the height), so don't use them if not necessary.
+
+The state of flags is always changed locally to the current group, but not to
+the current macro, so if you're using one of the \types\ involving flags
+bear in mind that they can affect other macros using the same flags at the
+current scope!
+
+\expkvc\ provides some macros to access, alter, and use flags. Flags of \expkvc\
+don't share a name space with the flags of \pkg{expl3}.
+
+\begin{function}{\ekvcFlagNew}
+ \begin{syntax}
+ \cs{ekvcFlagNew}\meta{flag}
+ \end{syntax}
+ This initialises the macro \meta{flag} as a new flag. It isn't checked whether
+ the macro \meta{flag} is currently undefined. A \meta{flag} will expand to the
+ flag's current height with a trailing space (so you can use it directly with
+ \cs[no-index]{ifnum} for example and it will terminate the number scanning on
+ its own).
+
+ All other macros dealing with flags take as a parameter a macro defined as a
+ \meta{flag} with \cs{ekvcFlagNew}.
+\end{function}
+
+\begin{function}{\ekvcFlagHeight}
+ \begin{syntax}
+ \cs{ekvcFlagHeight}\meta{flag}
+ \end{syntax}
+ This expands to the current height of \meta{flag} in a single step of
+ expansion (without a trailing space).
+\end{function}
+
+\begin{function}{\ekvcFlagRaise}
+ \begin{syntax}
+ \cs{ekvcFlagRaise}\meta{flag}
+ \end{syntax}
+ This expandably raises the height of \meta{flag} by 1.
+\end{function}
+
+\begin{function}{\ekvcFlagSetTrue,\ekvcFlagSetFalse}
+ \begin{syntax}
+ \cs{ekvcFlagSetTrue}\meta{flag}
+ \end{syntax}
+ By interpreting an even value as false and an odd value as true we can use a
+ flag as a boolean. This expandably sets \meta{flag} to true or false,
+ respectively, by raising it if necessary.
+\end{function}
+
+\begin{function}{\ekvcFlagIf}
+ \begin{syntax}
+ \cs{ekvcFlagIf}\meta{flag}\marg{true}\marg{false}
+ \end{syntax}
+ This interprets a \meta{flag} as a boolean and expands to either \meta{true}
+ or \meta{false}.
+\end{function}
+
+\begin{function}{\ekvcFlagIfRaised}
+ \begin{syntax}
+ \cs{ekvcFlagIfRaised}\meta{flag}\marg{true}\marg{false}
+ \end{syntax}
+ This tests whether the \meta{flag} is raised, meaning it has a height greater
+ than zero, and if so expands to \meta{true} else to \meta{false}.
+\end{function}
+
+\begin{function}{\ekvcFlagReset,\ekvcFlagResetGlobal}
+ \begin{syntax}
+ \cs{ekvcFlagReset}\meta{flag}
+ \end{syntax}
+ This resets a flag (so restores its height to 0). This operation is \emph{not}
+ expandable and done locally for \cs{ekvcFlagReset} and globally for
+ \cs{ekvcFlagResetGlobal}. If you really intend to use flags you can reset them
+ every now and then to keep the performance hit low.
+\end{function}
+
+\begin{function}{\ekvcFlagGetHeight}
+ \begin{syntax}
+ \cs{ekvcFlagGetHeight}\meta{flag}\marg{next}
+ \end{syntax}
+ This retrieves the current height of the \meta{flag} and provides it as a
+ braced argument to \meta{next}, leaving \meta{next}\marg{height} in the input
+ stream.
+\end{function}
+
+\begin{function}{\ekvcFlagGetHeights}
+ \begin{syntax}
+ \cs{ekvcFlagGetHeights}\marg{flag-list}\marg{next}
+ \end{syntax}
+ This retrieves the current height of each \meta{flag} in the \meta{flag-list}
+ and provides them as a single argument to \meta{next}. Inside that argument
+ each height is enclosed in a set of braces individually. The \meta{flag-list}
+ is just a single argument containing the \meta{flag}s. So a usage like
+ |\ekvcFlagGetHeights{\myflagA\myflagB}{\stuff}| will expand to
+ |\stuff{|\marg{height-A}\marg{height-B}|}|.
+\end{function}
+
+
+\subsection{Further Examples}
+
+\begin{example}{Defining an expandable \kv\ macro with an optional argument}
+ Using \cs[no-index]{NewExpandableDocumentCommand} or \expkv's \cs{ekvoptarg}
+ or \cs{ekvoptargTF} and forwarding arguments one can easily define \kv\ macros
+ with actual optional and mandatory arguments as well. A small nonsense
+ example:
+ \begin{enverb}[below,inter=resulting in]
+ \makeatletter
+ \newcommand*\nonsense{\ekvoptarg\nonsense@a{}}
+ \ekvcHashAndForward\nonsense@a\nonsense@b
+ {
+ keyA = A,
+ keyB = B,
+ keyC = c,
+ keyD = d,
+ }
+ \newcommand*\nonsense@b[2]
+ {%
+ \begin{tabular}{lll|}
+ key & A & \ekvcValue{keyA}{#1} \\
+ & B & \ekvcValue{keyB}{#1} \\
+ & C & \ekvcValue{keyC}{#1} \\
+ & D & \ekvcValue{keyD}{#1} \\
+ \multicolumn{2}{l}{mandatory} & #2 \\
+ \end{tabular}%
+ }
+ \makeatother
+ \nonsense{} % do nonsense
+ \nonsense[keyA=hihi]{haha}
+ \nonsense[keyA=hihi, keyB=A]{hehe}
+ \nonsense[keyC=huhu, keyA=hihi, keyB=A]{haha}
+ \end{enverb}
+\end{example}
+
+\begin{example}{The \cs[no-index]{sine} example revisited}
+ In \autoref{sec:expkv:sneak} I presented an expandable macro to calculate the
+ sine of some user input with a few keys, and there I hinted to \expkvc, so
+ here's the same function implemented with |\ekvcSplitAndForward|. There is a
+ small difference here, we need to use an internal key to store whether degrees
+ or radians will be used, but we don't need to use an internal key to collect
+ the values of our individual keys in the correct order.
+ \begin{enverb}
+ \makeatletter
+ \newcommand\sine{\ekvoptarg\sine@kv{}}
+ \ekvcSplitAndForward\sine@kv\sine@do
+ {
+ f = sin
+ ,internal = d
+ ,round = 3
+ }
+ \ekvcSecondaryKeys\sine@kv
+ {
+ nmeta degree = internal=d
+ ,nmeta radian = internal={}
+ }
+ \newcommand*\sine@do[4]{\fpeval{round(#1#2(#4),#3)}}
+ \makeatother
+ \sine{60}\par
+ \sine[round=10]{60}\par
+ \sine[f=cos,radian]{pi}\par
+ \edef\myval{\sine[f=tan]{1}}\texttt{\meaning\myval}
+ \end{enverb}
+\end{example}
+
+
+\subsection{Freedom for Keys!}
+
+If this had been the \TeX{}book this subsection would have had a double bend
+sign. Not because it is overly complicated, but because it shows things which
+could break \expkvc's expandability and its alignment safety. This is for
+experienced users wanting to get the most flexibility and knowing what they are
+doing.
+
+In case you're wondering, it is possible to define other keys than the primaries
+and the secondary key \types\ listed in \autoref{sec:c:secondary} for a
+macro defined with \expkvc\ by using the low-level interface of \expkv\ or even
+the interface provided by \expkvd. The set name used for \expkvc's keys is the
+macro name, including the leading backslash, or more precisely the result of
+|\string|\meta{cs} is used. This can be exploited to define additional keys with
+arbitrary code. Consider the following \emph{bad} example:
+\begin{enverb}[no-tcb]
+ \ekvcSplit\foo{a=A,b=B}{a is #1.\par b is #2.\par}
+ \protected\ekvdef{\string\foo}{c}{\def\fooC{#1}}
+\end{enverb}
+This would define a key named |c| that will store its \val\ inside a macro. The
+issue with this is that this can't be done expandably. As a result, the macro
+|\foo| isn't always expandable any more (not that bad if this was never
+required; killjoy if it was) and as soon as the key |c| is used it is also no
+longer alignment safe\footnote{This means that the \kv\ list can't contain
+ alignment markers that are not inside an additional set of braces if used
+ inside a \TeX\ alignment}
+(might be bad depending on the usage).
+
+So why do I show you this? Because we could as well do something useful like
+creating a key that pre-parses the input and after that passes the parsed value
+on. This parsing would have to be completely expandable though (and we could
+perhaps also implement this using the |e-aggregate| \type). For the
+pass-on part we can use the following function:
+
+\begin{function}{\ekvcPass}
+ \begin{syntax}
+ \cs{ekvcPass}\meta{cs}\marg{key}\marg{value}
+ \end{syntax}
+ This passes \val\ on to \key\ for the \expkvc-macro \meta{cs}. It should be
+ used inside the key parsing of a macro defined with \expkvc, else this most
+ likely results in a low level \TeX\ error. You can't forward anything to the
+ special unknown key handler |...| as that is no defined key.
+\end{function}
+\begin{example}
+ {Forwarding pre-parsed keys to an \expkvc\ key with \cs[no-index]{ekvcPass}}
+ With this we could for example split the value of a key at a hyphen and pass
+ the parts to different keys:
+ \begin{enverb}
+ \ekvcSplit\foo{a=A,b=B}{a is #1.\par b is #2.\par}
+ \ekvdef{\string\foo}{c}{\fooSplit#1\par}
+ \def\fooSplit#1-#2\par
+ {\ekvcPass\foo{a}{#1}\ekvcPass\foo{b}{#2}}
+ \foo{}
+ \foo{c=1-2}
+ \end{enverb}
+\end{example}
+
+Additionally, there is a more general version of the |aggregate| secondary key
+type, namely the |process| key type:
+
+\begin{function}[module=expkv-cs type]{process}
+ \begin{syntax}
+ process \key\ = \marg{primary}\marg{definition} \prefixes2
+ \end{syntax}
+ This will grab the current value of a \meta{primary} key as |#1| (without
+ changing the current value) and the new value as |#2| and leave all the
+ processing to \meta{definition}. You should use \cs{ekvcPass} to forward the
+ values afterwards. Unlike |aggregate| you can specify whether the \meta{key}
+ should be long or not, this isn't inherited from the \meta{primary} key. Keep
+ in mind that you could easily break things here if your code does not work by
+ expansion.
+\end{function}
+\begin{example}{Filtering out values with the \texttt{process} \type}
+ We could define a key that only accepts values greater than the current value
+ with this:
+ \begin{enverb}
+ \ekvcSplit\foo{internal=5}{a is #1.\par}
+ \ekvcSecondaryKeys\foo
+ {
+ process a={internal}
+ {\ifnum#1<#2 \ekvcPass\foo{internal}{#2}\fi}
+ }
+ \foo{a=1}
+ \foo{a=5}
+ \foo{a=9}
+ \end{enverb}
+\end{example}
+\begin{example}{Filtering out values with the \texttt{e-aggregate} \type}
+ The same is possible with an |e-aggregate| key as well though:
+ \begin{enverb}[no-tcb]
+ \ekvcSplit\foo{internal=5}{a is #1.\par}
+ \ekvcSecondaryKeys\foo
+ {
+ e-aggregate a={internal}
+ {\ifnum#1<#2 \unexpanded{#2}\else\unexpanded{#1}\fi}
+ }
+ \end{enverb}
+\end{example}
+
+\subsection{Useless Macros}
+
+These macros are most likely of little to no interest to users.
+
+\begin{function}{\ekvcDate,\ekvcVersion}
+ These two macros store the version and date of the package/generic code.
+\end{function}
diff --git a/macros/generic/expkv-bundle/pkg-def.tex b/macros/generic/expkv-bundle/pkg-def.tex
new file mode 100644
index 0000000000..fade98e8b8
--- /dev/null
+++ b/macros/generic/expkv-bundle/pkg-def.tex
@@ -0,0 +1,727 @@
+\genericekv\expkvd{-def}
+
+Since the trend for the last couple of years goes to defining keys for a \kv\
+interface using a \kv\ interface, I thought that maybe providing such an
+interface for \expkv\ will make it more attractive for actual use. But at the
+same time I didn't want to broaden \expkv's initial scope. So here is \expkvd,
+go define \kv\ interfaces with \kv\ interfaces.
+
+Unlike many of the other established \kv\ interfaces to define keys, \expkvd\
+works using prefixes instead of suffixes (\emph{e.g.}, |.tl_set:N| of
+\pkg{l3keys}) or directory like handlers (\emph{e.g.}, |/.store in| of
+\pkg{pgfkeys}). This was decided as a personal preference, more over in \TeX\
+parsing for the first spaces is way easier than parsing for the last one, so
+this should also turn out to be faster. \expkvd's prefixes are sorted into two
+categories: \prefixes, which are equivalent to \TeX's prefixes like |\long| and
+of which a \key\ can have multiple, and \types\ defining the basic behaviour of
+the \key\ and of which a \key\ must have one. For a description of the available
+\prefixes\ take a look at \autoref{sec:d:prefixes}, the \types\ are described in
+\autoref{sec:d:types}.
+
+
+\subsection{Macros\label{sec:d:macros}}
+
+The number of user-facing macros is quite manageable:
+
+\begin{function}{\ekvdefinekeys}
+ \begin{syntax}
+ \cs{ekvdefinekeys}\marg{set}\kvarg
+ \end{syntax}
+ In \meta{set}, define \key\ to have definition \val. The general syntax for
+ \key\ should be
+ \begin{quote}
+ \ttfamily
+ \meta{prefix} \meta{name}
+ \end{quote}
+ where \meta{prefix} is a space separated list of optional \prefixes\ followed
+ by one \type. The syntax of \val\ is dependent on the used \type.
+\end{function}
+
+\begin{function}{\ekvdDate,\ekvdVersion}
+ These two macros store the version and date of the package.
+\end{function}
+
+
+\subsection{Prefixes}
+
+As already said, prefixes are separated into two groups, \prefixes\ and \types.
+Not every \prefix\ is allowed for all \types.
+
+
+\subsubsection{\textit{Prefixes}\label{sec:d:prefixes}}
+
+\begin{function}[module=expkv-def prefix]{new}
+ The following \key\ must be new (so previously undefined). An error is thrown
+ if it is already defined and the new definition is ignored. |new| only asserts
+ that there are no conflicts between \Nkey{}s and other \Nkey{}s or \Vkey{}s
+ and other \Vkey{}s.
+\end{function}
+\begin{example}{The effects of the \texttt{new} \prefix}
+ You can test the following (lines throwing an error are marked by a comment,
+ error messages are printed in red for this example):
+ \expkvdocPrintErrors[\par]%
+ \begin{enverb}[below]
+ \ekvdefinekeys{new-example}
+ {
+ new code key = \domystuffwitharg{#1}
+ ,new noval KEY = \domystuffwithoutarg
+ ,new bool key = \mybool % Error!
+ ,new bool KEY = \mybool % Error!
+ ,new meta key = {KEY} % Error!
+ ,new nmeta KEY = {key} % Error!
+ }
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def prefix]{also}
+ The following key \type\ will be \emph{added} to an existing \key's
+ definition. You can't add a \type\ taking an argument at use time to an
+ existing \key\ which doesn't take an argument and vice versa. Also you'll get
+ an error if you try to add an action which isn't allowed to be either |\long|
+ or |\protected| to a \key\ which already is |\long| or |\protected| (the
+ opposite order would be suboptimal as well, but can't be really captured with
+ the current code).
+
+ A \key\ already defined as |\long| or |\protected| will stay that way, but you
+ can add |\long| or |\protected| to a \key\ which isn't by using |also|.
+\end{function}
+\begin{example}
+ {Overload a key \type\ with another with the \texttt{also} \prefix}
+ Suppose you want to create a boolean \key, but additionally to setting a
+ boolean value you want to execute some more code as well. For this you can use
+ the following:
+ \begin{enverb}[no-tcb]
+ \ekvdefinekeys{also-example}
+ {
+ bool key = \ifmybool
+ ,also code key = \domystuff{#1}
+ }
+ \end{enverb}
+\end{example}
+
+If you use |also| on a |choice|, |bool|, |invbool|, or |boolpair| \key\ it is
+tried to determine if the key already is of one of those types. If this test is
+true the declared choices will be added to the possible choices but the key's
+definition will not be changed other than that. If that wouldn't have been done,
+the callbacks of the different choices could get called multiple times.
+
+\begin{function}[module=expkv-def prefix]{protected,protect}
+ The following \key\ will be defined |\protected|. Note that \types\ which
+ can't be defined expandable will always use |\protected|. This only affects
+ the key at use time not the \key\ definition.
+\end{function}
+
+\begin{function}[module=expkv-def prefix]{long}
+ The following \key\ will be defined |\long| (so can take an explicit |\par|
+ token in its \val). Please note that this only changes the \key\ at use time.
+ |long| being present or not doesn't limit you to use |\par| inside of the
+ \key's definition (if the \type\ allows this).
+\end{function}
+
+
+\subsubsection{\textit{Types}\label{sec:d:types}}
+
+Since the \prefixes\ apply to some of the \types\ automatically but sometimes
+one might be disallowed we need some way to highlight this behaviour. In the
+following an enforced \prefix\ will be printed black
+(\texttt{\enfprefix{protected}}), allowed \prefixes\ will be grey
+(\texttt{\allprefix{protected}}), and disallowed \prefixes\ will be red
+(\texttt{\notprefix{protected}}). This will be put flush-right in the syntax
+showing line.
+
+\begin{function}[module=expkv-def type]{code,ecode}
+ \begin{syntax}
+ code \key\ = \marg{definition} \prefixes2222
+ \end{syntax}
+ Define \key\ to be a \Vkey\ expanding to \meta{definition}. You can use |#1|
+ inside \meta{definition} to access the \key's \val. The |ecode| variant will
+ fully expand \meta{definition} inside an |\edef|.
+\end{function}
+\ekvset{enverb}{no-tcb,store}% affect all the next examples.
+\begin{example}
+ {Defining a \Vkey\ with arbitrary effect with the \texttt{code} \type}
+ The following defines the key |foo|, that'll count the number of tokens passed
+ to it (we'll borrow a function from \pkg{expl3} for this). It'll accept
+ explicit |\par| tokens. Also it'll flip the \TeX-if \cs[no-index]{iffoo} to
+ true. The result of the counting will be stored in a count register. (Don't
+ get confused, all the next examples are part of this |\ekvdefinekeys| call, so
+ there is no closing brace here.)
+ \begin{enverb}
+ \ExplSyntaxOn
+ \cs_new_eq:NN \exampleCount \tl_count_tokens:n
+ \ExplSyntaxOff
+ \newcount\examplefoocount
+ \newif\iffoo
+ \ekvdefinekeys{example}
+ {
+ protected long code foo =
+ \footrue
+ \examplefoocount=\exampleCount{#1}\relax
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{noval,enoval}
+ \begin{syntax}
+ noval \key\ = \marg{definition} \prefixes2223
+ \end{syntax}
+ The |noval| \type\ defines \key\ as a \Nkey\ expanding to \meta{definition}.
+ |enoval| fully expands \meta{definition} inside an |\edef|.
+\end{function}
+\begin{example}{An arbitrary \Nkey\ action with the \texttt{noval} \type}
+ The following defines the \Nkey\ |foo| to toggle the \TeX-if
+ \cs[no-index]{iffoo} to false and set |\examplecount| to |0|. It'll be
+ |\protected| and mustn't override any existing key.
+ \begin{enverb}
+ ,new protected noval foo = \foofalse\examplefoocount=0\relax
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{default,odefault,fdefault,edefault}
+ \begin{syntax}
+ default \key\ = \marg{definition} \prefixes2223
+ \end{syntax}
+ This serves to place a default \val\ for a \Vkey. Afterwards if you use \key\
+ as a \Nkey\ it will be the same as if \key\ got passed \meta{definition} as
+ its \val. The |odefault| variant will expand the key-macro once, so will be
+ slightly quicker, but not change if you redefine the \Vkey\ afterwards. The
+ |fdefault| version will expand the key-code until a non-expandable token or a
+ space is found, a space would be gobbled.\footnotemark{}
+ The |edefault| on the other hand fully expands the key-code with
+ \meta{definition} as its argument in |\expanded|. The \prefix\ |new|
+ means that there should be no \Nkey\ of that name yet.
+\end{function}%
+\footnotetext{For those familiar with \TeX-coding: This uses a
+\cs[no-index]{romannumeral}-expansion}
+\begin{example}
+ {Setting a default value for a \Vkey\ with the \texttt{default} \type}
+ We later decide that the above behaviour isn't what we need any more and
+ instead redefine the \Nkey\ |foo| to pass some default value to the \Vkey\
+ |foo|.
+ \begin{enverb}
+ ,default foo = {Some creative default text}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{initial,oinitial,finitial,einitial}
+ \begin{syntax}
+ initial \key\ = \marg{value} \prefixes3333
+ initial \key
+ \end{syntax}
+ With |initial| you can set an initial \val\ for an already defined \key. It'll
+ just call the \key\ and pass it \val. The |einitial| variant will expand \val\
+ using |\expanded| prior to passing it to the \key\ and the |oinitial|
+ variant will expand the first token in \val\ once. |finitial| will expand
+ \val\ until a non-expandable token or a space is found, a space would be
+ gobbled.\footnotemark
+
+ If you don't provide a \val\ (and no equals sign) the \Nkey\ of the same name
+ is called once (or, if you specified a |default| for a \Vkey\ that would be
+ used).
+\end{function}%
+\footnotetext{Again using \cs[no-index]{romannumeral}}
+\begin{example}{Specifying initial values with the \texttt{initial} \type}
+ We want to get a defined initial behaviour for our |foo|. So we count
+ 0~tokens.
+ \begin{enverb}
+ ,initial foo = {}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{bool,gbool,boolTF,gboolTF}
+ \begin{syntax}
+ bool \key\ = \meta{cs} \prefixes2223
+ \end{syntax}
+ \singlecs{iffoo}
+ This will define \key\ to be a boolean key, which only takes the values |true|
+ or |false| and will throw an error for other values. If the \key\ is used as
+ a \Nkey\ it'll have the same effect as if you use |true|. |bool| and |gbool|
+ will behave like \TeX-ifs, so either be \cs[no-index]{iftrue} or
+ \cs[no-index]{iffalse}. The \meta{cs} in the |boolTF| and |gboolTF| variants
+ will take two arguments and if true the first will be used else the second, so
+ they are always either |\@firstoftwo| or |\@secondoftwo|. The variants with a
+ leading |g| will set the \meta{cs} globally, the other locally. If \meta{cs}
+ is not yet defined it'll be initialised as the |false| version. Note that the
+ initialisation is \emph{not} done with |\newif|, so you will not be able to do
+ |\footrue| outside of the \kv\ interface, but you could use |\newif| yourself.
+ Even if the \key\ will not be |\protected| the commands which execute the
+ |true| or |false| choice will be, so the usage should be safe in an expansion
+ context (\emph{e.g.}, you can use \texttt{edefault \key\ = false} without an
+ issue to change the default behaviour to execute the |false| choice).
+ Internally a |bool| is the same as a |choice| \type\ which is set up to handle
+ |true| and |false| as choices. |new| will assert that neither the \Vkey\ nor
+ the \Nkey\ are already defined.
+\end{function}
+\begin{example}{Defining Boolean keys with the \texttt{bool} \type}
+ Also we want to have a direct way to set our \cs[no-index]{iffoo}, now that
+ the \Nkey\ doesn't toggle it any longer.
+ \begin{enverb}
+ ,bool dofoo = \iffoo
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{invbool,ginvbool,invboolTF,ginvboolTF}
+ \begin{syntax}
+ invbool \key\ = \meta{cs} \prefixes2223
+ \end{syntax}
+ These are inverse boolean keys, they behave like |bool| and friends but set
+ the opposite meaning to the macro \meta{cs} in each case. So if |key=true| is
+ used |invbool| will set \meta{cs} to \cs[no-index]{iffalse} and vice versa.
+\end{function}
+\begin{example}
+ {Inversing the logic of a Boolean with the \texttt{invbool} \type}
+ And since traditional interfaces lacked \kv\ support for packages, often a
+ negated boolean key was used as well.
+ \begin{enverb}
+ ,invbool nofoo = \iffoo
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{boolpair,gboolpair,boolpairTF,gboolpairTF}
+ \begin{syntax}
+ boolpair \key\ = \meta{cs_1}\meta{cs_2} \prefixes2223
+ \end{syntax}
+ The |boolpair| \type\ behaves like both |bool| and |invbool|, the \meta{cs_1}
+ will be set to the meaning according to the rules of |bool|, and \meta{cs_2}
+ will be set to the opposite.
+\end{function}
+
+\begin{function}[module=expkv-def type]{store,estore,gstore,xstore}
+ \begin{syntax}
+ store \key\ = \meta{cs} \prefixes2212
+ \end{syntax}
+ \singlecs{foo}
+ This will define a \Vkey\ to store \val\ inside of the control sequence. If
+ \meta{cs} isn't yet defined it will be initialised as empty. The variants
+ behave similarly to their |\def|, |\edef|, |\gdef|, and |\xdef| counterparts,
+ but will allow you to store macro parameters inside them without needing to
+ double them. So |estore foo = \foo, initial foo = #1| will not result in a low
+ level \TeX\ error.
+\end{function}
+\begin{example}
+ {Also store the \val\ of an existing \key\ in a macro using the
+ \texttt{also} \prefix\ and the \texttt{store} \type}
+ Not only do we want to count the tokens handed to |foo|, but we want to also
+ store them inside of a macro (and we don't need to specify |long| here, since
+ |foo| is already |\long| from our |code| definition above).
+ \begin{enverb}
+ ,also store foo = \examplefoostore
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{data,edata,gdata,xdata}
+ \begin{syntax}
+ data \key\ = \meta{cs} \prefixes2212
+ \end{syntax}
+ \singlecs{foo}
+ This will define a \Vkey\ to store \val\ inside of the control sequence. But
+ unlike the |store| \type\ the macro \meta{cs} will be a switch at the same
+ time, it'll take two arguments and if \meta{key} was used expands to the first
+ argument followed by \val\ in braces, if \key\ was not used \meta{cs} will
+ expand to the second argument (so behave like |\@secondoftwo|). The idea is
+ that with this type you can define a key which should be typeset formatted.
+ The |edata| and |xdata| variants will fully expand \val, the |gdata| and
+ |xdata| variants will store \val\ inside \meta{cs} globally. Juts like with
+ |store| you can use macro parameters without having to double them. The
+ \prefixes\ only affect the key-macro, \meta{cs} will always be expandable and
+ |\long|.
+\end{function}
+\begin{example}{Define a key using the \texttt{data} \type}
+ Next we start to define other keys, now that our |foo| is pretty much
+ exhausted. The following defines a key |bar| to be a |data| key.
+ \begin{enverb}
+ ,data bar = \examplebar
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{dataT,edataT,gdataT,xdataT}
+ \begin{syntax}
+ dataT \key\ = \meta{cs} \prefixes2212
+ \end{syntax}
+ Just like |data|, but instead of \meta{cs} grabbing two arguments it'll only
+ grab one, so by default it'll behave like |\@gobble|, and if \val\ was given
+ to \key\ the \meta{cs} will behave like |\@firstofone| appended by
+ \marg{value}.
+\end{function}
+\begin{example}{Define a key using the \texttt{dataT} \type}
+ Another key we want to use is |baz|.
+ \begin{enverb}
+ ,dataT baz = \examplebaz
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{int,eint,gint,xint}
+ \begin{syntax}
+ int \key\ = \meta{cs} \prefixes2212
+ \end{syntax}
+ \singlecs{foo}
+ An |int| key will be a \Vkey\ setting a \TeX\ count register. If \meta{cs}
+ isn't defined yet, |\newcount| will be used to initialise it. The |eint| and
+ |xint| variants will use |\numexpr| to allow basic computations in their \val.
+ The |gint| and |xint| variants set the register globally.
+\end{function}
+
+\begin{function}[module=expkv-def type]{dimen,edimen,gdimen,xdimen}
+ \begin{syntax}
+ dimen \key\ = \meta{cs} \prefixes2212
+ \end{syntax}
+ \singlecs{foo}
+ This is just like |int| but uses a dimen register, |\newdimen|, and |\dimexpr|
+ instead.
+\end{function}
+
+\begin{function}[module=expkv-def type]{skip,eskip,gskip,xskip}
+ \begin{syntax}
+ skip \key\ = \meta{cs} \prefixes2212
+ \end{syntax}
+ \singlecs{foo}
+ This is just like |int| but uses a skip register, |\newskip|, and |\glueexpr|
+ instead.
+\end{function}
+\begin{example}
+ {Define keys that use \TeX\ registers, here a skip with the \texttt{eskip}
+ \type}
+ Exemplary for the different register keys, the following defines |distance| so
+ that we can store some distance.
+ \begin{enverb}
+ ,eskip distance = \exampledistance
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{toks,gtoks,apptoks,gapptoks,pretoks,gpretoks}
+ \begin{syntax}
+ toks \key\ = \meta{cs} \prefixes2212
+ \end{syntax}
+ \singlecs{foo}
+ Store \val\ inside of a toks-register. The |g| variants use |\global|, the
+ |app| variants append \val\ to the contents of that register, the |pre|
+ variants will prepend \val. If \meta{cs} is not yet defined it will be
+ initialised with |\newtoks|.
+\end{function}
+
+\begin{function}[module=expkv-def type]{box,gbox}
+ \begin{syntax}
+ box \key\ = \meta{cs} \prefixes2212
+ \end{syntax}
+ \singlecs{foo}
+ Typesets \val\ into a |\hbox| and stores the result in a box register. The
+ boxes are colour safe. \expkvd\ currently doesn't provide a |vbox| type.
+\end{function}
+
+\begin{function}[module=expkv-def type]{meta}
+ \begin{syntax}
+ meta \key\ = \kvarg \prefixes2222
+ \end{syntax}
+ This key \type\ can set other keys, you can access the \val\ given to the
+ created \Vkey\ inside the \kv\ list using |#1|. This works by injecting the
+ \kv\ list into the currently parsed list, so behaves just as if the \kv\ list
+ was directly used instead of \key.
+\end{function}
+\begin{example}
+ {Define a \Vkey\ as a shortcut to set multiple other keys with the
+ \texttt{meta} \type}
+ And we want to set a full set of keys with just this single one called |all|.
+ \begin{enverb}
+ ,meta all =
+ {distance=5pt,baz=cheese cake,bar=cocktail bar,foo={#1}}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{nmeta}
+ \begin{syntax}
+ nmeta \key\ = \kvarg \prefixes2223
+ \end{syntax}
+ This \type\ sets other keys, but unlike |meta| this defines a \Nkey, so the
+ \kv\ list is static.
+\end{function}
+\begin{example}
+ {Set multiple other keys from a \Nkey\ with the \texttt{nmeta} \type}
+ and if |all| is set without a value we want to do something about it as well.
+ \begin{enverb}
+ ,nmeta all =
+ {distance=10pt,baz=nothing,bar=Waikiki bar,foo}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{smeta}
+ \begin{syntax}
+ smeta \key\ = \marg{set}\kvarg \prefixes2222
+ \end{syntax}
+ Yet another |meta| variant. |smeta| will define a \Vkey, you can access the
+ given \val\ in the provided \kv\ list using |#1|. Unlike |meta| this will
+ process that \kv\ list inside of \meta{set} using a nested |\ekvset| call, so
+ this is equal to \texttt{\cs[no-index]{ekvset}\marg{set}\kvarg}. As a
+ result you can't use |\ekvsneak| using keys or similar macros in the way you
+ normally could.
+\end{function}
+
+\begin{function}[module=expkv-def type]{snmeta}
+ \begin{syntax}
+ snmeta \key\ = \marg{set}\kvarg \prefixes2223
+ \end{syntax}
+ And the last |meta| variant. |snmeta| combines |smeta| and |nmeta|, so parses
+ the \kv\ list inside of \meta{set} and defines a \Nkey\ with a static list.
+\end{function}
+
+\begin{function}[module=expkv-def type]{set}
+ \begin{syntax}
+ set \key\ = \marg{set} \prefixes2233
+ set \key
+ \end{syntax}
+ This will define a \Nkey\ that will change the current set to \meta{set}. If
+ you give no value to this definition (omit |= |\marg{set}) the set name will
+ be the same as \key\ so
+ |set |\key\
+ is equivalent to
+ |set |\key| = |\marg{key}.
+ Note that just like in \expkv\ it'll not be checked whether \meta{set} is
+ defined and you'll get a low-level \TeX\ error if you use an undefined
+ \meta{set}.
+\end{function}
+
+\begin{function}[module=expkv-def type]{choice}
+ \begin{syntax}
+ choice \key\ = \{\val=\meta{definition}, \ldots\} \prefixes2223
+ \end{syntax}
+ |choice| defines a \Vkey\ that will only accept a limited set of values. You
+ should define each possible \meta{value} inside of the \val=\meta{definition}
+ list. If a defined \meta{value} is passed to \meta{key} the \meta{definition}
+ will be left in the input stream. You can make individual values |protected|
+ inside the \val=\meta{definition} list by using that \prefix. To also allow
+ choices that shouldn't be |\protected| but which start with the word
+ |protected| you can also use |unprotected| as a special \prefix. By default a
+ |choice| key and all its choices are expandable, an undefined \meta{value}
+ will throw an error in an expandable way. You can add additional choices after
+ the \meta{key} was created by using |choice| again for the same \key,
+ redefining choices is possible the same way, but there is no interface to
+ remove certain choices. To change the behaviour of unknown choices see also
+ the |unknown-choice| \type.
+\end{function}
+\begin{example}
+ {Define a choice with arbitrary code using the \texttt{choice} \type}
+ We give the users a few choices.
+ \begin{enverb}
+ ,choice choose =
+ {
+ protected lemonade = \def\exampledrink{something sour}
+ ,protected water = \def\exampledrink{something boring}
+ }
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{choice-store}
+ \begin{syntax}
+ choice-store \key\ = \meta{cs}\{\val=\meta{definition}, \ldots\} \prefixes2223
+ \end{syntax}
+ \singlecs{foo}
+ This is a special \type\ of the |choice| \type\ that'll store the given choice
+ inside the macro \meta{cs}. Since storing inside a macro can't be done
+ expandably every choice-code is |\protected|, and you might define the
+ |choice-store| key itself as |\protected| as well if you want. Inside the
+ \val|=|\meta{definition} list the |=|\meta{definition} part is optional, if
+ you omit it the \val\ will be stored as given during define-time inside of
+ \meta{cs} (during use-time the \val\ needs to be matched |\detokenize|d), and
+ if you specify |=|\meta{definition} that \meta{definition} will be stored
+ inside of \meta{cs} instead. If \meta{cs} doesn't yet exist it's initialised
+ as empty.
+\end{function}
+\begin{example}
+ {Show the equivalent setup for a \texttt{choice} \type\ to mimic a
+ \texttt{choice-store} \type}
+ The following keys |key1| and |key2| are equivalent at use time (this doesn't
+ continue the |\ekvdefinekeys|-call for the set |example| above):
+ \begin{enverb}[no-store,no-tcb]
+ \newcommand*\mya{}% initialise \mya
+ \ekvdefinekeys{choice-store-example}
+ {
+ choice key1 =
+ {
+ protected a = \def\mya{a}
+ ,protected b = \def\mya{b}
+ ,protected c = \def\mya{c}
+ ,protected d = \def\mya{FOO}
+ }
+ ,choice-store key2 = \myb{a,b,c,d=FOO}
+ }
+ \end{enverb}
+\end{example}
+\begin{example}
+ {Store the user's choices in a macro with the \texttt{choice-store} \type}
+ (this continues the |\ekvdefinekeys|-call for the set |example| from above)
+ After the above drinks we define a few more choices which are directly stored.
+ \begin{enverb}
+ ,choice-store choose = \exampledrink{beer,wine}
+ \end{enverb}
+ One might notice that the entire setup of the |choose| key could've been done
+ using only |choice-store|.
+\end{example}
+
+\begin{function}[module=expkv-def type]{choice-enum}
+ \begin{syntax}
+ choice-enum \key\ = \meta{cs}\{\val, \ldots\} \prefixes2223
+ \end{syntax}
+ \singlecs{foo}
+ This is similar to |choice-store|, the differences are: \meta{cs} should be a
+ count register or is initialised as such using |\newcount|; instead of the
+ \val\ itself being stored its position in the list of choices is stored
+ (zero-based). It is not possible to specify a \meta{definition} to store
+ something else than the numerical position inside the list.
+\end{function}
+\begin{example}
+ {Show the equivalent setup for a \texttt{choice} \type\ to mimic a
+ \texttt{choice-enum} \type}
+ The following keys |key1| and |key2| are equivalent at use time (another
+ example not using the |example| set of above's |\ekvdefinekeys|):
+ \begin{enverb}[no-store,no-tcb]
+ \newcount\myc
+ \ekvdefinekeys{choice-enum-example}
+ {
+ choice key1 =
+ {
+ protected a={\myc=0 }
+ ,protected b={\myc=1 }
+ ,protected c={\myc=2 }
+ }
+ ,choice-enum key2 = \myd{a,b,c}
+ }
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{unknown-choice}
+ \begin{syntax}
+ unknown-choice \key\ = \marg{definition} \prefixes2323
+ \end{syntax}
+ By default an unknown \val\ passed to a |choice| or |bool| \type\ (and all
+ their variants) will throw an error. However, with this prefix you can define
+ an alternative action which should be executed if \key\ received an unknown
+ choice. In \meta{definition} you can refer to the given invalid choice with
+ |#1|.
+\end{function}
+\begin{example}
+ {Handle unknown choices without throwing an error with the
+ \texttt{unknown-choice} \type}
+ If a drink was chosen with |choose| that's not defined we don't want to throw
+ an error, but store something else instead.
+ \begin{enverb}
+ ,protected unknown-choice choose =
+ \def\exampledrink{something unavailable}
+ }% closing brace for \ekvdefinekeys
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=expkv-def type]{unknown code}
+ \begin{syntax}
+ unknown code = \marg{definition} \prefixes2322
+ \end{syntax}
+ By default \expkv\ throws errors when it encounters unknown keys in a set.
+ With the |unknown| \type\ you can define handlers that deal with undefined
+ keys, instead of a \key\ name you have to specify a subtype for this, here the
+ subtype is |code|.
+
+ With |unknown code| the \meta{definition} is used for unknown keys which were
+ provided a value (so corresponds to |\ekvdefunknown|), you can access the
+ unknown \key\ name with |#1| (|\detokenize|d), the given \val\ with |#2|, and
+ the unprocessed \key\ name with |#3| (in case you want to further expand
+ it).\footnotemark
+\end{function}%
+\footnotetext{There is some trickery involved to get this more intuitive
+argument order without any performance hit if you compare this to
+\cs[no-index]{ekvdefunknown} directly}
+
+\begin{function}[module=expkv-def type]{unknown noval}
+ \begin{syntax}
+ unknown noval = \marg{definition} \prefixes2323
+ \end{syntax}
+ This is like |unknown code| but uses \meta{definition} for unknown keys to
+ which no value was passed (so corresponds to |\ekvdefunknownNoVal|). You can
+ access the |\detokenize|d \key\ name with |#1| and the unprocessed one with
+ |#2|.
+\end{function}
+
+\begin{function}[module=expkv-def type]{unknown redirect-code}
+ \begin{syntax}
+ unknown redirect-code = \marg{set-list} \prefixes2331
+ \end{syntax}
+ This uses a predefined action for |unknown code|. Instead of throwing an
+ error, it is tried to find the \meta{key} in each \meta{set} in the comma
+ separated \meta{set-list}. The first found match will be used and the
+ remaining options from the list discarded. If the \meta{key} isn't found in
+ any \meta{set} an expandable error will be thrown eventually. Internally
+ \expkv's |\ekvredirectunknown| will be used.
+\end{function}
+
+\begin{function}[module=expkv-def type]{unknown redirect-noval}
+ \begin{syntax}
+ unknown redirect-noval = \marg{set-list} \prefixes2333
+ \end{syntax}
+ This behaves just like |unknown redirect-code| but will set up means to
+ forward keys for |unknown noval|. Internally \expkv's
+ |\ekvredirectunknownNoVal| will be used.
+\end{function}
+
+\begin{function}[module=expkv-def type]{unknown redirect}
+ \begin{syntax}
+ unknown redirect = \marg{set-list} \prefixes2333
+ \end{syntax}
+ This is a short cut to apply both, |unknown redirect-code| and
+ |unknown redirect-noval|, as a result you might get doubled error messages,
+ one from each.
+\end{function}
+
+\bigskip
+Time to use all those keys defined in the different examples!
+% undo the global no-tcb setting
+\ekvset{enverb}{no-store,undo-no-tcb}%
+\begin{enverb}[restore,below,inter=Which results in three paragraphs of text:]
+ \newcommand\defexample[1][]
+ {%
+ \ekvset{example}{#1}%
+ After walking \the\exampledistance\space we finally reached
+ \examplebar{\emph}{no particular place}.
+ There I ordered
+ \iffoo
+ a drink called \examplefoostore\space (that has
+ \the\examplefoocount\space tokens in it)%
+ \else
+ nothing of particular interest%
+ \fi
+ \examplebaz{ and ate \emph}.
+ Then a friend of mine also chose \exampledrink.
+ \par
+ }
+ \defexample[nofoo]
+ \defexample[all,choose=lemonade]
+ \defexample
+ [all=wheat beer,bar=Biergarten,baz=pretzel,choose=champagne]
+\end{enverb}
+
+\subsection{Another Example}
+
+This picks up the standard use case from \autoref{sec:expkv:standard}, but
+defines the keys using |\ekvdefinekeys|.
+
+\begin{enverb}
+ \makeatletter
+ \ekvdefinekeys{myrule}
+ {
+ store ht = \myrule@ht
+ ,initial ht = 1ex
+ ,store wd = \myrule@wd
+ ,initial wd = 0.1em
+ ,store raise = \myrule@raise
+ ,initial raise = \z@
+ ,meta lower = {raise={-#1}}
+ }
+ \ekvsetdef\myruleset{myrule}
+ \newcommand*\myrule[1][]
+ {%
+ \begingroup
+ \myruleset{#1}%
+ \rule[\myrule@raise]{\myrule@wd}{\myrule@ht}%
+ \endgroup
+ }
+ \makeatother
+ a\myrule\par
+ a\myrule[ht=2ex,lower=.5ex]\par
+ \myruleset{wd=5pt}
+ a\myrule
+\end{enverb}
diff --git a/macros/generic/expkv-bundle/pkg-main.tex b/macros/generic/expkv-bundle/pkg-main.tex
new file mode 100644
index 0000000000..0109eb70da
--- /dev/null
+++ b/macros/generic/expkv-bundle/pkg-main.tex
@@ -0,0 +1,1097 @@
+\genericekv\expkv{}
+
+This package supports two different front ends to parse a \kv\ list. The first
+(|\ekvset|) is similar to \pkg{keyval}'s |\setkeys|, it parses the list and
+executes defined actions based on the encountered \key{}s. The second
+(|\ekvparse|) is more versatile, it only splits the list into \key{}s and
+\val{}s and then runs user-provided code on the result.
+
+The first is described in subsections~\ref{sec:expkv:setup}
+to~\ref{sec:expkv:set}, the latter is described in \autoref{sec:expkv:parse}.
+
+Unlike the other packages in the bundle, if you load \expkv\ as a \LaTeXe\
+package there is a single option available:
+\begin{function}{all}
+ \begin{syntax}
+ \cs[no-index]{usepackage}[all]\{expkv\}
+ \end{syntax}
+ Loads all the packages of \expkvbundle.
+\end{function}
+
+\subsection{General Parsing Rules}
+
+\expkv\ parses a \kv\ list by first splitting the elements on commas (active or
+other), then looking for an equals sign (active or other). If there is one the
+\kv\ pair will be split at the first. From both \key\ and \val\ (if there was a
+\val) one set of outer spaces is stripped, and afterwards one set of outer
+braces (meaning braces which are around the complete remainder after space
+stripping if there are any).
+
+So the syntax looks something like the following pseudo-input:
+\begin{syntaxexample}
+ \vissp{ \marg{key} = \marg{value} }
+\end{syntaxexample}
+with the displayed spaces and braces being optional and removed if found. Note
+that if you want either \key\ or \val\ to include a comma the braces become
+mandatory, the same is true if \key\ should contain an equals sign.
+
+\subsubsection{Expansion Control\label{sec:expkv:expansion}}
+
+\expkv\ provides a mechanism to specify expansions of a \key\ and/or \val. For
+those familiar with \pkg{pgfkeys} this is similar to its |.expand once| or
+|.expanded| handlers. This concept will be called \expnotation\ or \expansion\
+throughout this documentation.
+
+The syntax for this notation is a leading list of \expansion-rules followed by a
+colon that is immediately followed by a space. Also the \expansion-rules must
+not contain any spaces outside of braces, and the remainder on the right hand
+side of the colon must not be blank, else it is not considered an \expnotation\
+but just a weirdly formed \key-name.
+
+The entire syntax of a \kv\ pair is
+\begin{syntaxexample}
+ \vissp{ \{\expansion: \asciispace\marg{key} \} = \marg{value} }
+\end{syntaxexample}
+Note that the \expansion\ prefix is right delimited by \verb*|: | so the space
+after the colon is only optional in the sense that the entire \expansion\ prefix
+is optional. Else all displayed spaces and braces are optional, the inner set of
+spaces and braces around \key\ only being optional if the optional \expansion\
+prefix (\expansion\verb*|: |) was present. If that part was present the list of
+\expansion-rules will be executed, which might change the contents of both \key\
+and \val. For |\ekvparse| this is always true, however in |\ekvset| it is only
+parsed for the \expnotation\ if there is no \key\ matching the given input (so
+this notation doesn't impose a restriction on key names, though \key-names
+actually containing what would otherwise be an \expansion\ prefix should be
+pretty rare in practice).
+
+All packages in \expkvbundle\ support this notation (most of them internally use
+|\ekvset| or |\ekvparse|). Please note however that while \expkvo\ fully
+supports them, reinsertion via the |\r| \expansion-rule might affect the unused
+global options list if used in the class options.
+
+An \expansion-rule consists of a single token. In a \Vkey\ they work on the
+\val\ (but you can use the |\key| rule to also affect the \key\ there) while in
+a \Nkey\ they work on the \key. The following rules are available (those
+familiar with \pkg{expl3} will notice that the first six are identical to its
+argument types):
+
+\begingroup
+\let\bigskip\medskip
+\begin{function}[module=Expansion]{o}
+ Expands the first token once.
+\end{function}
+
+\begin{function}[module=Expansion]{e}
+ Expands the entire \val\ inside of |\expanded|.
+\end{function}
+
+\begin{function}[module=Expansion]{c}
+ Builds a |\csname| from the contents.
+\end{function}
+
+\begin{function}[module=Expansion]{f}
+ Expands the contents until a space or an unexpandable token is found (the
+ space would be removed).
+\end{function}
+
+\begin{function}[module=Expansion]{V}
+ The \val\ should be a single token, either defined as a parameterless macro or
+ as a register (via |\newcount| etc.). This expands to the value of the
+ register or the macro's replacement text. If the token in \val\ has the
+ |\meaning| of |\relax| an error is thrown and the result is empty.
+\end{function}
+
+\begin{function}[module=Expansion]{v}
+ This is a combination of |c| and |V|, meaning the \val\ is turned into a
+ single control sequence via |\csname|, and then expanded to its value. The
+ control sequence will only be built if it's defined.
+\end{function}
+\begin{example}{The difference between \texttt{co} and \texttt{v} expansion}
+ Say we want to hand the contents of a macro as the value to our key, but the
+ actual macro name depends on user input. For this we have two options which
+ behave slightly different. One is to use |v| the other is to combine the |co|
+ \expansion-rules. The following demonstrates both (I modified the way errors
+ are thrown to instead output them in red for this; you'll learn about
+ |\ekvparse| in a few pages, for now just stick with me):
+ \expkvdocPrintErrors
+ \makeatletter
+ \begin{enverb}[below]
+ \newcommand\mypair[2]{Arg: `\detokenize{#2}'. }%
+ \newcommand\myvalue{Value}%
+ \ekvparse\@firstofone\mypair
+ {
+ co: key = myvalue, v: key = myvalue, \par
+ ,co: key = myValue, v: key = myValue, \par
+ }
+ \end{enverb}
+ The difference is that in |co| the variable is implicitly initialised as
+ |\relax| by |c| if it doesn't exist and then doesn't expand in |o|. On the
+ other hand |v| will check whether the variable would exist and throw an error
+ if it doesn't (and will not set it to |\relax| by blindly using |\csname|).
+\end{example}
+
+\begin{function}[module=Expansion]{s}
+ Strips one set of outer spaces and outer braces.
+\end{function}
+
+\begin{function}[module=Expansion]{b}
+ Adds one set of outer braces.
+\end{function}
+
+\begin{function}[module=Expansion]{p}
+ \begin{syntax}
+ p\marg{contents}
+ \end{syntax}
+ Places \meta{contents} before the \val.
+\end{function}
+
+\begin{function}[module=Expansion]{P}
+ \begin{syntax}
+ P\marg{contents}
+ \end{syntax}
+ Places \meta{contents} after the \val.
+\end{function}
+
+\begin{function}[module=Expansion]{g}
+ Gobbles the first token or balanced group on the left (leads to a low-level
+ \TeX-error if the \val\ is empty).
+\end{function}
+
+\begin{function}[module=Expansion]{\r}
+ In a \Vkey\ reinserts the contents of \val\ after all the \expansion-rules
+ were executed (the \key-name needs to be empty). In a \Nkey\ the contents of
+ \key\ are reinserted after all the \expansion-rules were executed (the \val\
+ needs to be empty, which is an easy to fulfil rule as there was no \val).
+ Normal \kv\ parsing is aborted afterwards for the current \kv\ list element.
+\end{function}
+\begin{example}{Parse the contents of a macro as additional \kv\ input}
+ Say we want to store a list of common settings in a macro, then we want to
+ parse a few keys, insert the contents of the macro, and parse a few more keys.
+ The following does exactly that (|\ekvset| is analogue to |\setkeys| of the
+ \pkg{keyval} package if you're familiar with it, else you'll learn about
+ |\ekvset| a few pages down the road so be patient):
+ \begin{enverb}[no-tcb]
+ \newcommand*\mykeylist{color=red,height=5cm}
+ \ekvset{mypkg}{key=value, o\r: \mykeylist, other key=other value}
+ \end{enverb}
+ You could also use the following with the same outcome, but this looks more
+ complicated so the other form should be preferred:
+ \begin{enverb}[no-tcb]
+ \ekvset{mypkg}{key=value, o\r: {}=\mykeylist, other key=other value}
+ \end{enverb}
+\end{example}
+
+\begin{function}[module=Expansion]{\key}
+ \begin{syntax}
+ \cs[module=Expansion]{key}\marg{expansion}
+ \end{syntax}
+ This is the only supported way to change the contents of \key\ for a \Vkey\ in
+ the \expnotation. All the rules in \expansion\ are applied to \key\ instead of
+ \val.
+\end{function}
+
+\begin{function}[module=Expansion]{R}
+ This is the same as if you used |V\r|. So it expects a single token, retrieves
+ its value, and reinserts this as additional \kv\ input.
+\end{function}
+
+\begin{function}[module=Expansion]{r}
+ This is the same as if you used |v\r|. So it builds a |\csname| if that is
+ defined, retrieves its value, and reinserts this as additional \kv\ input.
+\end{function}
+\begin{example}
+ {Parse the contents of a macro as additional \kv\ input (revisited)}
+ Now that we also know the |R| and |r| rule, the example above can be input
+ even simpler:
+ \begin{enverb}[no-tcb]
+ \ekvset{mypkg}{key=value, R: \mykeylist, other key=other value}
+ \end{enverb}
+ or
+ \begin{enverb}[no-tcb]
+ \ekvset{mypkg}{key=value, r: mykeylist, other key=other value}
+ \end{enverb}
+\end{example}
+\endgroup
+
+\subsection{Setting up Keys\label{sec:expkv:setup}}
+
+\expkv\ provides a rather simple approach to setting up keys, similar to
+\pkg{keyval}. If you're looking for a more sophisticated interface similar to
+those of \pkg{l3keys} or \pkg{pgfkeys} take a look at \expkvd\ described in
+\autoref{sec:expkv-def} or for a simple interface that defines expandable macros
+at \expkvc\ described in \autoref{sec:expkv-cs}.
+
+Keys in \expkv\ (as in many other \kv\ implementations) belong to a \emph{set},
+so that different sets can contain keys of the same name. Unlike many other
+implementations \expkv\ doesn't provide means to set a default value, instead we
+have keys that take a value (we call those \Vkey) and keys that don't (which are
+called \Nkey\ by \expkv), but both can share the same name on the user level,
+the only difference for the user is whether =\val\ was used or not.
+
+The following macros are available to define new keys. Those macros containing
+\enquote{\texttt{def}} in their name can be prefixed by anything allowed to
+prefix |\def| (but \emph{don't} use |\outer|, keys defined with it won't ever be
+usable). And prefixes allowed for |\let| can prefix those macros with
+\enquote{\texttt{let}} in their name, accordingly. Neither \set\ nor \key\ are
+allowed to be empty for new keys. \set\ will be used as is inside of
+|\csname ...\endcsname| and \key\ will get |\detokenize|d. Also \set\ should not
+contain an explicit |\par| token.
+
+\begin{function}{\ekvdef}
+ \begin{syntax}
+ \cs{ekvdef}\marg{set}\marg{key}\marg{code}
+ \end{syntax}
+ Defines a \Vkey\ in a \set\ to expand to \meta{code}. In \meta{code} you can
+ use |#1| to refer to the given \val.
+\end{function}
+\begin{example}{Define a single \Vkey}
+ Define |text| in |foo| to store the \val\ inside |\foo@text|:
+ \begin{enverb}[no-tcb]
+ \protected\long\ekvdef{foo}{text}{\def\foo@text{#1}}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvdefNoVal}
+ \begin{syntax}
+ \cs{ekvdefNoVal}\marg{set}\marg{key}\marg{code}
+ \end{syntax}
+ Defines a \Nkey\ in \set\ to expand to \meta{code}.
+\end{function}
+\begin{example}{Define a single \Nkey}
+ Define |bool| in |foo| to set |\iffoo@bool| to |true|:
+ \begin{enverb}[no-tcb]
+ \protected\ekvdefNoVal{foo}{bool}{\foo@booltrue}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvlet}
+ \begin{syntax}
+ \cs{ekvlet}\marg{set}\marg{key}\meta{cs}
+ \end{syntax}
+ Let the \Vkey\ in \set\ to \meta{cs}. There are no checks on \meta{cs}
+ enforced, but the code should expect the \val\ as a single braced argument
+ directly following it.
+\end{function}
+\begin{example}{Copy a macro to define a \Vkey}
+ Let |cmd| in |foo| do the same as |\foo@cmd|:
+ \begin{enverb}[no-tcb]
+ \ekvlet{foo}{cmd}\foo@cmd
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvletNoVal}
+ \begin{syntax}
+ \cs{ekvletNoVal} \marg{set} \marg{key} \meta{cs}
+ \end{syntax}
+ Let the \Nkey\ in \set\ to \meta{cs}. Again no checks on \meta{cs} are done.
+ It shouldn't expect any provided argument.
+\end{function}
+\begin{example}{Copy a macro to define a \Nkey}
+ See above.
+\end{example}
+
+\begin{function}{\ekvletkv}
+ \begin{syntax}
+ \cs{ekvletkv}\marg{set}\marg{key}\marg{set2}\marg{key2}
+ \end{syntax}
+ Copies the definition such that \Vkey\ in \set\ behaves like \meta{key2} of
+ \meta{set2}. It is not checked whether that second key exists!
+\end{function}
+\begin{example}{Copy an existing \Vkey}
+ Let |B| in |bar| do the same as |A| in |foo|:
+ \begin{enverb}[no-tcb]
+ \ekvletkv{bar}{B}{foo}{A}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvletkvNoVal}
+ \begin{syntax}
+ \cs{ekvletkvNoVal}\marg{set}\marg{key}\marg{set2}\marg{key2}
+ \end{syntax}
+ And this lets the \Nkey\ in \set\ to the definition of the |NoVal|-\meta{key2}
+ in \meta{set2}. Again, it is not checked whether the second key exists.
+\end{function}
+\begin{example}{Copy an existing \Nkey}
+ See above.
+\end{example}
+
+\subsection{Handle Unknown Keys}
+
+By default \expkv\ throws an error message if it encounters an undefined \key.
+You can change this behaviour with the macros listed here. Just like in the
+section above, prefixes for |\def| are allowed if the macro has |def| in its
+name, and |\let| prefixes are allowed if the macro is named something with
+|let|.
+
+\begin{function}{\ekvdefunknown}
+ \begin{syntax}
+ \cs{ekvdefunknown}\marg{set}\marg{code}
+ \end{syntax}
+ Execute \meta{code} if an undefined \Vkey\ is encountered while parsing in
+ \set. You can refer to the given \val\ with |#1|, the unknown \key's name
+ with |#2| (will be |\detokenize|d), and to the \key's name without
+ |\detokenize| applied with |#3| in \meta{code} (this order is chosen for
+ performance reasons).
+
+ \cs{ekvdefunknown} and \cs{ekvredirectunknown} are mutually exclusive, you
+ can't use both.
+\end{function}
+\begin{example}{Search undefined \Vkey{}s in another \set}
+ Also search |bar| for undefined keys of set |foo| (and use the not yet
+ |\detokenize|d \key's name in case the undefined key handler of |bar| needs
+ that):
+ \begin{enverb}[no-tcb]
+ \long\ekvdefunknown{foo}{\ekvset{bar}{{#3}={#1}}}
+ \end{enverb}
+ This example differs from using |\ekvredirectunknown{foo}{bar}| (see below) in
+ that also the unknown-key handler of the |bar| set will be triggered, error
+ messages for undefined keys will look different, and this is slower than using
+ \cs{ekvredirectunknown}.
+\end{example}
+
+\begin{function}{\ekvdefunknownNoVal}
+ \begin{syntax}
+ \cs{ekvdefunknownNoVal}\marg{set}\marg{code}
+ \end{syntax}
+ With this you can let \expkv\ execute \meta{code} if an unknown \Nkey\ was
+ encountered. You can refer to the given \key\ with |#1| (will be
+ |\detokenize|d), and to the not |\detokenize|d \key's name with |#2|.
+
+ \cs{ekvdefunknownNoVal} and \cs{ekvredirectunknownNoVal}
+ are mutually exclusive, you can't use both.
+\end{function}
+\begin{example}{Search undefined \Nkey{}s in another \set}
+ Adding to the above also handling of \Nkey{}s in |foo|:
+ \begin{enverb}[no-tcb]
+ \ekvdefunknownNoVal{foo}{\ekvset{bar}{{#2}}}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvredirectunknown}
+ \begin{syntax}
+ \cs{ekvredirectunknown}\marg{set}\marg{set-list}
+ \end{syntax}
+ This is a short cut to set up a special \cs{ekvdefunknown}-rule for \set\ that
+ will check each set in the comma separated \meta{set-list} for an unknown
+ \Vkey. The resulting unknown-key handler will always be |\long| and \emph{not}
+ |\protected|. The first set in \meta{set-list} has highest priority, once the
+ \Vkey\ is found in one of the sets the remainder of the list is discarded. If
+ \meta{key} isn't found in any of the sets an error will be thrown eventually.
+ Note that the error message looks different than a normal key-not-found error,
+ in particular no unwanted-value message can be thrown (it will not be checked
+ if a \Nkey\ of the same name does exist), and the error message will contain
+ all sets.
+
+ \cs{ekvdefunknown} and \cs{ekvredirectunknown}
+ are mutually exclusive, you can't use both.
+\end{function}
+\begin{example}{Search an undefined \Vkey\ in a list of other \set{}s}
+ For every undefined \Vkey\ in |foo| also search the sets |bar| and |baz|:
+ \begin{enverb}[no-tcb]
+ \ekvredirectunknown{foo}{bar, baz}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvredirectunknownNoVal}
+ \begin{syntax}
+ \cs{ekvredirectunknownNoVal}\marg{set}\marg{set-list}
+ \end{syntax}
+ This behaves just like \cs{ekvredirectunknown}, it does the same but for
+ \Nkey{}s. Again no prefixes are supported (the result will neither be |\long|
+ nor |\protected|). Note that the error messages will not check whether a
+ missing-value error should be thrown.
+
+ \cs{ekvdefunknownNoVal} and \cs{ekvredirectunknownNoVal}
+ are mutually exclusive, you can't use both.
+\end{function}
+\begin{example}{Search an undefined \Nkey\ in a list of other \set{}s}
+ See above.
+\end{example}
+
+\begin{function}{\ekvletunknown}
+ \begin{syntax}
+ \cs{ekvletunknown}\marg{set}\meta{cs}
+ \end{syntax}
+ This lets the handler for unknown \Vkey{}s to \meta{cs}. \meta{cs} should
+ expect three arguments, the first will be the \val\ the second the
+ |\detokenize|d \key-name, the third the unprocessed \key-name. No conditions
+ on \meta{cs} are enforced.
+\end{function}
+\begin{example}
+ {Do the same as an already defined macro if an unknown \Vkey\ is found}
+ Let the set |foo| do the same as the macro |\foo@unknown| whenever an unknown
+ \Vkey\ is encountered:
+ \begin{enverb}[no-tcb]
+ \ekvletunknown{foo}\foo@unknown
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvletunknownNoVal}
+ \begin{syntax}
+ \cs{ekvletunknownNoVal}\marg{set}\meta{cs}
+ \end{syntax}
+ This does the same as \cs{ekvletunknown} but for \Nkey{}s. The \meta{cs}
+ should expect two arguments, namely the |\detokenize|d \key\ and the
+ unprocessed \key.
+\end{function}
+\begin{example}{Silently ignore unknown \Nkey{}s}
+ Let the set |foo| ignore unknown \Nkey{}s by gobbling the \key-name:
+ \begin{enverb}[no-tcb]
+ \ekvletunknownNoVal{foo}\@gobbletwo
+ \end{enverb}
+\end{example}
+
+\subsection{Helpers in Actions}
+
+\begin{function}{\ekvifdefined,\ekvifdefinedNoVal}
+ \begin{syntax}
+ \cs{ekvifdefined}\marg{set}\marg{key}\marg{true}\marg{false}
+ \cs{ekvifdefinedNoVal}\marg{set}\marg{key}\marg{true}\marg{false}
+ \end{syntax}
+ These two macros test whether there is a \key\ in \set. It is false if either
+ a hash table entry doesn't exist for that key or its meaning is |\relax|.
+\end{function}
+\begin{example}{Check if a \Vkey\ is already defined}
+ Check whether the key |special| is already defined in set |foo|, if it isn't
+ input a file that contains more key definitions:
+ \begin{enverb}[no-tcb]
+ \ekvifdefined{foo}{special}{}{\input{foo.morekeys.tex}}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvifdefinedset}
+ \begin{syntax}
+ \cs{ekvifdefinedset}\marg{set}\marg{true}\marg{false}
+ \end{syntax}
+ This macro tests whether \set\ is defined (which it is if at least one key was
+ defined for it). If it is \meta{true} will be run, else \meta{false}.
+\end{function}
+\begin{example}{Check if a \set\ is already defined}
+ Check whether the set |VeRyUnLiKeLy| is already defined, if so throw an error,
+ else do nothing:
+ \begin{enverb}[no-tcb]
+ \ekvifdefinedset{VeRyUnLiKeLy}
+ {\errmessage{VeRyUnLiKeLy already defined}}{}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvsneak,\ekvsneakPre}
+ \begin{syntax}
+ \cs{ekvsneak}\marg{after}
+ \end{syntax}
+ Puts \meta{after} after the effects of \cs{ekvset} (without cancelling the
+ current \cs{ekvset} call). The first variant will put \meta{after} after any
+ other tokens which might have been sneaked before, while \cs{ekvsneakPre} will
+ put \meta{after} before other smuggled stuff. After \cs{ekvset} has parsed the
+ entire \kv\ list everything that has been \cs{ekvsneak}ed will be left in the
+ input stream.
+\end{function}
+\begin{example}{Execute code after \cs[no-index]{ekvset} if a \Nkey\ was used}
+ Define a key |secret| in the set |foo| that will sneak out
+ |\foo@secretly@sneaked|:
+ \begin{enverb}[no-tcb]
+ \ekvdefNoVal{foo}{secret}{\ekvsneak{\foo@secretly@sneaked}}
+ \end{enverb}
+\end{example}
+A more elaborate usage example is shown in \autoref{sec:expkv:sneak}.
+
+\begin{function}{\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak}
+ \begin{syntax}
+ \cs{ekvbreak}\marg{after}
+ \end{syntax}
+ Gobbles the remainder of the current \cs{ekvset} call and its argument list
+ and inserts \meta{after}. So this can be used to break out of \cs{ekvset}. The
+ first variant will also gobble anything that has been sneaked out using
+ \cs{ekvsneak} or \cs{ekvsneakPre}, while \cs{ekvbreakPreSneak} will put
+ \meta{after} before anything that has been smuggled and \cs{ekvbreakPostSneak}
+ will put \meta{after} after the stuff that has been sneaked out.
+\end{function}
+\begin{example}{Stop parsing a \kv\ list if a specific \Nkey\ was used}
+ Define a key |abort| that will stop key parsing inside the set |foo| and
+ execute |\foo@aborted|, or if it got a value |\foo@aborted@with|:
+ \begin{enverb}[no-tcb]
+ \ekvdefNoVal{foo}{abort}{\ekvbreak{\foo@aborted}}
+ \ekvdef{foo}{abort}{\ekvbreak{\foo@aborted@with{#1}}}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvmorekv}
+ \begin{syntax}
+ \cs{ekvmorekv}\kvarg
+ \end{syntax}
+ Adds the contents of the \kv\ list to the list processed by the current call
+ of |\ekvset|.
+\end{function}
+\begin{example}{Use one \key\ to set multiple other keys}
+ Define a \Nkey\ |style| that sets the keys |border|, |width|, and |height| as
+ a shortcut:
+ \begin{enverb}[no-tcb]
+ \ekvdefNoVal{foo}{style}{\ekvmorekv{border, width=2cm, height=1.5ex}}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvchangeset}
+ \begin{syntax}
+ \cs{ekvchangeset}\marg{new-set}
+ \end{syntax}
+ Replaces the current \set\ with \meta{new-set}, so for the rest of the current
+ \cs{ekvset} call that call behaves as if it was called with
+ \cs{ekvset}\marg{new-set}. It is comparable to using \key|/.cd| in
+ \pkg{pgfkeys}.
+\end{function}
+\begin{example}{Change the current \set}
+ Define a key |cd| in set |foo| that will change to another set as specified in
+ the \val. If the set is undefined it'll stop the parsing and throw an error as
+ defined in the macro |\foo@cd@error|:
+ \begin{enverb}[no-tcb]
+ \ekvdef{foo}{cd}
+ {\ekvifdefinedset{#1}{\ekvchangeset{#1}}{\ekvbreak{\foo@cd@error}}}
+ \end{enverb}
+\end{example}
+
+\subsection{Parsing Keys in Sets}\label{sec:expkv:set}
+
+\begin{function}{\ekvset}
+ \begin{syntax}
+ \cs{ekvset}\marg{set}\kvarg
+ \end{syntax}
+ This macro parses the \kv\ list and checks for defined \key{}s that are in
+ \set. Unlike the generic \cs{ekvparse} this macro uses |\detokenize| on the
+ \key\ before checking whether it is a defined key.
+
+ \cs{ekvset} is nestable, and fully expandable. But it is \emph{not} alignment
+ safe. As a result \key\ names and \val{}s that contain an |&| must be wrapped
+ in braces if \cs{ekvset} is used inside an alignment (like \LaTeXe's |tabular|
+ environment) or alternatively you have to create a wrapper that ensurs an
+ alignment safe context.
+\end{function}
+\begin{example}{Set defined keys using \cs[no-index]{ekvset}}
+ Parse |key=arg, key| in set |foo|:
+ \begin{enverb}[no-tcb]
+ \ekvset{foo}{key=arg, key}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvsetSneaked}
+ \begin{syntax}
+ \cs{ekvsetSneaked}\marg{set}\marg{sneak}\kvarg
+ \end{syntax}
+ This behaves like \cs{ekvset} in which \cs{ekvsneak} was immediately called.
+\end{function}
+\begin{example}
+ {Set defined keys and execute code afterwards using
+ \cs[no-index]{ekvsetSneaked}}
+ Parse |key=arg, key| in the set |foo| with |\afterwards| sneaked out:
+ \begin{enverb}[no-tcb]
+ \ekvsetSneaked{foo}{\afterwards}{key=arg, key}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvsetdef}
+ \begin{syntax}
+ \cs{ekvsetdef}\meta{cs}\marg{set}
+ \end{syntax}
+ Defines the macro \meta{cs} to be a shortcut for \cs{ekvset}\marg{set}. You
+ can use any \TeX-prefix allowed to prefix |\def| for \cs{ekvsetdef} (so
+ |\long|, |\protected|, or |\global| -- don't use |\outer|).
+ The resulting macro is faster than but else equivalent to the idiomatic
+ definition:\par
+ |\def|\meta{cs}|#1{|\cs{ekvset}\marg{set}|{#1}}|
+\end{function}
+\begin{example}
+ {Define a setup command for a defined \set\ using \cs[no-index]{ekvsetdef}}
+ Define the macro |\foosetup| to parse keys in the set |foo| and use it to
+ parse |key=arg, key|:
+ \begin{enverb}[no-tcb]
+ \ekvsetdef\foosetup{foo}
+ \foosetup{key=arg, key}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvsetSneakeddef}
+ \begin{syntax}
+ \cs{ekvsetSneakeddef}\meta{cs}\marg{set}
+ \end{syntax}
+ Just like \cs{ekvsetdef} this defines a shorthand macro \meta{cs}, but this
+ will make it a shorthand for \cs{ekvsetSneaked}, meaning \meta{cs} will take
+ two arguments (first the \cs{ekvsneak} argument, then the \kv\ list). Hence
+ the result is a faster version of:\par
+ |\long\def|\meta{cs}|#1#2{|\cs{ekvsetSneaked}\marg{set}|{#1}{#2}}|
+\end{function}
+\begin{example}
+ {Define a setup command that will also require code to execute after all
+ keys were processed using \cs[no-index]{ekvsetSneakeddef}}
+ Define the macro |\foothings| to parse keys in the set |foo| and accept a
+ sneaked argument, then use it to parse |key=arg, key| and sneak |\afterwards|:
+ \begin{enverb}[no-tcb]
+ \ekvsetSneakeddef\foothings{foo}
+ \foothings{\afterwards}{key=arg, key}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvsetdefSneaked}
+ \begin{syntax}
+ \cs{ekvsetdefSneaked}\meta{cs}\marg{set}\marg{sneaked}
+ \end{syntax}
+ This macro behaves like \cs{ekvsetSneakeddef}, but with a fixed \meta{sneaked}
+ argument. So the resulting macro is faster than but else equivalent to\par
+ |\long\def|\meta{cs}|#1{|\cs{ekvsetSneaked}\marg{set}\marg{sneaked}|{#1}}|
+\end{function}
+\begin{example}
+ {Define a setup command that will execute codes after all keys were
+ processed using \cs[no-index]{ekvsetdefSneaked}}
+ Define the macro |\barthing| to parse keys in the set |bar| and always execute
+ |\afterwards| afterwards, then use it to parse |key=arg, key|:
+ \begin{enverb}[no-tcb]
+ \ekvsetdefSneaked\barthing{bar}{\afterwards}
+ \barthing{key=arg, key}
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvcompile}
+ \begin{syntax}
+ \cs{ekvcompile}\meta{*}\meta{cs}\meta{parameters}\marg{set}\kvarg
+ \end{syntax}
+ This macro defines \meta{cs} to be a \emph{fast} way to set the given \kv\
+ list in \meta{set}. The meaning of the keys is frozen if you don't give the
+ optional |*| (if the star is present the stored content will be the key-macros
+ and later redefinitions of keys will affect them, otherwise the key-macros are
+ expanded once, hence the key-code is stored). This does support the unknown
+ key handlers set up with |\ekvdefunknown| and |\ekvdefunknownNoVal| and also
+ the redirection of unknown keys (the latter will not be expanded exhaustively
+ though, so the key-search is done on every later call of \meta{cs}). Any
+ prefix allowed for |\def| might prefix \cs{ekvcompile}. The list is not
+ entirely fixed, as you might use \meta{parameters} in a \val\ (this is not a
+ single token but a parameter text as you'd use it with |\def|). They can not
+ be part of a \key-name (the names are indeed fixed). If you need a |#| in a
+ \val\ you'll need to double it just as you'd do in |\def|. Internally
+ \cs{ekvcompile} uses |\ekvparse| and no |\ekvset| variant, because of this the
+ \expnotation\ is handled slightly differently; in case you're using a
+ \key-name that starts with something that looks like \expnotation\ you'll have
+ to explicitly add an empty \expansion\ prefix.
+\end{function}
+\begin{example}
+ {Compile a \kv\ list into a macro that will quickly set that list}
+ Define the macro |\foo| to set some keys in the set |foo|. Since one key has a
+ strange name we need to add an empty \expansion\ prefix. Also we'd like |\foo|
+ to take one parameter which is part of the \val\ of |bar| (since the list is
+ parsed now and not when |\foo| is used we don't need to put braces around that
+ value, even if at use time |#1| contains commas):
+ \begin{enverb}[no-tcb]
+ \ekvcompile\foo#1{foo}
+ {
+ bar = #1baz
+ ,: part-of-key: name = strange
+ ,NoVal
+ }
+ \end{enverb}
+ After this using |\foo{VAL}| will be the same as but faster than
+ \begin{enverb}[no-tcb]
+ \ekvset{foo}{bar={VALbaz},part-of-key: name=strange,NoVal}
+ \end{enverb}
+\end{example}
+
+\subsection{Generic Key Parsing}\label{sec:expkv:parse}
+
+\begin{function}{\ekvparse}
+ \begin{syntax}
+ \cs{ekvparse}\marg{code1}\marg{code2}\kvarg
+ \end{syntax}
+ This macro parses the \kv\ list and provides \Nkey{}s to \meta{code1} as a
+ single argument and \Vkey{}s with their corresponding \val\ as two arguments
+ to \meta{code2}.
+
+ \cs{ekvparse} is fully expandable and alignment safe, meaning that you don't
+ have to take any extra precautions if it is used inside an alignment context
+ (like \LaTeXe's |tabular| environment) and any \key\ or \val\ can contain an
+ |&|. \cs{ekvparse} expands in exactly two steps, the result is provided inside
+ |\unexpanded| (so doesn't expand further in an |\edef| or |\expanded|
+ context).
+
+ \cs{ekvbreak}, \cs{ekvsneak}, \cs{ekvmorekv}, \emph{etc.}\ don't work
+ in \cs{ekvparse}. \cs{ekvparse} does not throw an error if multiple
+ unprotected equals signs are found (it just splits at the first), and doesn't
+ throw an error if a \key\ is empty. If something looks like \expnotation\ (has
+ a colon followed but not preceded by a space and with non-blank material
+ following it) it'll be parsed as such (which might throw errors due to
+ undefined \expansion-rules if that wasn't the intended input). If you for some
+ reason need to input a \key-name that would match that pattern you'll need to
+ precede it by \verb*|: | (an empty \expansion\ prefix).
+\end{function}
+\begin{example}
+ {Parse a \kv\ list and execute arbitrary code for each element using
+ \cs[no-index]{ekvparse}}
+ \begin{enverb}[no-tcb]
+ \ekvparse{\handlekey{S}}{\handlekeyval{S}}{foo = bar, key, baz={zzz}}
+ \end{enverb}
+ would be equivalent to
+ \begin{enverb}[no-tcb]
+ \handlekeyval{S}{foo}{bar}\handlekey{S}{key}\handlekeyval{S}{baz}{zzz}
+ \end{enverb}
+ and afterwards |\handlekey| and |\handlekeyval| would have to further handle
+ the keys. No such macros are contained in \expkv, but I hope you get the idea.
+ Because it expands in two steps and doesn't expand any further both
+ \begin{enverb}[no-tcb]
+ \expandafter\parse\expanded{\ekvparse\k\kv{foo = bar, key, baz={zzz}}}
+ \end{enverb}
+ and
+ \begin{enverb}[no-tcb]
+ \expandafter\expandafter\expandafter
+ \parse\ekvparse\k\kv{foo={bar}, key, baz = zzz}
+ \end{enverb}
+ expand to
+ \begin{enverb}[no-tcb]
+ \parse\kv{foo}{bar}\k{key}\kv{baz}{zzz}
+ \end{enverb}
+\end{example}
+
+\subsection{Other Useful Macros}
+
+\begin{function}{\ekvoptarg}
+ \begin{syntax}
+ \cs{ekvoptarg}\marg{next}\marg{default}
+ \end{syntax}
+ This macro will expandably check for a following optional argument in brackets
+ (|[]|). After the optional argument there has to be a mandatory one (or else
+ this might have unwanted side effects). The code in \meta{next} should expect
+ two arguments (or more), namely the processed optional argument and the
+ mandatory one that followed it. If there was an optional argument the result
+ will be \meta{next}\marg{optional}\meta{mandatory} (so the optional argument
+ will be wrapped in braces, the mandatory argument will be untouched). If there
+ was no optional argument the result will be
+ \meta{next}\marg{default}\marg{mandatory} (so the default will be used and the
+ mandatory argument will be wrapped in braces after it was read once -- if it
+ was already wrapped it is effectively unchanged).
+
+ \cs{ekvoptarg} expands in exactly two steps, grabs all the arguments only at
+ the second expansion step, and is alignment safe. It has its limitations
+ however. It can't tell the difference between |[| and |{[}|, so it doesn't
+ work if the mandatory argument is a single bracket. Also if the optional
+ argument should contain a nested closing bracket it has to be nested in braces
+ like so: |[{arg[u]ment}]| (or else the result would be |arg[u| with a trailing
+ |ment]|).
+\end{function}
+\begin{example}{Expandably search for an optional argument with a default value}
+ Say we have a macro that should take an optional argument defaulting to |1|,
+ we could program it like this:
+ \makeatletter
+ \begin{enverb}
+ \newcommand\foo{\ekvoptarg\@foo{1}}
+ \newcommand\@foo[2]{Mandatory: #2\par Optional: #1}
+ \foo{5}\par
+ \foo[4]{5}\par
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvoptargTF}
+ \begin{syntax}
+ \cs{ekvoptargTF}\marg{true}\marg{false}
+ \end{syntax}
+ This macro is similar to \cs{ekvoptarg} but will result in
+ \meta{true}\marg{optional}\meta{mandatory} or \meta{false}\marg{mandatory}
+ instead of placing a default value.
+
+ \cs{ekvoptargTF} expands in exactly two steps, grabs all the arguments only at
+ the second expansion step, and is alignment safe. It has the same limitations
+ as \cs{ekvoptarg}.
+\end{function}
+\begin{example}
+ {Expandably search for an optional argument and behave differently if it's
+ found or not}
+ Say we have a macro that should behave differently depending on whether there
+ was an optional argument or not. This could be done with:
+ \makeatletter
+ \begin{enverb}
+ \newcommand\foo{\ekvoptargTF\foo@a\foo@b}
+ \newcommand\foo@a[2]{Mandatory: #2\par Optional: #1}
+ \newcommand\foo@b[1]{Mandatory: #1\par No optional.}
+ \foo{5}\par
+ \foo[4]{5}\par
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekvcsvloop}
+ \begin{syntax}
+ \cs{ekvcsvloop}\marg{code}\marg{csv-list}
+ \end{syntax}
+ This loops over the comma separated items in \meta{csv-list} and, after
+ stripping spaces from either end of \meta{item} and removing at most one set
+ of outer braces, leaves |\unexpanded{|\meta{code}\marg{item}|}| for each list
+ item in the input stream. Blank elements are ignored (if you need a blank
+ element it should be given as \verb*|{ }|). It supports both active commas and
+ commas of category other. \cs{ekvcsvloop} is not alignment safe, but you could
+ make it so by nesting it in |\expanded| (since the braces around the argument
+ of |\expanded| will hide alignment characters from \TeX's parsing).
+\end{function}
+\begin{example}
+ {Loop over a comma separated list and execute arbitrary code for each
+ element}
+ The following splits a comma separated list and prints it in a typewriter font
+ with parentheses around each element:
+ \begin{enverb}
+ \newcommand*\myprocessor[1]{\texttt{(#1)}}
+ \ekvcsvloop\myprocessor{abc,def,ghi}\par
+ \ekvcsvloop\myprocessor{1,,2,,3,,4}\par
+ \end{enverb}
+\end{example}
+
+\begin{function}{\ekverr}
+ \begin{syntax}
+ \cs{ekverr}\marg{package}\marg{message}
+ \end{syntax}
+ This macro will throw an error fully expandably.\footnotemark\ The error
+ length is limited to a total length of 69~characters, and since ten characters
+ will be added for the formatting (\verb*|! | and \verb*| Error: |) that leaves
+ us with a total length of \meta{package} plus \meta{message} of 59~characters.
+ If the message gets longer \TeX\ will only display the first 69~characters and
+ append |\ETC.| to the end.
+
+ Neither \meta{package} nor \meta{message} expand any further. Also
+ \meta{package} must not contain an explicit |\par| token or the token
+ |\thanks@jfbu|. No such restriction applies to \meta{message}.
+
+ If |^^J| is set up as the |\newlinechar| (which is the case in \LaTeXe\ but
+ not in \hologo{plainTeX} by default) you can use that to introduce line breaks
+ in your error message. However that doesn't change the message length limit.
+\end{function}
+\footnotetext{The used mechanism was to the best of my knowledge first
+implemented by Jean-François Burnol.}
+After your own error message some further text will be placed. The formatting
+of that text will look good if |^^J| is the |\newlinechar|, else not so much.
+That text will read:
+\begin{verbatim}
+ ! Paragraph ended before \<an-expandable-macro>
+ completed due to above exception. If the error
+ summary is not comprehensible see the package
+ documentation.
+ I will try to recover now. If you're in inter-
+ active mode hit <return> at the ? prompt and I
+ continue hoping recovery was complete.
+\end{verbatim}
+Any clean up has to be done by you, |\ekverr| will expand to nothing after
+throwing the error message.
+
+In \ConTeXt\ this macro works differently. While still being fully expandable,
+it doesn't have the character count limitation and doesn't impose restrictions
+on \meta{package}. It will not display the additional text and adding line
+breaks is not possible.
+\begin{example}{Expandably throw error messages using \cs[no-index]{ekverr}}
+ Say we set up a macro that takes as mandatory argument a simple equation which
+ must not be empty and if it's not empty it displays it and calculates the
+ result:
+ \begin{enverb}[no-tcb]
+ \newcommand*\mycalc[1]
+ {%
+ \the\numexpr
+ \if\relax\detokenize{#1}\relax
+ \ekverr{my}{Empty equation not allowed, leaving -2147483647}%
+ -2147483647%
+ \else
+ #1%
+ \fi
+ \relax
+ }
+ Using \mycalc{} wrong.
+ \end{enverb}
+ If that code gets executed the following will be the terminal output
+ \begin{verbatim}
+ Runaway argument?
+ ! my Error: Empty equation not allowed, leaving -2147483647
+ ! Paragraph ended before \<an-expandable-macro>
+ completed due to above exception. If the error
+ summary is not comprehensible see the package
+ documentation.
+ I will try to recover now. If you're in inter-
+ active mode hit <return> at the ? prompt and I
+ continue hoping recovery was complete.
+ <to be read again>
+ \par
+ l.17 Using \mycalc{}
+ wrong.
+ ?
+ \end{verbatim}
+ and the output would contain
+ \exres{Using -2147483647 wrong}
+ if we continued the \TeX\ run at the prompt.
+\end{example}
+
+
+\subsection{Other Macros}
+
+\begin{variable}{\ekvDate,\ekvVersion}
+ These two macros store \expkv's date and version.
+\end{variable}
+
+\begin{function}{\ekv@name,\ekv@name@set,\ekv@name@key}
+ \begin{syntax}
+ \cs{ekv@name}\marg{set}\marg{key}
+ \cs{ekv@name@set}\marg{set}
+ \cs{ekv@name@key}\marg{key}
+ \end{syntax}
+ The names of the macros storing the code of \Vkey{}s are stored in are built
+ with these macros. The name is built from two blocks, one that is formatting
+ the \set\ name, and on for formatting the \key\ name. To get the actual name
+ the argument to \cs{ekv@name@key} must be |\detokenize|d. Both blocks are put
+ together (with the necessary |\detokenize|) by \cs{ekv@name}. For \Nkey{}s an
+ additional |N| gets appended, so their name is
+ \cs{ekv@name}\marg{set}\marg{key}|N|.
+
+ You can use these macros to implement additional functionality or access
+ key-macros outside of \expkv, but \emph{don't} change them! \expkv\ relies on
+ their exact definitions internally.
+\end{function}
+\begin{example}{Directly call key code without parsing a \kv\ list}
+ Execute the key-macro of the \Nkey\ named |bar| in set |foo|:
+ \begin{enverb}[no-tcb]
+ \csname\ekv@name{foo}{bar}N\endcsname
+ \end{enverb}
+\end{example}
+
+
+\subsection{Examples}
+\subsubsection{Standard Use-Case\label{sec:expkv:standard}}
+
+\begin{example}{A \kv\ based replacement for \LaTeXe's \cs[no-index]{rule}}
+ Because I keep forgetting the correct order of \LaTeXe's |\rule| command I
+ want to create a \kv\ interface to it. For this I define the keys |ht| to
+ specify the rule's height, |wd| to specify its width, and to give a
+ displacement I use two keys (because who can remember whether the rule is
+ moved upwards or downwards?).
+
+ First the internals storing the values are initialised
+ \begin{enverb}[no-tcb,store]
+ \makeatletter
+ \newcommand*\myrule@ht{1ex}
+ \newcommand*\myrule@wd{0.1em}
+ \newcommand*\myrule@raise{\z@}
+ \end{enverb}
+ then the keys are defined. We could use |\dimen| registers instead of defining
+ macros, but macros have the advantage that the font dependent dimensions are
+ evaluated at use time.
+ \begin{enverb}[no-tcb,store]
+ \protected\ekvdef{myrule}{ht}{\def\myrule@ht{#1}}
+ \protected\ekvdef{myrule}{wd}{\def\myrule@wd{#1}}
+ \protected\ekvdef{myrule}{raise}{\def\myrule@raise{#1}}
+ \protected\ekvdef{myrule}{lower}{\def\myrule@raise{-#1}}
+ \end{enverb}
+ We also want a way to change the initial values without outputting a rule
+ (since there are unexpandable keys involved it's a good idea to define this
+ |\protected|)
+ \begin{enverb}[no-tcb,store]
+ \protected\ekvsetdef\myruleset{myrule}
+ \end{enverb}
+ and we need an actual frontend that does the job:
+ \begin{enverb}[no-tcb,store]
+ \newcommand*\myrule[1][]
+ {%
+ \begingroup
+ \myruleset{#1}%
+ \rule[\myrule@raise]{\myrule@wd}{\myrule@ht}%
+ \endgroup
+ }
+ \makeatother
+ \end{enverb}
+ Now we can use it:
+ \begin{enverb}[same-line=0.5,restore]
+ a\myrule\par
+ a\myrule[ht=2ex,lower=.5ex]\par
+ \myruleset{wd=5cm}
+ a\myrule
+ \end{enverb}
+\end{example}
+
+
+\subsubsection{An Expandable \kv\ Macro Using
+ \cs[no-index]{ekvsneak}\label{sec:expkv:sneak}}
+
+\begin{example}{An expandable \kv\ macro using \cs[no-index]{ekvsneak}}
+ Let's set up an expandable macro that uses a \kv\ interface. The problems
+ we'll face for this are:
+ \begin{enumerate}
+ \item ignoring duplicate keys
+ \item default values for keys which weren't used
+ \item providing the values as the correct argument to a macro (ordered)
+ \end{enumerate}
+
+ First we need to decide which \kv\ parsing macro we want to do this with,
+ \cs{ekvset} or \cs{ekvparse}. For this example we also want to show the usage
+ of \cs{ekvsneak}, hence we'll choose \cs{ekvset}. And we'll have to use
+ \cs{ekvset} such that it builds a parsable list for our macro internals. To
+ gain back control after \cs{ekvset} is done we have to put an internal of our
+ macro at the start of that list, so we use an internal key that uses
+ \cs{ekvsneakPre} after any user input.
+
+ To ignore duplicates will be easy if the value of the key used last will be
+ put first in the list, so we'll use \cs{ekvsneakPre} for the real values as
+ well. If for some reason we wanted a key for which the first usage was the
+ binding one we'd use \cs{ekvsneak} for that one.
+
+ Providing default values can be done in different ways. We'll use a simple
+ approach in which we'll just put the outcome of our keys if they were used
+ with default values before our end marker.
+
+ Ordering the keys can be done simply by searching for a specific token for
+ each argument (that token acts as a flag), so our sneaked out values will
+ include these specific tokens acting as markers.
+
+ Now we got an answer to each of our initial problems. Everything that's left
+ is deciding what our macro should actually do. For this example we'll define a
+ macro that calculates the sine of a number rounded to a specified precision.
+ The macro should also understand input in radian and degree, and we could also
+ decide to evaluate a different function. For the real hard part of this
+ (expandably calculating trigonometric functions) we'll use \pkg{xfp}.
+
+ First we set up our keys according to our earlier considerations and set up
+ the user facing macro |\sine|. The end marker of the parsing list will be a
+ |\sine@stop| token (which we don't need to define) and we put our default
+ values right before it. The user macro |\sine| uses |\ekvoptargTF| to check
+ for the optional argument short cutting a bit if no optional argument was
+ found. If you'd so prefer you could use \pkg{ltcmd}'s
+ |\NewExpandableDocumentCommand| to expandably get an optional argument as
+ well.
+ \begin{enverb}[no-tcb,store]
+ \RequirePackage{xfp}
+ \makeatletter
+ \ekvdef{sine}{f}{\ekvsneakPre{\f{#1}}}
+ \ekvdef{sine}{round}{\ekvsneakPre{\rnd{#1}}}
+ \ekvdefNoVal{sine}{degree}{\ekvsneakPre{\deg{d}}}
+ \ekvdefNoVal{sine}{radian}{\ekvsneakPre{\deg{}}}
+ \ekvdefNoVal{sine}{internal}{\ekvsneakPre{\sine@rnd}}
+ \newcommand*\sine{\ekvoptargTF\sine@args{\sine@final{sin}{d}{3}}}
+ \newcommand*\sine@args[2]
+ {\ekvset{sine}{#1,internal}\rnd{3}\deg{d}\f{sin}\sine@stop{#2}}
+ \end{enverb}
+
+ Now we need to define some internal macros to extract the value of each key's
+ last usage (remember that this will be the argument after the first matching
+ flag). For that we use one delimited macro per key.
+ \begin{enverb}[no-tcb,store]
+ \def\sine@rnd#1\rnd#2#3\sine@stop{\sine@deg#1#3\sine@stop{#2}}
+ \def\sine@deg#1\deg#2#3\sine@stop{\sine@f#1#3\sine@stop{#2}}
+ \def\sine@f#1\f#2#3\sine@stop{\sine@final{#2}}
+ \end{enverb}
+ After the macros |\sine@rnd|, |\sine@deg|, and |\sine@f| the macro
+ |\sine@final| will see
+ |\sine@final|\marg{f}\marg{degree/radian}\marg{round}\marg{num}. Now
+ |\sine@final| has to expandably deal with those arguments such that the
+ |\fpeval| macro of \pkg{xfp} gets the correct input. Luckily this part is
+ pretty easy after the build up we've done until now. In |\fpeval| the
+ trigonometric functions have names such as |sin| or |cos|, and the degree
+ taking alternatives just have an appended |d| (so |sind| or |cosd|). So
+ putting \meta{f} and \meta{degree/radian} together will form the correct
+ names.
+ \begin{enverb}[no-tcb,store]
+ \newcommand*\sine@final[4]{\fpeval{round(#1#2(#4),#3)}}
+ \makeatother
+ \end{enverb}
+ Let's give our macro a test:
+ \begin{enverb}[restore,inter=\def\RequirePackage#1{}]
+ \sine{60}\par
+ \sine[round=10]{60}\par
+ \sine[f=cos,radian]{pi}\par
+ \edef\myval{\sine[f=tan]{1}}\texttt{\meaning\myval}
+ \end{enverb}
+\end{example}
+
+Please note that setting this up a lot more user friendly is easily possible by
+utilizing \expkvc\ (see \autoref{sec:expkv-cs}).
diff --git a/macros/generic/expkv-bundle/pkg-opt.tex b/macros/generic/expkv-bundle/pkg-opt.tex
new file mode 100644
index 0000000000..452fbd1c28
--- /dev/null
+++ b/macros/generic/expkv-bundle/pkg-opt.tex
@@ -0,0 +1,229 @@
+\latexekv\expkvo{-opt}
+
+\expkvo\ allows to parse \LaTeXe\ class and package options as \kv\ lists using
+sets of \expkv.
+
+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
+(luckily, the \expnotation\ can be used to get around that as well). One feature
+of \expkvo\ 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.
+
+Another very interesting change in \LaTeXe\ was the addition of \pkg{ltkeys} and
+its |\ProcessKeyOptions| with the possibility to parse future options with it
+instead of getting the dreaded |Option clash| error. The idea is brilliant and
+changes made in the 2022-10-22 version allow us to provide the same feature
+without having to hack any kernel internals, so starting with kernel version
+2022-11-01 \expkvo\ supports this as well.
+
+\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 (see above). The one thing that \expkvo\ doesn't support, which \expkv\
+alone would, is active commas or equals signs. But there is no good reason why
+any of the two should be active in the preamble.
+
+You can use \LaTeXe's rollback support, so to load v0.1 explicitly use:
+\begin{enverb}[no-tcb]
+ \usepackage{expkv-opt}[=v0.1]
+\end{enverb}
+which will load the last version of \expkvo\ that doesn't use the raw option
+lists (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).
+
+
+\subsection{Macros\label{sec:o:macros}}
+
+\subsubsection{Option Processors\label{sec:o:processors}}
+
+\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 processed in
+any way) is stored within the macro |\CurrentOption|.
+
+\begin{function}{\ekvoProcessOptions}
+ \begin{syntax}
+ \cs{ekvoProcessOptions}\marg{set}
+ \end{syntax}
+ This runs |\ekvoProcessGlobalOptions|, then |\ekvoProcessLocalOptions|, and
+ finally |\ekvoProcessFutureOptions|. If you're using |\ekvoUseUnknownHandlers|
+ it'll affect all three option processors. Else the respective default
+ unknown-rules are used.
+\end{function}
+
+\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}
+\expkvorules
+ {%
+ cd = {remove the option from the list of unused global options if the local
+ option list matches the option list of the main class and the unused
+ global options list is not empty; else \emph{nothing}}
+ ,cu = add the key to the list of unused global options (if the local option
+ list matches the option list of the main class)
+ ,pu = throw an error
+ }
+
+\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}
+\expkvorules{d = remove the option from the list of unused global options}
+
+\begin{function}{\ekvoProcessFutureOptions}
+ \begin{syntax}
+ \cs{ekvoProcessFutureOptions}\marg{set}
+ \end{syntax}
+ This parses the option list of every future call of the package with
+ |\usepackage| or similar with an \expkv\ \set, circumventing the
+ |Option clash| error that'd be thrown by \LaTeXe. It is only available for
+ kernel versions starting with 2022-11-01. It is mutually exclusive with
+ \LaTeXe's |\ProcessKeyOptions| (which ever comes last defines how future
+ options are parsed).
+\end{function}
+\expkvorules{u = throw an error}
+
+\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}
+\expkvorules{}
+
+
+\subsubsection{Other Macros\label{sec:o:others}}
+
+\begin{function}{\ekvoUseUnknownHandlers}
+ \begin{syntax}
+ \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. The
+ macro \meta{cs_1} will be called if an undefined \Nkey\ is encountered and get
+ one argument being the \key\ (without being |\detokenize|d). Analogous the
+ macro \meta{cs_2} will be called if an undefined \Vkey\ was parsed and get two
+ arguments, the first being the \key\ (without being |\detokenize|d) and the
+ second the \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}
+ These two macros store the version and date of the package.
+\end{function}
+
+
+\subsection{Examples}
+
+\begin{example}{A package using \expkvo}
+ 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 |\thefootnote|
+ and we'll call this package \pkg{ex-footnote}. First we report back which
+ package we are:
+ \begin{enverb}[no-tcb]
+ \ProvidesPackage{ex-footnote}[2020-02-02 v1 change footnotes]
+ \end{enverb}
+ Next we'll need to provide the options we want the package to have.
+ \begin{enverb}[no-tcb]
+ \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{enverb}
+ We can provide initial values just by defining the two macros storing the
+ value.
+ \begin{enverb}[no-tcb]
+ \newcommand*\exfn@color{}
+ \newcommand*\exfn@format{arabic}
+ \end{enverb}
+ Next we need to process the options given to the package. The package should
+ only obey options directly passed to it, so we're using
+ |\ekvoProcessLocalOptions| and |\ekvoProcessFutureOptions|:
+ \begin{enverb}[no-tcb]
+ \ekvoProcessLocalOptions {ex-footnote}
+ \ekvoProcessFutureOptions{ex-footnote}
+ \end{enverb}
+ Now everything that's still missing is actually changing the way footnotes
+ appear:
+ \begin{enverb}[no-tcb]
+ \renewcommand*\thefootnote
+ {%
+ \ifx\exfn@color\@empty
+ \csname\exfn@format\endcsname{footnote}%
+ \else
+ \textcolor{\exfn@color}{\csname\exfn@format\endcsname{footnote}}%
+ \fi
+ }
+ \end{enverb}
+ So the complete code of the package would look like this:
+ \begin{enverb}[no-tcb]
+ \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}
+ \ekvoProcessFutureOptions{ex-footnote}
+
+ \renewcommand*\thefootnote
+ {%
+ \ifx\exfn@color\@empty
+ \csname\exfn@format\endcsname{footnote}%
+ \else
+ \textcolor{\exfn@color}{\csname\exfn@format\endcsname{footnote}}%
+ \fi
+ }
+ \end{enverb}
+ And it could be used with one (or thanks to |\ekvoProcessFutureOptions| all)
+ of the following lines:
+ \begin{enverb}[no-tcb]
+ \usepackage{ex-footnote}
+ \usepackage[format=fnsymbol]{ex-footnote}
+ \usepackage[color=green]{ex-footnote}
+ \usepackage[color=red,format=roman]{ex-footnote}
+ \end{enverb}
+\end{example}
+
+\begin{example}{Parsing the global options}
+ This document was compiled with the global options
+ \texttt{[\detokenize\expandafter\expandafter\expandafter{\csname @raw@classoptionslist\endcsname]}}
+ in use. If we define the following keys
+ \begin{enverb}[store,no-tcb]
+ \ekvdef{optexample}{exfoo}
+ {Global option \texttt{exfoo} got \texttt{\detokenize{#1}}.\par}
+ \ekvdefNoVal{optexample}{exbar}
+ {Global option \texttt{exbar} set.\par}
+ \end{enverb}
+ we can use those options to control the result of the following:
+ \begin{enverb}[restore,same-line=.55]
+ \ekvoProcessGlobalOptions{optexample}
+ \end{enverb}
+ Please note that under normal conditions
+ \cs[no-index]{ekvoProcessGlobalOptions} is only useable in the preamble; this
+ example is only for academic purposes, you'll not be able to reproduce this
+ with the exact code shown above.
+\end{example}
diff --git a/macros/generic/expkv-bundle/pkg-pop.tex b/macros/generic/expkv-bundle/pkg-pop.tex
new file mode 100644
index 0000000000..e34d0c5d1f
--- /dev/null
+++ b/macros/generic/expkv-bundle/pkg-pop.tex
@@ -0,0 +1,439 @@
+\genericekv\expkvp{-pop}
+
+The \expkvp\ is mainly written to lay the basis for \expkvc's and \expkvd's
+key-defining front ends. Historically the two packages shared pretty similar
+code. To unify this and reduce the overall code amount some auxiliary package
+was originally planned, but then I realised that with little to no overhead
+(apart from documentation) this can also be provided to users. Well, and then I
+thought, why not make the whole thing expandable as well. And here we are.
+
+So what's the idea? This package provides a \textbf{p}refix \textbf{o}riented
+\textbf{p}arser\footnote{Naming packages is hard, especially when the name
+should fit a particular naming scheme. Big thanks to samcarter for helping
+me: \url{https://topanswers.xyz/tex?q=1985}. The author apologises that there is
+no \texttt{expkv-pnk}, \texttt{expkv-rok}, \texttt{expkv-jaz} or any other music
+themed name in \expkvbundle.} with two kinds of prefixes. The first is called a
+\prefix, of which an item can have arbitrary many, the second a \type, of which
+every item has only one. To distinguish the concept of an optional \prefix\ from
+the generic term \enquote{prefix} I'll use this formatting whenever the special
+kind of prefix is meant.
+
+Another peculiarity of \expkvp\ compared to the other packages in
+\expkvbundle\ is that it doesn't separate \Nkey{}s from \Vkey{}s as
+strictly. Instead a |NoVal|-marker is used as the value. If this is not what you
+want you can use \cs{ekvpValueAlwaysRequired} (see there).
+
+
+\subsection{Parsing Rules}
+
+A parser is processing only the \key\ of a \kv\ pair. The \key\ is split at
+spaces (braces might be lost by this process!). Each split off piece is checked
+whether it's a defined prefix. If it's a \type\ parsing of the \key\ stops and
+the remainder is considered a \meta{name}. If it's a \prefix\ it'll be recorded
+and parsing goes on. If it's neither parsing is also stopped (and the last
+parsed space delimited part is put back -- braces might've been lost at this
+step). If a no-type rule has been defined (\cs{ekvpDefNoType}) that one is
+executed else an error is thrown.
+
+The \prefix\ or \type\ has to match after being |\detokenize|d, whereas the
+\meta{name} will be unchanged (except for stripping off the prefixes). If only a
+\key\ is given (so no =\val\ used) the same is done, and instead of \val\ a
+no-value marker is used (if that accidentally ends up in the input stream this
+looks like this: \csname c\string_novalue\string_tl\endcsname; this is the same
+as the marker used by \pkg{expl3} for those familiar with it).
+
+A \prefix\ has two parts to it, a \meta{pre} and a \meta{post} code, whereas a
+\type\ only results in a \type-action (or the no-type action if that's defined
+and no \type\ found). The parsing result can also be seen in
+\autoref{fig:p:result}.
+
+\begin{figure}[b]
+ \centering
+ \def\plevel#1{\raisebox{1ex}{#1}}%
+ \def\ts#1{\textsubscript{$#1$}}%
+ \begingroup
+ \ttfamily
+ pre\ts1
+ \plevel
+ {%
+ pre\ts2
+ \plevel
+ {%
+ \ldots\space
+ \plevel
+ {%
+ pre\ts n
+ \plevel{\type-action}
+ post\ts n
+ }%
+ \ldots\space
+ }%
+ post\ts2
+ }%
+ post\ts{1}%
+ \endgroup
+ \caption
+ {%
+ Structure of a single \kv\ pair's parsing result with $n$~\prefix{}es%
+ \label{fig:p:result}%
+ }
+\end{figure}
+
+Please note that \expkvp's parsers are fully expandable as long as your
+\prefixes\ and \types\ are. Additionally \expkvp\ doesn't provide means to
+define parsers, \prefixes, or \types\ |\protected|. As a result, make sure
+you'll always call |\ekvpParse| inside of a |\protected| macro if you need
+anything that's unexpandable or else your code might not do what you intended
+since some states may not be updated when expandable code tries to access them.
+The macro |\ekvpProtect| can help to overcome this issue, but it's more of a
+last resort than a clean solution.
+
+\subsection{Defining Parsers}
+
+\begin{function}{\ekvpNewParser}
+ \begin{syntax}
+ \cs{ekvpNewParser}\marg{parser}
+ \end{syntax}
+ Defines a new parser called \meta{parser}. Every parser has to be defined this
+ way. Throws an error if the parser is already defined.
+\end{function}
+
+\begin{function}{\ekvpDefType}
+ \begin{syntax}
+ \cs{ekvpDefType}\marg{parser}\marg{type}\marg{code}
+ \end{syntax}
+ Defines a \type\ that is called \meta{type} for the parser \meta{parser}. If
+ the \type\ is parsed the \meta{code} will be used as a \type-action. Inside of
+ \meta{code} you can use |#1| to refer to the \meta{name} (the remainder of the
+ \key\ after stripping off all the prefixes), |#2| to use the unaltered \key,
+ and |#3| to access the \val\ which was given to your \key.
+\end{function}
+
+\begin{function}{\ekvpDefPrefix}
+ \begin{syntax}
+ \cs{ekvpDefPrefix}\marg{parser}\marg{prefix}\marg{pre}\marg{post}
+ \end{syntax}
+ Defines a \prefix\ that is called \meta{prefix} for the parser \meta{parser}.
+ If the \prefix\ is encountered the code in \meta{pre} will be put before the
+ \type-action and the code in \meta{post} will be put behind it.
+ If multiple \prefix{}es are used the \meta{pre} of the first will be put first
+ and the \meta{post} of the first will be put last. Inside of \meta{pre} and
+ \meta{post} |#1| is replaced with the found \type, |#2| the \meta{name}, and
+ |#3| the unaltered \key. If no valid type was found and the no-type rule
+ defined with \cs{ekvpDefNoType} is executed the argument |#1| will be empty.
+\end{function}
+
+\begin{function}{\ekvpDefAutoPrefix}
+ \begin{syntax}
+ \cs{ekvpDefAutoPrefix}\marg{parser}\marg{pre}\marg{post}
+ \end{syntax}
+ You can also define a \prefix-like rule that is executed on each element
+ automatically. So the \meta{pre} and \meta{post} code of this will be inserted
+ for every valid element of the \kv\ list. Just like for \cs{ekvpDefPrefix} you
+ can access the \type\ with |#1|, the \meta{name} with |#2|, and the unaltered
+ \key\ with |#3|.
+\end{function}
+
+\begin{function}{\ekvpDefPrefixStore}
+ \begin{syntax}
+ \cs{ekvpDefPrefixStore}\marg{parser}\marg{prefix}\meta{cs}\marg{pre}\marg{post}
+ \end{syntax}
+ This is a shortcut to define a \prefix\ named \meta{prefix} for \meta{parser}
+ that'll store \meta{pre} inside of \meta{cs} (which should be a single control
+ sequence) before the \type-action and afterwards store \meta{post} in it. Both
+ definitions (in \meta{pre} and in \meta{post}) are put inside |\ekvpProtect|.
+\end{function}
+
+\begin{function}{\ekvpDefPrefixLet}
+ \begin{syntax}
+ \cs{ekvpDefPrefixLet}\marg{parser}\marg{prefix}\meta{cs}\meta{pre}\meta{post}
+ \end{syntax}
+ This is similar to \cs{ekvpDefPrefixStore}, but instead of storing in the
+ \meta{cs} it'll be let to the single tokens specified by \meta{pre} and
+ \meta{post}. If either \meta{pre} or \meta{post} contains more than a single
+ token the remainder is put after the |\let| statement. Both assignments (in
+ \meta{pre} and in \meta{post}) are put inside |\ekvpProtect|.
+\end{function}
+
+\begin{function}{\ekvpLet}
+ \begin{syntax}
+ \cs{ekvpLet}\marg{parser_1}\marg{type}\marg{name_1}\oarg{parser_2}\marg{name_2}
+ \end{syntax}
+ Copies the definition of a \prefix\ or \type. The \meta{type} should be one of
+ |prefix|, or |type|. The \prefix\ or \type\ \meta{name_1} for \meta{parser_1}
+ will be let equal to the \prefix\ or \type\ \meta{name_2} of \meta{parser_2}.
+ If you omit the optional \meta{parser_2} it will default to \meta{parser_1}.
+\end{function}
+
+
+\subsection{Changing Default Behaviours}
+
+\begin{function}{\ekvpValueAlwaysRequired}
+ \begin{syntax}
+ \cs{ekvpValueAlwaysRequired}\marg{parser}
+ \end{syntax}
+ By default a special no-value marker will be provided for \val\ if no value
+ was given to a key. If this is used instead an error will be thrown that a
+ value is required.
+\end{function}
+
+\begin{function}{\ekvpDefNoValue}
+ \begin{syntax}
+ \cs{ekvpDefNoValue}\marg{parser}\marg{code}
+ \end{syntax}
+ This is a third alternative to the default behaviour and
+ \cs{ekvpValueAlwaysRequired}. With this macro you can stop normal parsing if
+ no value was specified and instead run \meta{code}. Inside of \meta{code} the
+ unprocessed \Nkey\ is available as |#1|. No further processing of this \kv\
+ list element takes place.
+\end{function}
+
+\begin{function}{\ekvpUseNoValueMarker}
+ \begin{syntax}
+ \cs{ekvpUseNoValueMarker}\marg{parser}\marg{marker}
+ \end{syntax}
+ This macro changes the no-value marker from the package default to
+ \meta{marker}. Note that macros like \cs{ekvpAssertValue} don't work with
+ markers different from the default one.
+\end{function}
+
+\begin{function}{\ekvpDefNoValuePrefix}
+ \begin{syntax}
+ \cs{ekvpDefNoValuePrefix}\marg{parser}\marg{pre}\marg{post}
+ \end{syntax}
+ It is also possible to handle \Nkey{}s as if this was some special \prefix.
+ So if a \Nkey\ is encountered you'll have \meta{pre} and \meta{post} put
+ before and behind the \type-action (as the outermost \prefix). The no-value
+ marker will be forwarded as \val. If you want to change a parser's marker and
+ use this you have to use \cs{ekvpUseNoValueMarker} before calling
+ \cs{ekvpDefNoValuePrefix}, and you must not use \cs{ekvpDefNoValue} or
+ \cs{ekvpValueAlwaysRequired} before using \cs{ekvpDefNoValuePrefix} (both
+ result in undefined behaviour).
+\end{function}
+
+\begin{function}{\ekvpDefNoType}
+ \begin{syntax}
+ \cs{ekvpDefNoType}\marg{parser}\marg{code}
+ \end{syntax}
+ This defines an action if no valid \type\ was found, otherwise this behaves
+ like \cs{ekvpDefType} with the same arguments |#1| (\meta{name}), |#2|
+ (unaltered \key), and |#3| (\val) in \meta{code}. If this isn't used for the
+ \meta{parser} instead an error will be thrown whenever no \type\ is found.
+\end{function}
+
+
+\subsection{Markers}
+
+\expkvp\ will place three markers for each list element that was parsed and
+defines an auxiliary to gobble up to that marker. After each marker an
+additional group is placed containing the current list element (excluding the
+\val). The gobblers gobble that group as well. Those markers are:
+
+\begin{function}{\ekvpEOP,\ekvpGobbleP}
+ Is placed after all the \prefix{}es' \meta{pre} code, directly before the
+ \type-action.
+\end{function}
+
+\begin{function}{\ekvpEOT,\ekvpGobbleT}
+ Is placed after the \type-action, directly before the last \prefix's
+ \meta{post} code.
+\end{function}
+
+\begin{function}{\ekvpEOA,\ekvpGobbleA}
+ Is placed at the end of the complete result of the current element, so after
+ all the \prefix{}es' \meta{post} code.
+\end{function}
+
+
+\subsection{Helpers in Actions}
+
+\begin{function}{\ekvpIfNoVal}
+ \begin{syntax}
+ \cs{ekvpIfNoVal}\marg{arg}\marg{true}\marg{false}
+ \end{syntax}
+ This will expand to \meta{true} if the \meta{arg} is the special no-value
+ marker, otherwise \meta{false} is left in the input stream.
+\end{function}
+
+\begin{function}{\ekvpAssertIf,\ekvpAssertIfNot}
+ \begin{syntax}
+ \cs{ekvpAssertIf}\oarg{marker}\marg{if}\marg{message}
+ \end{syntax}
+ This macro will run the \TeX-if test specified by \meta{if} (should expand to
+ any \TeX-style if, e.g., \cs[no-index]{iftrue} or
+ \cs[no-index]{ifx}\meta{A}\meta{B}). If the test is true everything's fine,
+ else an error message is thrown using \meta{message} followed by the current
+ element and everything up to \meta{marker} is gobbled (\meta{marker} can be
+ any of |EOT|, which is the default, |EOP|, or |EOA|). The |Not| variant will
+ invert the logic, so if the \TeX-style if is true this will throw the error.
+\end{function}
+
+\begin{function}{\ekvpAssertTF,\ekvpAssertTFNot}
+ \begin{syntax}
+ \cs{ekvpAssertTF}\oarg{marker}\marg{if}\marg{message}
+ \end{syntax}
+ This is pretty similar to \cs{ekvpAssertIf}, but \meta{if} should be a test
+ that uses its first argument if it's true and its second otherwise (so an
+ error is thrown if the second argument is used, nothing happens otherwise).
+ The |Not| variant is again inversed.
+\end{function}
+
+\begin{function}{\ekvpAssertValue,\ekvpAssertNoValue}
+ \begin{syntax}
+ \cs{ekvpAssertValue}\oarg{marker}\marg{arg}
+ \end{syntax}
+ Asserts that \meta{arg} is not the no-value marker (\cs{ekvpAssertValue}) or
+ is the no-value marker (\cs{ekvpAssertNoValue}), otherwise throws an error and
+ gobbles everything up to \meta{marker} (like \cs{ekvpAssertIf}).
+\end{function}
+
+\begin{function}{\ekvpAssertOneValue,\ekvpAssertTwoValues}
+ \begin{syntax}
+ \cs{ekvpAssertOneValue}\oarg{marker}\marg{arg}
+ \end{syntax}
+ Asserts that \meta{arg} contains exactly one or two values (which could both
+ be either single tokens or braced groups -- spaces between the two values in
+ the \cs{ekvpAssertTwoValues} case are ignored), if the number of values
+ doesn't match an error is thrown and everything up to \meta{marker} gobbled.
+\end{function}
+
+\begin{function}{\ekvpProtect}
+ \begin{syntax}
+ \cs{ekvpProtect}\marg{code}
+ \end{syntax}
+ This macro protects \meta{code} from further expanding in every context a
+ |\protected| macro wouldn't expand. It needs at least two steps of expansion.
+ When a |\protected| macro would expand this will remove the braces around
+ \meta{code} and \TeX\ will process \meta{code} the same way it normally would.
+ After the first step of expansion it'll leave two macros, and after each
+ further full expansion these two macros stay there. Since \expkvp\ offers no
+ method to define \prefixes\ or \types\ |\protected| you can instead use this
+ macro. But if your parser needs any assignments you should nest the
+ |\ekvpParse| call in a |\protected| macro anyway.
+\end{function}
+
+\subsection{Using Parsers}
+
+\begin{function}{\ekvpParse}
+ \begin{syntax}
+ \cs{ekvpParse}\marg{parser}\kvarg
+ \end{syntax}
+ Parses the \kv\ list as defined for \meta{parser}. This expands in exactly two
+ steps, and returns inside of |\unexpanded|, so doesn't expand any further in
+ an |\edef| or |\expanded|. After the two steps it'll directly leave the code
+ as though every \prefix's \meta{pre} and \meta{post} code and the \type-action
+ were input directly along with the different markers.
+\end{function}
+
+\subsection{The Boring Macros}
+Just for the sake of completeness.
+\begin{function}{\ekvpDate,\ekvpVersion}
+ Store the date and version, respectively.
+\end{function}
+
+\subsection{Examples}
+\begin{example}{Defining a parser similar to \expkvd}
+ \ekvset{enverb}{store,no-tcb}%
+ Let's define a parser that is similar to \expkvd's |\ekvdefinekeys|. First we
+ define a new parser named |exdef|:
+ \begin{enverb}
+ \ekvpNewParser{exdef}
+ \end{enverb}
+ We'll need to provide our prefixes, |long| and |protected|. The following
+ initialises them and defines their action.
+ \begin{enverb}
+ \newcommand*\exLong{}
+ \newcommand*\exProtected{}
+ \ekvpDefPrefixLet{exdef}{long}\exLong\long\empty
+ \ekvpDefPrefixLet{exdef}{protected}\exProtected\protected\empty
+ \end{enverb}
+ Now we define a few types, I'll go with |noval|, |store|, and |code| for
+ starters. We exploit the fact that |\ekvdef| and |\ekvdefNoVal| will expand
+ the first argument, so we can simply store the set name in a macro.
+ \begin{enverb}
+ \ekvpDefType{exdef}{code}
+ {%
+ \ekvpAssertValue{#3}%
+ \exProtected\exLong\ekvdef\exSetName{#1}{#3}%
+ }
+ \ekvpDefType{exdef}{noval}
+ {%
+ \ekvpAssertValue{#3}%
+ \ekvpAssertIfNot{\ifx\exLong\long}{`long' not accepted}%
+ \exProtected\ekvdefNoVal\exSetName{#1}{#3}%
+ }
+ \ekvpDefType{exdef}{store}
+ {%
+ \ekvpAssertOneValue{#3}%
+ \ifdefined#3\else
+ \let#3\empty
+ \fi
+ \protected\exLong\ekvdef\exSetName{#1}{\edef#3{\unexpanded{##1}}}%
+ }
+ \end{enverb}
+ Now we need a user facing macro that puts the pieces together (this uses
+ |\NewDocumentCommand| instead of |\newcommand| because the former defines
+ macros |\protected|).
+ \begin{enverb}
+ \NewDocumentCommand\exdefinekeys{m +m}
+ {\def\exSetName{#1}\ekvpParse{exdef}{#2}}
+ \end{enverb}
+ Now we got that sorted so we can use our little parser:
+ \ekvset{enverb}{no-store,undo-no-tcb}%
+ \begin{enverb}[restore]
+ \newif\ifbar
+ \exdefinekeys{exampleset}
+ {
+ long store foo = \myfoo
+ ,protected noval bar = \bartrue
+ ,code baz = baz was called with \detokenize{#1}
+ }
+ \ekvset{exampleset}{foo=Foobar,bar,baz=\empty}
+ \ifbar bar was true so: \myfoo\fi
+ \end{enverb}
+\end{example}
+
+\begin{example}{Visualising the expandability of \cs[no-index]{ekvpParse}}
+ \ekvset{enverb}{store,no-tcb}%
+ With this example we want to take a closer look at the expansion of
+ |\ekvpParse|. So please bear with me if this doesn't make much sense
+ otherwise. One of the issues is that \prefixes\ are a somewhat unordered
+ concept, and only \types\ must come last. We could juggle with flags (an
+ expandable data-storage, see \autoref{sec:c:flags}) to overcome this somehow
+ just to define some pseudo-syntax here, but I guess that's not worth it.
+ Anyhow, here goes nothing.\par
+ First we need a parser
+ \begin{enverb}
+ \ekvpNewParser{exexp}
+ \end{enverb}
+ and a \prefix. We could define one that ensures the name starts of with
+ a letter. We also want each element to start a new line, which we do using an
+ auto prefix.
+ \begin{enverb}
+ \newcommand\ifletter{}
+ \long\def\ifletter#1#2\stop{\ifcat a\noexpand#1}
+ \ekvpDefPrefix{exexp}{letter}
+ {\ekvpAssertIf{\ifletter#2\stop}{not a letter}}
+ { (really a letter)}
+ \ekvpDefAutoPrefix{exexp}{\noindent}{\par}
+ \end{enverb}
+ Finally we define a \type\ and a |NoType| rule:
+ \begin{enverb}
+ \ekvpDefType{exexp}{*}{$#1\cdot#3 = \the\numexpr#1*#3\relax$}
+ \ekvpDefNoType{exexp}{the #3th letter is #1}
+ \end{enverb}
+ Now we want to see whether the thing is expandable:
+ \ekvset{enverb}{no-store,undo-no-tcb}%
+ \begin{enverb}[restore,below]
+ \raggedright
+ \edef\foo{\ekvpParse{exexp}{letter e = 5, * 4 = \empty3}}
+ 1st full expansion
+ \texttt{\meaning\foo}\par
+ \medskip
+ \edef\foo{\foo}
+ 2nd full expansion
+ \texttt{\meaning\foo}\par
+ \medskip
+ \foo
+ \end{enverb}
+\end{example}
diff --git a/macros/generic/expkv-bundle/preamble-enverb.tex b/macros/generic/expkv-bundle/preamble-enverb.tex
new file mode 100644
index 0000000000..22f39cd31c
--- /dev/null
+++ b/macros/generic/expkv-bundle/preamble-enverb.tex
@@ -0,0 +1,348 @@
+\RequirePackage{expkv-def}
+
+\ExplSyntaxOn
+\cs_new_eq:NN \enverb@count \tl_count:n
+\cs_set:Npx \enverb@othercr { \char_generate:nn {13} {12} }
+\ExplSyntaxOff
+%% key setup
+\ekvdefinekeys{enverb}
+ {
+ boolTF auto-ignore = \enverb@ifautoignore
+ ,initial auto-ignore
+ ,protected code ignore = \let\enverb@ifautoignore\@secondoftwo
+ ,eint more-ignore = \enverb@moreignore
+ ,initial more-ignore = 2
+ ,also eint ignore = \enverb@ignore
+ ,boolTF same-line = \enverb@ifsameline
+ ,unknown-choice same-line =
+ \let\enverb@ifsameline\@firstoftwo\edef\enverb@codeshare{\unexpanded{#1}}
+ ,initial same-line = 0.75
+ ,invboolTF other-line = \enverb@ifsameline
+ ,nmeta below = {same-line=false, no-aboveskip, no-belowskip}
+ ,nmeta undo-below = {same-line=true, aboveskip, belowskip}
+ ,store same-line-lst = \enverb@options@lst@same
+ ,store same-line-tcb = \enverb@options@tcb@same
+ ,initial same-line-lst = {aboveskip=0pt,belowskip=0pt}
+ ,initial same-line-tcb = {nobeforeafter,box align=center}
+ ,store other-line-lst = \enverb@options@lst@other
+ ,store other-line-tcb = \enverb@options@tcb@other
+ ,meta slst = same-line-lst={#1}
+ ,meta stcb = same-line-tcb={#1}
+ ,meta olst = other-line-lst={#1}
+ ,meta otcb = other-line-tcb={#1}
+ ,store lst = \enverb@options@lst
+ ,store tcb = \enverb@options@tcb
+ ,long store bol = \enverb@bol@content
+ ,long store eol = \enverb@eol@content
+ ,einitial eol = \enverb@othercr
+ ,boolTF no-lst = \enverb@ifno@lst
+ ,also nmeta no-lst = below
+ ,boolTF no-tcb = \enverb@ifno@tcb
+ ,also nmeta no-tcb = below
+ ,nmeta undo-no-tcb = {no-tcb=false, undo-below}
+ ,store inter = \enverb@inter
+ ,data gappend = \enverb@append
+ ,dataT pre-tcb = \enverb@pretcb
+ ,store after = \enverb@after
+ ,nmeta store = gappend=\enverb@store
+ ,noval no-store = \let\enverb@append\@secondoftwo
+ ,nmeta restore = {pre-tcb=\enverb@store,after=\enverb@clear@store}
+ ,code aboveskip = \edef\enverb@aboveskip{\vskip\unexpanded{#1}\relax}
+ ,code belowskip = \edef\enverb@belowskip{\vskip\unexpanded{#1}\relax}
+ ,default aboveskip = \medskipamount
+ ,default belowskip = \medskipamount
+ ,initial aboveskip
+ ,initial belowskip
+ ,noval no-aboveskip = \let\enverb@aboveskip\@empty
+ ,noval no-belowskip = \let\enverb@belowskip\@empty
+ }
+\protected\long\ekvsetdef\enverbsetup{enverb}
+\protected\def\enverb@clear@store{\global\let\enverb@store\@empty}
+\enverb@clear@store
+
+%% start of nested environments
+\newcommand\enverb@tcb
+ {%
+ \expanded
+ {%
+ \noexpand\begin{exresult}%
+ [{%
+ \enverb@options@tcb,%
+ \enverb@ifsameline\enverb@options@tcb@same\enverb@options@tcb@other
+ }]%
+ }%
+ {\linewidth\enverb@ifsameline{-\enverb@codeshare\linewidth}{}}%
+ }
+\newcommand\enverb@lst
+ {%
+ \expanded
+ {%
+ \noexpand\begin{lstlisting}%
+ [{%
+ \enverb@options@lst,%
+ \enverb@ifsameline\enverb@options@lst@same\enverb@options@lst@other
+ }]%
+ }%
+ }
+
+%% auxiliary error function
+\newcommand\enverb@error[1]
+ {%
+ \GenericError
+ {(enverb)\@spaces\@spaces\@spaces\@spaces}%
+ {Environment enverb error: #1}%
+ {Just use it correctly!}%
+ {Read the sources.}%
+ }
+
+%% setup for weird category code regime
+\begingroup
+\lccode`\~=`\^^M
+\catcode`\:=13
+\lccode`\:=`\ % <- space
+\catcode`\;=13
+\lccode`\;=`\^^I % <- tab
+\lowercase{\endgroup
+%% code for spaces and CR
+\def\enverb@body@space{}%
+\def\enverb@body@tab{}%
+\def\enverb@body@newline#1~%
+ {\enverb@ifnotend{#1}{\enverb@bol\unexpanded{#1}\enverb@eol~}}%
+%% activate the category code regime of the body
+\protected\def\enverb@body@setup
+ {%
+ \let\enverb@collected@body\@empty
+ \let\do\@makeother\dospecials
+ \catcode`\^^M=13 \let~\enverb@body@newline
+ \catcode`\ =13 \let:\enverb@body@space
+ \catcode`\^^I=13 \let;\enverb@body@tab
+ \let\enverb@bol\relax
+ \let\enverb@eol\relax
+ }
+%% check for optional argument
+\newcommand\enverb@search@oarg@a
+ {%
+ \ifx:\next
+ \ifenverb@firsteol
+ \else
+ \enverb@body@add{:}%
+ \fi
+ \let\next\enverb@search@oarg@b
+ \else
+ \ifx~\next
+ \ifenverb@firsteol
+ \enverb@firsteolfalse
+ \else
+ \enverb@body@add{~}%
+ \fi
+ \let\next\enverb@search@oarg@b
+ \else
+ \ifx[\next\@gobble]%
+ \let\next\enverb@oarg
+ \else
+ \ifenverb@firsteol
+ \let\next\enverb@body@after@begin
+ \else
+ \let\next\enverb@body
+ \fi
+ \fi
+ \fi
+ \fi
+ \next
+ }
+%% start body collection
+\newcommand\enverb@body
+ {\edef\enverb@collected@body{\iffalse}\fi\expandafter~\enverb@collected@body}
+%% check the line after an oarg
+\def\enverb@body@after@oarg#1~%
+ {\enverb@ensure@blank{#1}{closing bracket}\enverb@body}
+%% check the line after the \begin statement
+\def\enverb@body@after@begin#1~%
+ {\enverb@ensure@blank{#1}{\string\begin}\enverb@body}
+}
+%% quick check for empty line
+\newcommand\enverb@ensure@blank[2]
+ {%
+ \expandafter\enverb@ifempty\expanded{{#1}}{}%
+ {%
+ \expanded{%
+ \noexpand\enverb@error
+ {%
+ Line after #2 not empty.\noexpand\MessageBreak
+ Contains: \detokenize\expandafter{\romannumeral`\^^@#1}%
+ }%
+ }%
+ }%
+ }
+%% quick check for empty argument
+\newcommand\enverb@ifempty[1]
+ {%
+ \enverb@ifempty@\enverb@ifempty@A#1\enverb@ifempty@B.\enverb@ifempty@true
+ \enverb@ifempty@A\enverb@ifempty@B
+ }
+\def\enverb@ifempty@#1\enverb@ifempty@A\enverb@ifempty@B#2#3{#3}
+\def\enverb@ifempty@true\enverb@ifempty@A\enverb@ifempty@B#1#2{#1}
+\newcommand\enverb@gadd[2]{\xdef#1{\unexpanded\expandafter{#1#2}}}
+\newcommand\enverb@body@add[1]
+ {%
+ \edef\enverb@collected@body
+ {\unexpanded\expandafter{\enverb@collected@body#1}}%
+ }
+% start of environment `enverb'
+\newcommand\enverb
+ {%
+ \begingroup
+ \def\tmp{enverb}%
+ \expandafter
+ \endgroup
+ \expandafter\enverb@ifnotend@setup@perhaps\expanded
+ {{\string{\@currenvir\string}}}%
+ \begingroup
+ \enverb@body@setup
+ \enverb@firsteoltrue
+ \let\enverb@collected@oarg\@empty
+ \enverb@search@oarg
+ }
+\newif\ifenverb@firsteol
+\newcommand\enverb@search@oarg{\futurelet\next\enverb@search@oarg@a}
+\newcommand\enverb@search@oarg@b{\expandafter\enverb@search@oarg\@gobble}
+\newcommand\enverb@oarg{\endgroup\enverb@oarg@}
+\NewDocumentCommand\enverb@oarg@{O{}}
+ {%
+ \edef\enverb@collected@oarg{\unexpanded{#1}}%
+ \begingroup
+ \enverb@body@setup
+ \enverb@body@after@oarg
+ }
+\def\enverb@ifnotend#1%
+ {%
+ \def\enverb@ifnotend##1%
+ {%
+ \enverb@ifnotend@
+ ##1\enverb@mark\enverb@ifnotend@maybe
+ #1\enverb@mark\@thirdofthree
+ \enverb@stop
+ }%
+ \def\enverb@ifnotend@##1#1##2\enverb@mark##3##4\enverb@stop{##3{##1}{##2}}%
+ }
+\expandafter\enverb@ifnotend\expanded{{\expandafter\@gobble\string\\end}}
+\newcommand\enverb@ifnotend@maybe[2]
+ {\expandafter\enverb@ifnotend@perhaps\expandafter{\romannumeral`\^^@#2}{#1}}
+\newcommand\enverb@ifnotend@setup@perhaps[1]
+ {%
+ \def\enverb@ifnotend@perhaps##1%
+ {%
+ \enverb@ifnotend@perhaps@\enverb@mark##1\enverb@mark\enverb@ifnotend@end
+ \enverb@mark#1\enverb@mark\@thirdofthree
+ \enverb@stop
+ }%
+ \def\enverb@ifnotend@perhaps@
+ ##1\enverb@mark#1##2\enverb@mark##3##4\enverb@stop
+ {##3{##2}}%
+ }
+\providecommand\@thirdofthree[3]{#3}
+\outer\def\myabsolutestop{\stop}
+\newcommand\enverb@ifnotend@end[3]
+ {%
+ \iffalse{\fi}%
+ \enverb@ensure@blank{#1}{\string\end}%
+ \expanded
+ {%
+ \endgroup
+ \enverbsetup
+ {\unexpanded\expandafter{\enverb@collected@oarg}}%
+ \noexpand\enverb@output
+ {\unexpanded\expandafter{\enverb@collected@body}}%
+ }%
+ {#2}%
+ \expandafter\end\expandafter{\@currenvir}%
+ }
+\long\def\enverb@output#1#2%
+ {%
+ \enverb@ifautoignore
+ {\enverb@setup@ignore{\enverb@count{#2}+\enverb@moreignore}}%
+ {\enverb@setup@ignore\enverb@ignore}%
+ \edef\enverb@line##1\enverb@eol
+ {%
+ \noexpand\detokenize{##1}%
+ \noexpand\unexpanded{\unexpanded\expandafter{\enverb@eol@content}}%
+ }%
+ \edef\enverb@collected@body{#1}%
+ \expanded
+ {\unexpanded{\enverb@append\enverb@gadd\@gobble}\expandafter}%
+ \expandafter{\enverb@collected@body}%
+ \par
+ \enverb@aboveskip
+ \enverb@ifno@lst{}%
+ {%
+ \enverb@ifsameline
+ {\noindent\begin{minipage}[c]{\enverb@codeshare\linewidth}}%
+ {}%
+ \begingroup
+ \everyeof{\noexpand}%
+ \expandafter
+ \endgroup
+ \scantokens\expanded
+ {{%
+ \noexpand\csname enverb@lst\endcsname
+ \enverb@othercr
+ \enverb@collected@body
+ \string\end{lstlisting}\enverb@othercr
+ }}%
+ \enverb@ifsameline{\end{minipage}}{}%
+ }%
+ \enverb@inter
+ \enverb@ifno@tcb{}%
+ {%
+ \begingroup
+ \everyeof{\noexpand}%
+ \newlinechar=\endlinechar
+ \expandafter
+ \endgroup
+ \scantokens\expanded
+ {{%
+ \noexpand\csname enverb@tcb\endcsname
+ \enverb@pretcb{\unexpanded\expandafter}%
+ \enverb@collected@body
+ \noexpand\end{exresult}%
+ }}%
+ }%
+ \par
+ \enverb@belowskip
+ \enverb@after
+ \@endpetrue
+ }
+\providecommand\@firstofnine[9]{#1}
+\newcommand\enverb@setup@ignore[1]
+ {\expandafter\enverb@setup@ignore@\the\numexpr#1\relax;\enverb@line}
+\def\enverb@setup@ignore@#1;#2%
+ {%
+ \ifnum#1>9
+ \expandafter\@firstoftwo
+ \else
+ \expandafter\@secondoftwo
+ \fi
+ {\expandafter\enverb@setup@ignore@\the\numexpr#1-8;{\@firstofnine{#2}}}%
+ {%
+ \let\enverb@bol@gobble\@empty % just so that renewcommand doesn't go nuts
+ \expanded
+ {%
+ \unexpanded{\renewcommand\enverb@bol@gobble}\ifnum#1>\z@[#1]\fi
+ {%
+ \noexpand\unexpanded
+ {\unexpanded\expandafter{\enverb@bol@content}}%
+ \unexpanded{#2}%
+ }%
+ \unexpanded{\def\enverb@bol##1\enverb@eol}%
+ {%
+ \noexpand\unexpanded
+ {\unexpanded\expandafter{\enverb@bol@content}}%
+ \unexpanded{\expandafter\enverb@ifempty\expanded}{{##1}}%
+ {\noexpand\enverb@line}%
+ {\noexpand\enverb@bol@gobble}%
+ ##1\unexpanded{\enverb@eol}%
+ }%
+ }%
+ }%
+ }
+\let\endenverb\@empty
diff --git a/macros/generic/expkv-bundle/preamble-examples.tex b/macros/generic/expkv-bundle/preamble-examples.tex
new file mode 100644
index 0000000000..5a146d9eb6
--- /dev/null
+++ b/macros/generic/expkv-bundle/preamble-examples.tex
@@ -0,0 +1,16 @@
+\makeatletter
+\newcounter{example}[section]
+\newcommand*\example[1]
+ {%
+ \par\smallskip
+ \refstepcounter{example}%
+ \addcontentsline{exs}{example}{#1}%
+ \noindent\textit{Example:} \ignorespaces
+ }
+\newcommand*\l@example{\@dottedtocline{0}{1.5em}{2.3em}}
+\newcommand\listofexamples
+ {%
+ \addsec{List of Examples}%
+ \@starttoc{exs}%
+ }
+\makeatother
diff --git a/macros/generic/expkv-bundle/preamble-l3doctweaks.tex b/macros/generic/expkv-bundle/preamble-l3doctweaks.tex
new file mode 100644
index 0000000000..47d2c744a5
--- /dev/null
+++ b/macros/generic/expkv-bundle/preamble-l3doctweaks.tex
@@ -0,0 +1,39 @@
+\ExplSyntaxOn
+\cs_new_protected:Npn \__expkvdoc_patchfootnote:% >>=
+ {
+ \cs_set:Npx \footnote
+ {
+ \exp_not:n { \ClassError {expkvdoc} {Footnote~ in~ function} {} }
+ \exp_not:o { \footnote }
+ }
+ }% =<<
+\AddToHook{env/function/begin}{\__expkvdoc_patchfootnote:}
+
+\group_begin:
+\cs_set_protected:Npn \__expkvdoc_tmp:nN #1#2
+ {
+ \__kernel_tl_set:Nx #2 { \tl_to_str:n {#1} }
+ \tl_replace_all:Nxn #2 { \c_underscore_str } { / }
+ \tl_remove_all:Nx #2 { \c_backslash_str }
+ \tl_put_left:Nn #2 { doc/function// }
+ }
+\cs_if_eq:NNTF \__expkvdoc_tmp:nN \__codedoc_get_hyper_target:nN
+ {
+ \cs_gset:Npn \__codedoc_get_hyper_target:nN #1#2
+ {
+ \__kernel_tl_set:Nx #2 { \tl_to_str:n {#1} }
+ \tl_replace_all:Nxn #2 { \c_underscore_str } { / }
+ \tl_remove_all:Nx #2 { \c_backslash_str }
+ \tl_put_left:Nx #2 { doc/function/ \g__expkvdoc_module_str / }
+ }
+ }
+ {
+ \ClassWarning{expkvdoc}
+ {
+ Didn't~ patch~ l3doc's~ hyper~ targets.~ You~ might~ get~ duplicate~
+ labels.
+ }
+ }
+\group_end:
+
+\ExplSyntaxOff
diff --git a/macros/generic/expkv-bundle/preamble-logos.tex b/macros/generic/expkv-bundle/preamble-logos.tex
new file mode 100644
index 0000000000..f5c963134c
--- /dev/null
+++ b/macros/generic/expkv-bundle/preamble-logos.tex
@@ -0,0 +1,107 @@
+\definecolor{ekvred}{HTML}{9F393D}
+\colorlet{ekvgrey}{black!75}
+\makeatletter
+\newcommand*\kvstyle%>>=
+ {\normalfont\rmfamily\bfseries\color{ekvred}}%=<<
+\newcommand*\expFormat % used for the title only >>=
+ {%
+ {%
+ \rmfamily
+ \bfseries
+ {\color{ekvgrey}e\kern-.05em x\kern-.05em}%
+ \lower.493ex\hbox{{\color{ekvgrey}P}}%
+ }%
+ }%=<<
+\newcommand\expnotation% >>=
+ {%
+ \begingroup
+ \BeginAccSupp{ActualText=exp|notation,E=expansion-notation}%
+ \rmfamily
+ \bfseries
+ \color{ekvgrey}%
+ e\kern-.05em x\kern-.05em%
+ \lower.493ex\hbox{{\color{ekvgrey}P}}%
+ \kern-.05em:%
+ \kern.05em\textsc{notation}%
+ \EndAccSupp{}%
+ \endgroup
+ }% =<<
+\newcommand\expkvLogoFormat[1]% >>=
+ {%
+ \begingroup
+ \rmfamily
+ \bfseries
+ {\color{ekvgrey}e\kern-.05em x\kern-.05em}%
+ \lower.493ex\hbox{{\color{ekvgrey}P}\kern-.1em{\color{ekvred}k}}%
+ \kern-.18em{\color{ekvred}v}%
+ \IfValueT{#1}
+ {%
+ \begingroup
+ \color{ekvgrey}%
+ \kern.05em\rule[-.1ex]{.08em}{1.2ex}%
+ \kern.05em\textsc{#1}%
+ \endgroup
+ }%
+ \endgroup
+ }% =<<
+\NewDocumentCommand \expkvLogo { o }%>>=
+ {%
+ \mbox
+ {%
+ \BeginAccSupp{ActualText=expkv\IfValueT{#1}{-#1}}%
+ \ifodd\ekvdoc@insection
+ \href{https://gitlab.com/islandoftex/texmf/expkv-bundle}%
+ {\expkvLogoFormat{#1}}%
+ \else
+ \hyperref[sec:expkv\IfValueT{#1}{-#1}]{\expkvLogoFormat{#1}}%
+ \fi
+ \EndAccSupp{}%
+ }%
+ }%=<<
+\newcommand*\expkv%>>=
+ {%
+ \texorpdfstring
+ {\expkvLogo}
+ {expkv}%
+ }%=<<
+\newcommand*\expkvpkg[1]%>>=
+ {%
+ \texorpdfstring
+ {\expkvLogo[{#1}]}%
+ {expkv-#1}%
+ }%=<<
+\newcommand*\expkvbundle% >>=
+ {%
+ \texorpdfstring
+ {\begingroup\chardef\ekvdoc@insection1 \expkvpkg{bundle}\endgroup}%
+ {\expkvpkg{bundle}}%
+ }% =<<
+\newcommand*\expkvc{\expkvpkg{cs}}
+\newcommand*\expkvd{\expkvpkg{def}}
+\newcommand*\expkvo{\expkvpkg{opt}}
+\newcommand*\expkvp{\expkvpkg{pop}}
+\ExplSyntaxOn
+\cs_new_protected:Npn \pkglogo #1%>>=
+ {
+ \texorpdfstring
+ {
+ \mbox
+ {
+ \BeginAccSupp{ActualText=#1}
+ \rmfamily
+ \str_case:nn {#1}
+ {
+ {yax}
+ {
+ Y\kern-.1em
+ \raise.15em\hbox{\scshape a}
+ \kern-.1em \lower.15em\hbox{X}%
+ }
+ }
+ \EndAccSupp{}
+ }
+ }
+ {#1}
+ }%=<<
+\newcommand*\yax{\pkglogo{yax}}
+\ExplSyntaxOff
diff --git a/macros/generic/expkv-bundle/preamble-lst.tex b/macros/generic/expkv-bundle/preamble-lst.tex
new file mode 100644
index 0000000000..a94920bfff
--- /dev/null
+++ b/macros/generic/expkv-bundle/preamble-lst.tex
@@ -0,0 +1,218 @@
+\def\mylstwd{.55em}
+\lstdefinelanguage{expkv}[primitive]{TeX}
+ {
+ ,moretexcs=[2]% e-TeX
+ {
+ expanded,
+ numexpr,
+ protected,
+ unexpanded,
+ ifdefined,
+ detokenize,
+ }
+ ,moretexcs=[3]% plain/LaTeX/ConTeXt
+ {
+ approx,
+ begin,end,
+ cdot,
+ emph,empty,
+ item,
+ LaTeX,
+ makeatletter,makeatother,multicolumn,
+ newcommand,renewcommand,newdimen,newif,newcount,NewDocumentCommand,
+ usepackage,RequirePackage,ProvidesPackage,
+ raggedright,
+ rule,
+ space,stop,
+ smallskip,medskip,bigskip,
+ TeX,
+ textit,texttt,
+ usepackage,
+ usemodule,
+ @gobble,@gobbletwo,@firstofone,@empty,
+ ExplSyntaxOn,ExplSyntaxOff,
+ }
+ ,moretexcs=[4]% used packages
+ {
+ % xfp
+ fpeval,
+ % keyval
+ setkeys,
+ % kvsetkeys
+ kvsetkeys,
+ % color
+ textcolor,
+ % yax
+ defactiveparameter,storevalue,setparameterlist,
+ % graphics
+ includegraphics,
+ }
+ ,moretexcs=[5]% expkv macros
+ {
+ ekvdef,ekvdefNoVal,%
+ ekvlet,ekvletNoVal,ekvletkv,ekvletkvNoVal,%
+ ekvdefunknown,ekvdefunknownNoVal,%
+ ekvletunknown,ekvletunknownNoVal,%
+ ekvredirectunknown,ekvredirectunknownNoVal,%
+ ekvset,ekvsetSneaked,%
+ ekvsetdef,ekvsetSneakeddef,ekvsetdefSneaked,%
+ ekvcompile,%
+ ekvparse,%
+ ekvVersion,ekvDate,%
+ ekvifdefined,ekvifdefinedNoVal,ekvifdefinedset,%
+ ekvbreak,ekvbreakPreSneak,ekvbreakPostSneak,%
+ ekvsneak,ekvsneakPre,%
+ ekvchangeset,%
+ ekvmorekv,%
+ ekvoptarg,ekvoptargTF,%
+ ekvcsvloop,%
+ ekverr,%
+ ekv@name,%
+ }
+ ,moretexcs=[6]% expkv-cs macros
+ {
+ ekvcSecondaryKeys,%
+ ekvcSplit,ekvcSplitAndForward,ekvcSplitAndUse,%
+ ekvcHash,ekvcHashAndForward,ekvcHashAndUse,%
+ ekvcValue,ekvcValueFast,ekvcValueSplit,ekvcValueSplitFast,%
+ ekvcChange,%
+ ekvcPass,%
+ }
+ ,moretexcs=[7]% expkv-def macros
+ {
+ ekvdefinekeys
+ }
+ ,moretexcs=[8]% expkv-pop macros
+ {
+ ekvpNewParser,
+ ekvpDefType,
+ ekvpDefPrefix,ekvpDefAutoPrefix,ekvpDefPrefixStore,ekvpDefPrefixLet,
+ ekvpLet,
+ ekvpValueAlwaysRequired,ekvpDefNoValue,ekvpUseNoValueMarker,
+ ekvpDefNoValuePrefix,ekvpDefNoType,ekvpDefNoValue,
+ ekvpEOP,ekvpGobbleP,ekvpEOT,ekvpGobbleT,ekvpEOA,ekvpGobbleA,
+ ekvpIfNoVal,
+ ekvpAssertIf,ekvpAssertIfNot,ekvpAssertTF,ekvpAssertTFNot,
+ ekvpAssertValue,ekvpAssertNoValue,
+ ekvpAssertOneValue,ekvpAssertTwoValues,
+ ekvpParse,
+ }
+ ,moretexcs=[9]% expkv-opt macros
+ {
+ ekvoProcessOptions,%
+ ekvoProcessLocalOptions,ekvoProcessGlobalOptions,%
+ ekvoProcessFutureOptions,ekvoProcessOptionsList,%
+ ekvoUseUnknownHandlers,%
+ ekvoVersion,ekvoDate,%
+ }
+ ,alsoletter={_:}
+ ,moretexcs=[10]% expl3
+ {
+ cs_new_eq:NN,
+ tl_count_tokens:n,
+ }
+ }
+\colorlet{codeparam}{cyan!65!black}
+\lstdefinestyle{expkv}
+ {
+ texcsstyle=*[5]{\bfseries\color{ekvred}} % expkv
+ ,texcsstyle=*[6]{\color{ekvred}} % expkv-cs
+ ,texcsstyle=*[7]{\color{ekvred}} % expkv-def
+ ,texcsstyle=*[8]{\color{ekvred}} % expkv-pop
+ ,texcsstyle=*[9]{\color{ekvred}} % expkv-opt
+ }
+\lstdefinestyle{expkv-cs}
+ {
+ texcsstyle=*[5]{\color{ekvred}} % expkv
+ ,texcsstyle=*[6]{\bfseries\color{ekvred}} % expkv-cs
+ ,texcsstyle=*[7]{\color{ekvred}} % expkv-def
+ ,texcsstyle=*[8]{\color{ekvred}} % expkv-pop
+ ,texcsstyle=*[9]{\color{ekvred}} % expkv-opt
+ }
+\lstdefinestyle{expkv-def}
+ {
+ texcsstyle=*[5]{\color{ekvred}} % expkv
+ ,texcsstyle=*[6]{\color{ekvred}} % expkv-cs
+ ,texcsstyle=*[7]{\bfseries\color{ekvred}} % expkv-def
+ ,texcsstyle=*[8]{\color{ekvred}} % expkv-pop
+ ,texcsstyle=*[9]{\color{ekvred}} % expkv-opt
+ }
+\lstdefinestyle{expkv-pop}
+ {
+ texcsstyle=*[5]{\color{ekvred}} % expkv
+ ,texcsstyle=*[6]{\color{ekvred}} % expkv-cs
+ ,texcsstyle=*[7]{\color{ekvred}} % expkv-def
+ ,texcsstyle=*[8]{\bfseries\color{ekvred}} % expkv-pop
+ ,texcsstyle=*[9]{\color{ekvred}} % expkv-opt
+ }
+\lstdefinestyle{expkv-opt}
+ {
+ texcsstyle=*[5]{\color{ekvred}} % expkv
+ ,texcsstyle=*[6]{\color{ekvred}} % expkv-cs
+ ,texcsstyle=*[7]{\color{ekvred}} % expkv-def
+ ,texcsstyle=*[8]{\color{ekvred}} % expkv-pop
+ ,texcsstyle=*[9]{\bfseries\color{ekvred}} % expkv-opt
+ }
+\lstdefinestyle{expkv-all}
+ {
+ texcsstyle=*[5]{\bfseries\color{ekvred}} % expkv
+ ,texcsstyle=*[6]{\bfseries\color{ekvred}} % expkv-cs
+ ,texcsstyle=*[7]{\bfseries\color{ekvred}} % expkv-def
+ ,texcsstyle=*[8]{\bfseries\color{ekvred}} % expkv-pop
+ ,texcsstyle=*[9]{\bfseries\color{ekvred}} % expkv-opt
+ }
+\lstset
+ {
+ ,language=expkv
+ ,style=expkv
+ ,flexiblecolumns=false
+ ,basewidth=\mylstwd
+ %,basicstyle=\fontfamily{lmtt}\selectfont
+ %,basicstyle=\fontfamily{GoMono-TLF}\selectfont%\itshape
+ %,basicstyle=\fontfamily{jkp}\selectfont%\itshape
+ %,basicstyle=\fontfamily{jkptt}\selectfont%\itshape
+ ,basicstyle=\fontfamily{txtt}\selectfont%\itshape
+ ,texcsstyle=*[1]{\bfseries\color{ekvgrey}} % primitives
+ ,texcsstyle=*[2]{\bfseries\color{ekvgrey}} % e-TeX
+ ,texcsstyle=*[3]{\bfseries\color{ekvgrey}} % plain/LaTeX macros
+ ,texcsstyle=*[4]{\bfseries\color{ekvgrey}} % macros of other packages
+ ,texcsstyle=*[10]{\bfseries\color{ekvgrey}} % macros of expl3
+ ,commentstyle=\color[gray]{0.4}
+ ,literate=
+ {\{} {{\CodeUpBf\{}}{1}
+ {\}} {{\CodeUpBf\}}}{1}
+ {$} {{\CodeUpBf\$}}{1}
+ {[} {{\CodeUp[}}{1}
+ {]} {{\CodeUp]}}{1}
+ {(} {{\CodeUp(}}{1}
+ {)} {{\CodeUp)}}{1}
+ {*} {{$*$}}{1}
+ {1} {{\CodeUp{1}}}{1}
+ {2} {{\CodeUp{2}}}{1}
+ {3} {{\CodeUp{3}}}{1}
+ {4} {{\CodeUp{4}}}{1}
+ {5} {{\CodeUp{5}}}{1}
+ {6} {{\CodeUp{6}}}{1}
+ {7} {{\CodeUp{7}}}{1}
+ {8} {{\CodeUp{8}}}{1}
+ {9} {{\CodeUp{9}}}{1}
+ {0} {{\CodeUp{0}}}{1}
+ {##} {{\CodeColored{codeparam}{1}{\#}}}{1}
+ {##1}{{\CodeColored{codeparam}{2}{\#1}}}{2}
+ {##2}{{\CodeColored{codeparam}{2}{\#2}}}{2}
+ {##3}{{\CodeColored{codeparam}{2}{\#3}}}{2}
+ {##4}{{\CodeColored{codeparam}{2}{\#4}}}{2}
+ {##5}{{\CodeColored{codeparam}{2}{\#5}}}{2}
+ {##6}{{\CodeColored{codeparam}{2}{\#6}}}{2}
+ {##7}{{\CodeColored{codeparam}{2}{\#7}}}{2}
+ {##8}{{\CodeColored{codeparam}{2}{\#8}}}{2}
+ {##9}{{\CodeColored{codeparam}{2}{\#9}}}{2}
+ {<key>}{{$\langle$}key{$\rangle$}}{5}
+ {<set>}{{$\langle$}set{$\rangle$}}{5}
+ {<set1>}{{$\langle$}set1{$\rangle$}}{6}
+ {<set2>}{{$\langle$}set2{$\rangle$}}{6}
+ %,literate=*{<key>}{\key}{4}{<set>}{\set}{4}
+ }
+\newcommand*\CodeColored[3]{\textcolor{#1}{\makebox[\dimexpr\mylstwd*#2]{#3}}}
+\newcommand*\CodeUpBf[1]{\makebox[\mylstwd]{\textup{\textbf{#1}}}}
+\newcommand*\CodeUp[1]{\makebox[\mylstwd]{\textup{#1}}}
diff --git a/macros/generic/expkv-bundle/preamble-noidx.tex b/macros/generic/expkv-bundle/preamble-noidx.tex
new file mode 100644
index 0000000000..410db83483
--- /dev/null
+++ b/macros/generic/expkv-bundle/preamble-noidx.tex
@@ -0,0 +1,50 @@
+\DoNotIndex{\-,\:,\\,\~}
+\DoNotIndex{\advance,\AtEndOfPackage}
+\DoNotIndex{\ClassError,\CurrentOption}
+\DoNotIndex{\DeclareCurrentRelease,\DeclareOption,\DeclareRelease}
+\DoNotIndex{\directlua,\dimexpr}
+\DoNotIndex{\def,\edef,\,,\=,\begingroup,\catcode,\chardef,\csname,\endcsname}
+\DoNotIndex{\endgroup,\endinput,\errmessage,\expandafter,\input,\let,\long}
+\DoNotIndex{\gdef,\global,\glueexpr,\gtoksapp,\gtokspre}
+\DoNotIndex{\hbox}
+\DoNotIndex{\IfFormatAtLeastTF}
+\DoNotIndex{\key}
+\DoNotIndex{\lccode,\lowercase}
+\DoNotIndex{\MessageBreak}
+\DoNotIndex{\N,\newcommand,\newcount,\newtoks,\number,\numexpr}
+\DoNotIndex{\PackageError,\PackageWarning,\ProcessOptions}
+\DoNotIndex{\requestedLaTeXdate,\RequirePackage}
+\DoNotIndex{\setbox}
+\DoNotIndex{\@classoptionslist,\@clsextension,\@currext,\@currname,\@empty}
+\DoNotIndex{\@firstofone,\@firstoftwo,\@gobble,\@gobblethree,\@gobbletwo}
+\DoNotIndex{\@ifstar,\@onlypreamble,\@raw@classoptionslist,\@secondoftwo}
+\DoNotIndex{\@unprocessedoptions,\@unusedoptionlist}
+\DoNotIndex{\pkgcls@parse@date@arg,\pkgcls@targetdate,\pkgcls@targetlabel}
+\DoNotIndex{\protected,\ProvidesFile,\ProvidesPackage,\relax,\space}
+\DoNotIndex{\^,\@,\unexpanded,\string,\expanded,\detokenize,\meaning}
+\DoNotIndex{\lastnamedcs,\romannumeral,\z@}
+\DoNotIndex{\noexpand,\normalexpanded,\normalunexpanded}
+\DoNotIndex{\par,\protect}
+\DoNotIndex{\the,\toksapp,\tokspre}
+\DoNotIndex{\unprotect,\unless,\usemodule}
+\DoNotIndex{\V}
+\DoNotIndex{\writestatus}
+\DoNotIndex{\xdef}
+\DoNotIndex{\Z,\z}
+\DoNotIndex{\ifcsname}
+\DoNotIndex{\if}
+\DoNotIndex{\ifdefined}
+\DoNotIndex{\ifodd}
+\DoNotIndex{\iftrue}
+\DoNotIndex{\ifx}
+\DoNotIndex{\iffalse}
+\DoNotIndex{\ifnum}
+\DoNotIndex{\else}
+\DoNotIndex{\fi}
+\@gobble\fi % ignoring \ifx etc., but only one \fi
+\@gobble\fi % ignoring \ifx etc., but only one \fi
+\@gobble\fi % ignoring \ifx etc., but only one \fi
+\@gobble\fi % ignoring \ifx etc., but only one \fi
+\@gobble\fi % ignoring \ifx etc., but only one \fi
+\@gobble\fi % ignoring \ifx etc., but only one \fi
+\@gobble\fi % ignoring \ifx etc., but only one \fi
diff --git a/macros/generic/expkv-bundle/preamble-prefixes.tex b/macros/generic/expkv-bundle/preamble-prefixes.tex
new file mode 100644
index 0000000000..a961fc3f24
--- /dev/null
+++ b/macros/generic/expkv-bundle/preamble-prefixes.tex
@@ -0,0 +1,36 @@
+\AddToHook{env/syntax/begin}{\let\prefixes\prefixline}
+\newcount\prefixes@num
+\newcommand\enfprefix{\textcolor{black}}
+\newcommand\allprefix{\textcolor{gray}}
+\newcommand\notprefix{\textcolor{red!80!black}}
+\@ifdefinable\prefixline
+ {\protected\def\prefixline{\hfill\afterassignment\prefixes@\prefixes@num=}}
+\ExplSyntaxOn
+\newcommand\prefixes@place[1]
+ {%
+ \numexpr
+ \int_mod:nn { \int_div_truncate:nn \prefixes@num {#1} } { 10 }
+ \relax
+ }
+\ExplSyntaxOff
+\newcommand\printprefix[2]
+ {%
+ \ifcase\prefixes@place{#1}\or
+ \enfprefix{#2}\or
+ \allprefix{#2}\or
+ \notprefix{#2}\fi
+ }
+\protected\def\prefixes@
+ {%
+ \ifnum\prefixes@num>10
+ \printprefix{1000}{new}
+ \printprefix {100}{also}
+ \printprefix {10}{protected}
+ \printprefix {1}{long}%
+ \else
+ \ifcase\prefixes@num\or
+ \enfprefix{long}\or
+ \allprefix{long}\or
+ \notprefix{long}\fi
+ \fi
+ }
diff --git a/macros/generic/expkv-cs/README.md b/macros/generic/expkv-cs/README.md
deleted file mode 100644
index 481d94ba34..0000000000
--- a/macros/generic/expkv-cs/README.md
+++ /dev/null
@@ -1,32 +0,0 @@
--------------------------------------------------------------------------------
-# expkv-cs -- define expandable key=val macros using expkv
-
-Version 2022-02-13 v1.2
-
-Released under the LaTeX Project Public License v1.3c or later
-See http://www.latex-project.org/lppl.txt
-
-Hosted at https://github.com/Skillmon/tex_expkv-cs
-
--------------------------------------------------------------------------------
-
-Copyright (C) 2020-2022 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 provides means to define expandable key=val taking macros utilizing
-[`expkv`](https://github.com/Skillmon/tex_expkv). It is generic code and only
-requires `expkv` for its parsing. There is a LaTeX package `expkv-cs.sty`
-included to play nice on LaTeX's package loading system, but that package is not
-needed and does not provide more functionality than the generic code in
-`expkv-cs.tex`.
diff --git a/macros/generic/expkv-cs/expkv-cs.dtx b/macros/generic/expkv-cs/expkv-cs.dtx
deleted file mode 100644
index 561dec7af9..0000000000
--- a/macros/generic/expkv-cs/expkv-cs.dtx
+++ /dev/null
@@ -1,3431 +0,0 @@
-% \iffalse meta-comment
-%
-% File: expkv-cs.dtx Copyright (C) 2020-2022 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-cs -- define expandable key=val macros using 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-2022 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-cs.dtx
-and the derived files expkv-cs.pdf
- expkv-cs.sty
- expkv-cs.tex
- t-expkv-cs.tex
-
-\endpreamble
-% stop docstrip adding \endinput
-\postamble
-\endpostamble
-\generate{\file{expkv-cs.sty}{\from{expkv-cs.dtx}{pkg}}}
-\generate{\file{expkv-cs.tex}{\from{expkv-cs.dtx}{tex}}}
-\generate{\file{t-expkv-cs.tex}{\from{expkv-cs.dtx}{ctx}}}
-\ifx\fmtname\nameofplainTeX
- \expandafter\endbatchfile
-\else
- \expandafter\endgroup
-\fi
-%
-\IfFileExists{expkv-cs.tex}{\input{expkv-cs.tex}}{}
-\ProvidesFile{expkv-cs.dtx}
- [\csname ekvcDate\endcsname\ define expandable key=val macros using expkv]
-\PassOptionsToPackage{full}{textcomp}
-\documentclass{l3doc}
-\RequirePackage[oldstylenums,nott]{kpfonts}
-\input{glyphtounicode}
-\pdfgentounicode=1
-\RequirePackage{tcolorbox}
-\newtcolorbox{exresult}[2][]
- {colback=expkvgrey!10!white,colframe=expkvgrey,fontupper=\small,width={#2},#1}
-\newtcbox\exres[1][]
- {
- colback=expkvgrey!10!white
- ,colframe=expkvgrey
- ,size=small
- ,nobeforeafter
- ,tcbox raise base
- ,fontupper=\small
- ,#1
- }
-\RequirePackage{listings}
-\RequirePackage{booktabs}
-\RequirePackage{array}
-\RequirePackage{collcell}
-\RequirePackage{siunitx}
-\RequirePackage{xcolor}
-\RequirePackage{caption}
-\RequirePackage{microtype}
-\RequirePackage{accsupp}
-\lstdefinelanguage{expkvc}[primitive]{TeX}
- {
- ,moretexcs=[4]^^A e-TeX
- {
- expanded,
- numexpr,
- protected,
- }
- ,moretexcs=[5]^^A plain/LaTeX
- {
- approx,
- begin,
- empty,
- item,
- LaTeX,
- makeatletter,makeatother,multicolumn,
- newcommand,newdimen,
- RequirePackage,
- rule,
- TeX,
- textit,texttt,
- usepackage,
- usemodule,
- }
- ,moretexcs=[6]^^A used packages
- {
- ^^A xfp
- fpeval,
- ^^A keyval
- setkeys,
- ^^A yax
- defactiveparameter,storevalue,setparameterlist
- }
- ,moretexcs=[2]^^A expkv-cs macros
- {
- ekvcSplit,ekvcSplitAndForward,ekvcSplitAndUse,
- ekvcHash,ekvcHashAndForward,ekvcHashAndUse,
- ekvcValue,ekvcValueFast,ekvcValueSplit,ekvcValueSplitFast,
- ekvcSecondaryKeys,
- ekvcChange,
- ekvcFlagNew,
- ekvcFlagHeight,
- ekvcFlagRaise,
- ekvcFlagSetTrue,ekvcFlagSetFalse,
- ekvcFlagIf,ekvcFlagIfRaised,
- ekvcFlagReset,
- ekvcFlagGetHeight,ekvcFlagGetHeights,
- ekvcPass
- }
- ,moretexcs=[3]^^A expkv-pkg macros
- {
- ^^A expkv
- ekvdef,ekvdefNoVal,^^A
- ekvlet,ekvletNoVal,ekvletkv,ekvletkvNoVal,^^A
- ekvdefunknown,ekvdefunknownNoVal,^^A
- ekvredirectunknown,ekvredirectunknownNoVal,^^A
- ekvset,ekvsetSneaked,^^A
- ekvsetdef,ekvsetSneakeddef,ekvsetdefSneaked,^^A
- ekvparse,^^A
- ekvVersion,ekvDate,^^A
- ekvifdefined,ekvifdefinedNoVal,ekvifdefinedset,^^A
- ekvbreak,ekvbreakPreSneak,ekvbreakPostSneak,^^A
- ekvsneak,ekvsneakPre,^^A
- ekvchangeset,^^A
- ekvoptarg,ekvoptargTF,^^A
- ekverr,
- ^^A expkv-def
- ekvdefinekeys
- }
- }
-\colorlet{codeparam}{cyan!65!black}
-\def\mylstwd{.55em}
-\lstset
- {
- ,language=expkvc
- ,flexiblecolumns=false
- ,basewidth=\mylstwd
- ,gobble=2
- ,basicstyle=\fontfamily{jkp}\itshape
- ,texcsstyle=*[1]{\bfseries\color{expkvgrey}} ^^A primitives
- ,texcsstyle=*[2]{\bfseries\color{expkvred}} ^^A expkv
- ,texcsstyle=*[3]{\color{expkvred}} ^^A expkv-pkg
- ,texcsstyle=*[4]{\bfseries\color{expkvgrey}} ^^A e-TeX
- ,texcsstyle=*[5]{\bfseries\color{expkvgrey}} ^^A plain/LaTeX macros
- ,texcsstyle=*[6]{} ^^A macros of other packages
- ,commentstyle=\color[gray]{0.4}
- ,literate=
- {\{} {{\CodeUpBf\{}}{1}
- {\}} {{\CodeUpBf\}}}{1}
- {$} {{\CodeUpBf\$}}{1}
- {[} {{\CodeUp[}}{1}
- {]} {{\CodeUp]}}{1}
- {(} {{\CodeUp(}}{1}
- {)} {{\CodeUp)}}{1}
- {*} {{$*$}}{1}
- {1} {{\CodeUp{1}}}{1}
- {2} {{\CodeUp{2}}}{1}
- {3} {{\CodeUp{3}}}{1}
- {4} {{\CodeUp{4}}}{1}
- {5} {{\CodeUp{5}}}{1}
- {6} {{\CodeUp{6}}}{1}
- {7} {{\CodeUp{7}}}{1}
- {8} {{\CodeUp{8}}}{1}
- {9} {{\CodeUp{9}}}{1}
- {0} {{\CodeUp{0}}}{1}
- {##} {{\CodeColored{codeparam}{1}{\#}}}{1}
- {##1}{{\CodeColored{codeparam}{2}{\#1}}}{2}
- {##2}{{\CodeColored{codeparam}{2}{\#2}}}{2}
- {##3}{{\CodeColored{codeparam}{2}{\#3}}}{2}
- {##4}{{\CodeColored{codeparam}{2}{\#4}}}{2}
- {##5}{{\CodeColored{codeparam}{2}{\#5}}}{2}
- {##6}{{\CodeColored{codeparam}{2}{\#6}}}{2}
- {##7}{{\CodeColored{codeparam}{2}{\#7}}}{2}
- {##8}{{\CodeColored{codeparam}{2}{\#8}}}{2}
- {##9}{{\CodeColored{codeparam}{2}{\#9}}}{2}
- {<key>}{{$\langle$}key{$\rangle$}}{5}
- {<set>}{{$\langle$}set{$\rangle$}}{5}
- {<set1>}{{$\langle$}set1{$\rangle$}}{6}
- {<set2>}{{$\langle$}set2{$\rangle$}}{6}
- ^^A,literate=*{<key>}{\key}{4}{<set>}{\set}{4}
- }
-\newcommand*\CodeColored[3]{\textcolor{#1}{\makebox[\dimexpr\mylstwd*#2]{#3}}}
-\newcommand*\CodeUpBf[1]{\makebox[\mylstwd]{\textup{\textbf{#1}}}}
-\newcommand*\CodeUp[1]{\makebox[\mylstwd]{\textup{#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*\example{\par\smallskip\noindent\textit{Example:} \ignorespaces}
-\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\kv{\meta{key}=\meta{value}}
-\newcommand\key{\meta{key}}
-\newcommand\val{\meta{value}}
-\newcommand\set{\meta{set}}
-\newcommand\enflong{\textcolor{black}{long}}
-\newcommand\alllong{\textcolor{gray}{long}}
-\newcommand\notlong{\textcolor{red!80!black}{long}}
-\newcommand\prefixes[1]
- {^^A
- \hfill
- \ifcase\numexpr#1\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,\z@}
-\DoNotIndex{\protected,\ProvidesFile,\ProvidesPackage,\relax,\space,\advance}
-\DoNotIndex{\@,\unexpanded,\string,\expanded,\dimexpr,\global,\glueexpr,\hbox}
-\DoNotIndex{\numexpr,\RequirePackage,\setbox,\the,\unless,\xdef,\gdef,\newcount}
-\DoNotIndex{\number,\detokenize,\meaning,\lccode,\lowercase}
-\DoNotIndex{\^,\\,\@firstofone,\@firstoftwo,\@gobble,\@secondoftwo}
-\DoNotIndex{\ifcsname}
-\DoNotIndex{\ifx}
-\DoNotIndex{\ifodd}
-\DoNotIndex{\ifnum}
-\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
-\@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\expkvc
- \\[\medskipamount]
- \Large define expandable \kv\ macros using \expkv
- }{expkv-cs - define expandable key=val macros using expkv}^^A
- }
- \date{\ekvcDate\space v\ekvcVersion}
- \author{Jonathan P. Spratte\thanks{\protect\randomize{jspratte@yahoo.de}}}
- \DocInput{expkv-cs.dtx}
-\end{document}
-%</driver>^^A=<<
-% \fi
-%
-% \maketitle
-% \renewcommand*\thefootnote{\arabic{footnote}}
-%
-% \begin{abstract}
-% \noindent\parfillskip=0pt
-% \expkvc\ provides two small interfaces to define expandable \kv\ macros using
-% \expkv. It therefore lowers the entrance boundary to expandable \kv\ macros.
-% The stylised name is \expkvc\ but the files use \file{expkv-cs}, 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\ package enables the new possibility of creating \kv\ macros which
-% are fully expandable. The creation of such macros is however cumbersome for
-% the average user. \expkvc\ tries to step in here. It provides interfaces to
-% define \kv\ macros without worrying too much about the implementation. In case
-% you're wondering now, the |cs| in \expkvc\ stands for control sequence,
-% because |def| was already taken by \expkvd\ and ``control sequence'' is the
-% term D.\,E.\,Knuth used in his \TeX book for named commands hence macros
-% (though he also used the term ``macro''). So \expkvc\ defines control
-% sequences for and with \expkv.
-%
-% There are two different approaches supported by this package. The first is
-% splitting the keys up into individual arguments, the second is providing all
-% the keys as a single argument to the underlying macro and getting an
-% individual \val\ by using a hash. Well, actually there is no real hash, just
-% some markers which are parsed, but this shouldn't be apparent to the user, the
-% behaviour matches that of a hash-table.
-%
-% In addition to these two methods of defining a macro with primary keys a way
-% to define secondary keys, which can reference the primary ones, is provided.
-% These secondary keys don't correspond to an argument or an entry in the hash
-% table directly but might come in handy for the average use case. Each macro
-% has its own set of primary and secondary keys.
-%
-% A word of advice you should consider: If your macro doesn't have to be
-% expandable (and often it doesn't) consider not using \expkvc. The interface
-% has some overhead (though it still is fast -- check \autoref{sec:speed}) and
-% the approach has its limits in versatility. If you don't need to be
-% expandable, you should consider either defining your keys manually using
-% \expkv\ or using \expkvd\ for convenience. Or you resort to another \kv\
-% interface. Nevertheless setting up macros with \expkvc, especially with
-% |\ekvcSplit|, is very convenient in my opinion, so if you just want to define
-% a single macro with just a few keys this might be the way to go.
-%
-% \expkvc\ is usable as generic code, as a \LaTeX\ package, and as a \ConTeXt\
-% module. It'll automatically load \expkv\ in the same mode as well. To use it,
-% just use one of
-% \begin{lstlisting}
-% \input expkv-cs % plainTeX
-% \usepackage{expkv-cs} % LaTeX
-% \usemodule[expkv-cs] % ConTeXt
-% \end{lstlisting}
-%
-%
-% \subsection{Define Macros and Primary Keys}\label{sec:define}
-%
-% All macros defined with \expkvc\ have to be previously undefined or have the
-% |\meaning| of |\relax|. This is necessary as there is no way to automatically
-% undefine keys once they are set up (neither \expkv\ nor \expkvc\ keep track of
-% defined keys) -- so to make sure there are no conflicts only new definitions
-% are allowed (that's not the case for individual keys, only for frontend
-% macros).
-%
-%
-% \subsubsection{Primary Keys}\label{sec:primaries}
-%
-% In the following descriptions there will be one argument named \meta{primary
-% keys}. This argument should be a \kv\ list where each \key\ will be one
-% primary key and \val\ the associated initial value. By default all keys are
-% defined short, but you can define long keys by prefixing \key\ with |long|
-% (\emph{e.g.}, \texttt{long name=Jonathan P. Spratte}). You only need |long| if
-% the key should be able to take an explicit |\par| token. Note however that
-% |long| keys are a microscopic grain faster (due to some internals of \expkvc).
-% Only if at least one of the keys was |long| the \meta{cs} in the following
-% defining macros will be |\long|. For obvious reasons there is no possibility
-% to define a macro or key as |\protected|.
-%
-% To allow keys not defined |long| which key names should start with |long|, you
-% can also use the prefix |short| (|short| and |long| are mutually exclusive,
-% which ever comes first defines the behaviour, the latter is considered part of
-% the key name). Note that this is the only reason for |short|'s existance,
-% essentially it does nothing.
-%
-% The consequence culminates in the following:
-% \begin{lstlisting}
-% \ekvcSplit\foo
-% {
-% long short = abc\par
-% ,short long = def
-% }
-% {#1#2}
-% \end{lstlisting}
-% will define a macro |\foo| that knows two primary keys, the first one is
-% called |short|, and accepts explicit |\par| tokens inside its values, the
-% second one is called |long| and will not accept |\par| tokens (leading to a
-% low level \TeX\ error). A description of |\ekvcSplit| follows shortly.
-%
-% There is one exception to these syntax rules of \meta{primary keys}: One can
-% include a key named |...| without a value. If this is found the \meta{cs} will
-% be defined |\long|. Any unknown keys found at use time will end up in a list
-% at this spot. See some examples in \autoref{sec:unknown}.
-%
-% At the moment \expkvc\ doesn't require any internal keys, but I can't foresee
-% whether this will be the case in the future as well, as it might turn out that
-% some features I deem useful can't be implemented without such internal keys.
-% Because of this, please don't use key names starting with
-% \texttt{EKVC\string|} as that should be the private name space.
-%
-%
-% \subsubsection{Split}
-%
-% The split variants will provide the key values as separate arguments. This
-% limits the number of keys for which this is truly useful.
-%
-% \begin{function}{\ekvcSplit}
-% \begin{syntax}
-% \cs{ekvcSplit}\meta{cs}\marg{primary keys}\marg{definition}
-% \end{syntax}
-% This defines \meta{cs} to be a macro taking one mandatory argument which
-% should contain a \kv\ list. The \meta{primary keys} will be defined for this
-% macro (see \autoref{sec:primaries}). The \meta{definition} is the code that
-% will be executed. You can access the \val\ of a \key\ by using a macro
-% parameter from |#1| to |#9|. The order of the macro parameters will be the
-% order provided in the \meta{primary keys} list (so |#1| is the \val\ of the
-% key defined first). With |\ekvcSplit| you can define macros using at most
-% nine primary keys.
-% \end{function}
-% \example The following defines a macro |\foo| that takes the keys |a| and |b|
-% and outputs their values in a textual form:\\
-% \begin{minipage}{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
-% \foo{}
-% \foo{b=e}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
-% \foo{}
-% \foo{b=e}
-% \end{exresult}
-%
-% \begin{function}{\ekvcSplitAndForward}
-% \begin{syntax}
-% \cs{ekvcSplitAndForward}\meta{cs}\marg{after}\marg{primary keys}
-% \end{syntax}
-% This defines \meta{cs} to be a macro taking one mandatory argument which
-% should contain a \kv\ list. You can use as many primary keys as you want
-% with this. The primary keys will be forwarded to \meta{after} as braced
-% arguments (as many as necessary for your primary keys). The order of the
-% braced arguments will be the order of your primary key definitions. In
-% \meta{after} you can use just a single control sequence, or some arbitrary
-% stuff which will be left in the input stream before your braced values (with
-% one set of braces stripped from \meta{after}), so both of the following
-% would be fine:
-% \begin{lstlisting}
-% \ekvcSplitAndForward\foo\foo@aux{keyA = A, keyB = B}
-% \ekvcSplitAndForward\foo{\foo@aux{more args}}{keyA = A, keyB = B}
-% \end{lstlisting}
-% \end{function}
-% \noindent
-% In the first case |\foo@aux| should take at least two arguments (|keyA| and
-% |keyB|), in the second case at least three (|more args|, |keyA|, and |keyB|).
-%
-% \begin{function}{\ekvcSplitAndUse}
-% \begin{syntax}
-% \cs{ekvcSplitAndUse}\meta{cs}\marg{primary keys}
-% \end{syntax}
-% This will roughly do the same as |\ekvcSplitAndForward|, but instead of
-% specifying what will be used after splitting the keys, \meta{cs} will use
-% what follows the \kv\ list. So its syntax will be
-% \end{function}
-% \begin{quote}
-% \ttfamily
-% \meta{cs}\{\key=\val, \ldots\}\marg{after}
-% \end{quote}
-% and the code in |after| should expect at least as many arguments as the number
-% of keys defined for \meta{cs}.
-%
-% \subsubsection{Hash}
-%
-% The hash variants will provide the key values as a single argument in which
-% you can access specific values using a special macro. The implementation might
-% be more convenient and scale better, \emph{but} it is slower (for a
-% rudimentary macro with a single key benchmarking was almost $1.7$ times
-% slower, the root of which being the key access with |\ekvcValue|, not the
-% parsing, and for a key access using |\ekvcValueFast| it was still about $1.2$
-% times slower). So if your macro uses less than ten primary keys, you should
-% consider using the split approach.
-%
-% \begin{function}{\ekvcHash}
-% \begin{syntax}
-% \cs{ekvcHash}\meta{cs}\marg{primary keys}\marg{definition}
-% \end{syntax}
-% This defines \meta{cs} to be a macro taking one mandatory argument which
-% should contain a \kv\ list. You can use as many primary keys as you want.
-% The primary keys will be forwarded as a single argument containing every key
-% to the underlying macro. The underlying macro is defined as
-% \meta{definition}, in which you can access the \val\ of a \key\ by using
-% \texttt{\cs[no-index]{ekvcValue}\{\key\}\{\#1\}}.
-% \end{function}
-% \example This defines an equivalent macro to the |\foo| defined with
-% |\ekvcSplit| earlier:\\
-% \begin{minipage}{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcHash\foo{a=a,b=b}{a is \ekvcValue{a}{#1}.\par
-% b is \ekvcValue{b}{#1}.\par}
-% \foo{}
-% \foo{b=e}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcHash\foo{a=a,b=b}{a is \ekvcValue{a}{#1}.\par
-% b is \ekvcValue{b}{#1}.\par}
-% \foo{}
-% \foo{b=e}
-% \end{exresult}
-%
-% \begin{function}{\ekvcHashAndForward}
-% \begin{syntax}
-% \cs{ekvcHashAndForward}\meta{cs}\marg{after}\marg{primary keys}
-% \end{syntax}
-% This defines \meta{cs} to be a macro taking one mandatory argument which
-% should contain a \kv\ list. You can use as many primary keys as you want.
-% The primary keys will be forwarded as a single argument containing every key
-% to \meta{after}. You can use a single macro for \meta{after} or use some
-% arbitrary stuff, which will be left in the input stream before the hashed
-% \kv\ list with one set of braces stripped. In the
-% macro called in \meta{after} you can access the \val\ of a \key\ by using
-% \texttt{\cs[no-index]{ekvcValue}\{\key\}\{\#1\}} (or whichever argument the
-% hashed \kv\ list will be).
-% \end{function}
-% \example This defines a macro |\foo| processing two keys, and passing the
-% result to |\foobar|:
-% \begin{lstlisting}
-% \ekvcHashAndForward\foo\foobar{a=a,b=b}
-% \newcommand*\foobar[1]{a is \ekvcValue{a}{#1}.\par
-% b is \ekvcValue{b}{#1}.\par}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvcHashAndUse}
-% \begin{syntax}
-% \cs{ekvcHashAndUse}\meta{cs}\marg{primary keys}
-% \end{syntax}
-% This will roughly do the same as |\ekvcHashAndForward|, but instead of
-% specifying what will be used after hashing the keys at install time,
-% \meta{cs} will use what follows the \kv\ list. So its syntax will be
-% \end{function}
-% \begin{quote}
-% \ttfamily
-% \meta{cs}\{\key=\val, \ldots\}\marg{after}
-% \end{quote}
-%
-% \begin{function}{\ekvcValue}
-% \begin{syntax}
-% \cs{ekvcValue}\{\key\}\marg{key list}
-% \end{syntax}
-% This is a safe way to access your keys in a hash variant. \key\
-% is the key which's \val\ you want to use out of the \meta{key list}.
-% \meta{key list} should be the key list argument forwarded to your underlying
-% macro by |\ekvcHash|, |\ekvcHashAndForward|, or |\ekvcHashAndUse|. It will
-% be tested whether the hash function to access that \key\ exists, the \key\
-% argument is not empty, and that the \meta{key list} really contains a \val\
-% of that \key. This macro needs exactly two steps of expansion and if used
-% inside of an |\edef| or |\expanded| context will protect the \val\ from
-% further expanding.
-% \end{function}
-%
-% \begin{function}{\ekvcValueFast}
-% \begin{syntax}
-% \cs{ekvcValueFast}\{\key\}\marg{key list}
-% \end{syntax}
-% This behaves just like |\ekvcValue|, but \emph{without any} safety tests. As
-% a result this is about $1.4$ times faster \emph{but} will throw low level
-% \TeX\ errors eventually if the hash function isn't defined or the \key\
-% isn't part of the \meta{key list} (\emph{e.g.}, because it was defined as a
-% key for another macro -- all macros share the same hash function per \key\
-% name). Use it if you know what you're doing. This macro needs exactly three
-% steps of expansion in the no-errors case.
-% \end{function}
-%
-% \begin{function}{\ekvcValueSplit}
-% \begin{syntax}
-% \cs{ekvcValueSplit}\{\key\}\marg{key list}\marg{next}
-% \end{syntax}
-% If you need a specific \key\ from a \meta{key list} more than once, it'll
-% be a good idea to only extract it once and from then on keep it as a
-% separate argument. Hence the macro \cs{ekvcValueSplit} will extract one
-% specific \key's value from the list and forward it as an argument to
-% \meta{next}, so the result
-% of this will be \meta{next}\marg{value}. This is roughly as fast as
-% |\ekvcValue| and runs the same tests.
-% \end{function}
-% \example The following defines a macro |\foo| which will take three keys.
-% Since the next parsing step will need the value of one of the keys multiple
-% times we split that key off the list (in this example the next step doesn't
-% use the key multiple times for simplicity though), and the entire list is
-% forwarded as the second argument:\\
-% \begin{minipage}{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcHash\foo{a=a,b=b,c=c}
-% {\ekvcValueSplit{a}{#1}\foobar{#1}}
-% \newcommand*\foobar[2]{a is #1.\par
-% b is \ekvcValue{b}{#2}.\par
-% c is \ekvcValue{c}{#2}.\par}
-% \foo{}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcHash\foo{a=a,b=b,c=c}
-% {\ekvcValueSplit{a}{#1}\foobar{#1}}
-% \newcommand*\foobar[2]{a is #1.\par
-% b is \ekvcValue{b}{#2}.\par
-% c is \ekvcValue{c}{#2}.\par}
-% \foo{}
-% \end{exresult}
-%
-% \begin{function}{\ekvcValueSplitFast}
-% \begin{syntax}
-% \cs{ekvcValueSplitFast}\{\key\}\marg{key list}\marg{next}
-% \end{syntax}
-% This behaves just like |\ekvcValueSplit|, but it won't run the same tests,
-% hence it is faster but more error prone, just like the relation between
-% |\ekvcValue| and |\ekvcValueFast|.
-% \end{function}
-%
-%
-% \subsection{Secondary Keys}\label{sec:secondaries}
-%
-% To remove some of the limitations with the approach that each primary key
-% matches an argument or hash entry, you can define secondary keys. Those have
-% to be defined for each macro individually but it doesn't matter whether that
-% macro was a split or a hash variant. If a secondary key references another key
-% it doesn't matter whether that other key is primary or secondary unless
-% otherwise specified.
-%
-% Secondary keys can have a prefix (like |long|) which are called |p|-type
-% prefix and must have a type (like |meta|) which are called |t|-type prefix.
-% Some types might require some |p|-prefixes, while others might forbid those.
-%
-% Please keep in mind that key names shouldn't start with \texttt{EKVC\string|}.
-%
-% \begin{function}{\ekvcSecondaryKeys}
-% \begin{syntax}
-% \cs{ekvcSecondaryKeys}\meta{cs}\{\kv, \ldots\}
-% \end{syntax}
-% This is the front facing macro to define secondary keys. For the macro
-% \meta{cs} define \key\ to have definition \val. The general syntax for \key\
-% should be
-% \begin{quote}\ttfamily\small
-% \meta{prefix} \meta{name}
-% \end{quote}
-% Where \meta{prefix} is a space separated list of optional |p|-type prefixes
-% followed by one |t|-type prefix. The syntax of \val\ is dependent on the
-% used |t|-prefix.
-% \end{function}
-%
-%
-% \subsubsection{\texttt{p}-type Prefixes}
-%
-% There is only one |p|-prefix available, which is |long|.
-%
-% \begin{function}{long}
-% The following key will be defined |\long|.
-% \end{function}
-%
-%
-% \subsubsection{\texttt{t}-type Prefixes}
-%
-% If you're familiar with \expkvd\ you'll notice that the |t|-type prefixes
-% provided here are much fewer. The expansion only concept doesn't allow for
-% great variety in the auto-defined keys.
-%
-% The syntax examples of the |t|-prefixes will show which |p|-prefix will be
-% automatically used by printing those black (\texttt{\enflong}), which
-% will be available in grey (\texttt{\alllong}), and which will be disallowed in
-% red (\texttt{\notlong}). This will be put flush right next to the syntax line.
-%
-% \begin{function}{meta}
-% \begin{syntax}
-% meta \key\ = \{\kv, \ldots\} \prefixes2
-% \end{syntax}
-% With a |meta| key you can set other keys. Whenever \key\ is used the keys in
-% the \kv\ list will be set to the values given there. You can use the \val\
-% given to \key\ by using |#1| in the \kv\ list. The keys in the \kv\ list can
-% be primary and secondary ones.
-% \end{function}
-%
-% \begin{function}{nmeta}
-% \begin{syntax}
-% nmeta \key\ = \{\kv, \ldots\} \prefixes3
-% \end{syntax}
-% An |nmeta| key is like a |meta| key, but it doesn't take a value, so the
-% \kv\ list is static.
-% \end{function}
-%
-% \begin{function}{alias}
-% \begin{syntax}
-% alias \key\ = \marg{key_2} \prefixes3
-% \end{syntax}
-% This assigns the definition of \meta{key_2} to \key. As a result \key\ is an
-% alias for \meta{key_2} behaving just the same. Both the value taking and the
-% |NoVal| version (that's \expkv\ slang for a key not accepting a value) will
-% be copied if they are defined when |alias| is used. Of course, \meta{key_2}
-% has to be defined, be it as a primary or secondary one.
-% \end{function}
-%
-% \begin{function}{default}
-% \begin{syntax}
-% default \key\ = \marg{default} \prefixes3
-% \end{syntax}
-% If \key\ is a defined value taking key, you can define a |NoVal| version
-% with this that will behave as if \key\ was given \meta{default} as its
-% \val. Note that this doesn't change the initial values of primary keys set
-% at definition time in |\ekvcSplit| and friends (see |\ekvcChange| in
-% \autoref{sec:change} for this). \key\ can be a primary or secondary key.
-% \end{function}
-%
-% \begin{function}{enum}
-% \begin{syntax}
-% enum \key\ = \marg{key_2}\{\val, \ldots\} \prefixes2
-% \end{syntax}
-% This defines \key\ to only accept the values given in the list of the second
-% argument of its definition. It forwards the position of \val\ in that list
-% to \meta{key_2} (zero-based). The \meta{key_2} has to already be defined
-% by the time an |enum| key is set up. Each \val\ in the list (and at use
-% time) is treated as a string, so no expansion takes place here.
-%
-% If you use |enum| twice on the same \key\ the new values will again start at
-% zero (so it is possible to define multiple values with the same outcome),
-% however since you can't skip values you'll have to use the same as in the
-% first call for values with just a single variant. There is no interface to
-% delete existing values.
-% \end{function}
-% \example First a small example that might give you an idea of what the
-% description above could mean:\\
-% \begin{minipage}[c]{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcSplit\foo{k-internal=-1}{#1}
-% \ekvcSecondaryKeys\foo
-% {enum k = {k-internal}{a,b,c}}
-% \foo{}\foo{k=a}\foo{k=b}\foo{k=c}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcSplit\foo{k-internal=-1}{#1}
-% \ekvcSecondaryKeys\foo
-% {enum k = {k-internal}{a,b,c}}
-% \foo{}\foo{k=a}\foo{k=b}\foo{k=c}
-% \end{exresult}
-% \example We can define a choice setup that might do different things based on
-% the choice encountered, and the numeric value is easy to parse using
-% |\ifcase|:\\
-% \begin{minipage}[c]{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcSplit\foo{k-internal=-1}
-% {%
-% \ifcase#1
-% is\or
-% This\or
-% easy%
-% \else
-% .%
-% \fi
-% }
-% \ekvcSecondaryKeys\foo
-% {enum k = {k-internal}{a,b,c}}
-% \foo{k=b} \foo{k=a} \foo{k=c}\foo{}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcSplit\foo{k-internal=-1}
-% {^^A
-% \ifcase#1
-% is\or
-% This\or
-% easy^^A
-% \else
-% .^^A
-% \fi
-% }
-% \ekvcSecondaryKeys\foo
-% {enum k = {k-internal}{a,b,c}}
-% \foo{k=b} \foo{k=a} \foo{k=c}\foo{}
-% \end{exresult}
-%
-% \begin{function}{aggregate}
-% \begin{syntax}
-% aggregate \key\ = \marg{primary}\marg{definition} \prefixes3
-% \end{syntax}
-% While all other key types replace the current value of the associated
-% \meta{primary} key, with |aggregate| you can create keys that append or
-% prepend (or whatever you like) the new value to the current one. The
-% value must be exactly two \TeX\ arguments, where \meta{primary} should
-% be the name of a \meta{primary} key, and \meta{definition} the way you want
-% to store the current and the new value. Inside \meta{definition} you
-% can use |#1| for the current, and |#2| for the new value. The
-% \meta{definition} will not expand any further during the entire parsing (so
-% this doesn't allow general processing of current and new values). The
-% resulting \key\ will inherit being either |short| or |long| from the
-% \meta{primary} key.
-% \end{function}
-% \example The following defines an internal key (|k-internal|), which is used
-% to build a comma separated list from each call of the user facing key (|k|):\\
-% \begin{minipage}[c]{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcSplit\foo
-% {k-internal=0,color=red}
-% {\textcolor{#2}{#1}}
-% \ekvcSecondaryKeys\foo
-% {aggregate k = {k-internal}{#1,#2}}
-% \foo{}\par
-% \foo{k=1,k=2,k=3,k=4}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcSplit\foo
-% {k-internal=0,color=red}
-% {\textcolor{#2}{#1}}
-% \ekvcSecondaryKeys\foo
-% {aggregate k = {k-internal}{#1,#2}}
-% \foo{}\par
-% \foo{k=1,k=2,k=3,k=4}
-% \end{exresult}
-%
-% But also more strange stuff could end there, like macros or using the same
-% value multiple times:
-% \begin{lstlisting}
-% \ekvcSecondaryKeys\foo
-% {aggregate k = {k-internal}{\old{#1}\new{#2\old{#1}}}}
-% \end{lstlisting}
-%
-%
-% \begin{function}{flag-bool}
-% \begin{syntax}
-% flag-bool \key\ = \meta{cs} \prefixes3
-% \end{syntax}
-% This is a secondary key that doesn't directly involve any of the primary or
-% secondary keys.
-% This defines \key\ to take a value, which should be either |true| or
-% |false|, and set the flag called \meta{cs} accordingly as a boolean.
-% If \meta{cs} isn't defined yet it will be initialised as a flag.
-% Please also read \autoref{sec:flags}.
-% \end{function}
-%
-% \begin{function}{flag-true,flag-false}
-% \begin{syntax}
-% flag-true \key\ = \meta{cs} \prefixes3
-% \end{syntax}
-% This is a secondary key that doesn't directly involve any of the primary or
-% secondary keys.
-% This defines \key\ to take no value and set the flag called \meta{cs} to
-% |true| or |false|, respectively.
-% If \meta{cs} isn't defined yet it will be initialised as a flag.
-% Please also read \autoref{sec:flags}.
-% \end{function}
-%
-% \begin{function}{flag-raise}
-% \begin{syntax}
-% flag-raise \key\ = \meta{cs} \prefixes3
-% \end{syntax}
-% This is a secondary key that doesn't directly involve any of the primary or
-% secondary keys.
-% This defines \key\ to take no value and raise the flag called \meta{cs}.
-% If \meta{cs} isn't defined yet it will be initialised as a flag.
-% Please also read \autoref{sec:flags}.
-% \end{function}
-%
-%
-% \subsection{Changing the Initial Values}\label{sec:change}
-%
-% \begin{function}{\ekvcChange}
-% \begin{syntax}
-% \cs{ekvcChange}\meta{cs}\{\kv,\ldots\}
-% \end{syntax}
-% This processes the \kv\ list for the macro \meta{cs} to set new defaults for
-% it (meaning the values used if you don't provide anything at use time, not
-% those specified with the |default| secondary key). \meta{cs} should be
-% defined with \expkvc\ (so with any of the methods in \autoref{sec:define}).
-% Inside the \kv\ list both primary and secondary keys can be used. If
-% \meta{cs} was defined |\long| earlier it will still be |\long|, every other
-% \TeX\ prefix will be stripped (but \expkvc\ doesn't support them anywhere
-% else so that should be fine). The resulting new defaults will be stored
-% inside the \meta{cs} locally (just as the original defaults were). If there
-% was an unknown key forwarding added to \meta{cs} (see \autoref{sec:unknown})
-% any unknown key will be stored inside the list of unknown keys as well.
-% |\ekvcChange| is not expandable!
-% \end{function}
-%
-% Consider the following example:\\
-% \begin{minipage}[c]{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
-% \begingroup
-% \ekvcChange\foo{b=B}
-% \foo{} % new defaults
-% \ekvcSecondaryKeys\foo{meta c={a={#1},b={#1}}}
-% \ekvcChange\foo{c=c}
-% \foo{} % newer defaults
-% \endgroup
-% \foo{} % initial defaults
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcSplit\foo{a=a,b=b}{a is #1.\par b is #2.\par}
-% \begingroup
-% \ekvcChange\foo{b=B}
-% \foo{}
-% \ekvcSecondaryKeys\foo{meta c={a={#1},b={#1}}}
-% \ekvcChange\foo{c=c}
-% \foo{}
-% \endgroup
-% \foo{}
-% \end{exresult}
-%
-% As a result with this the typical setup macro could be implemented:
-% \begin{lstlisting}
-% \ekvcHashAndUse\foo{key=a,key=b}
-% \newcommand*\foosetup{\ekvcChange\foo}
-% \end{lstlisting}
-% Of course the usage is limited to a single macro |\foo|, hence this might not
-% be as powerful as similar macros used with other \kv\ interfaces. But at least
-% a few similar macros could be grouped using the same key parsing macro
-% internally.
-%
-%
-% \subsection{Handling Unknown Keys}\label{sec:unknown}
-%
-% If your macro should handle unknown keys without directly throwing an error
-% you can use the special |...| marker in the \meta{primary keys} list. Since
-% those keys will be processed once by \expkv\ they will be forwarded
-% normalised: The key name will be the result of one |\detokenize|, the value
-% will be forwarded as \verb*| {|\meta{value}\verb*|} |, so with spaces around
-% one set of braces (this way, most other \kv\ implementations should parse the
-% correct input).
-%
-% The exact behaviour differs slightly between the two variants (as all keys
-% do). The behaviour inside the split variants will be similar to normal primary
-% keys, the $n$-th argument (corresponding to the position of |...| inside the
-% primary keys list) will contain any unknown key encountered while parsing the
-% argument. And inside the split variant you can use a primary key named |...|
-% at the same time.
-%
-% \example The following will forward any unknown key to |\includegraphics| to
-% control the appearance while processing its own keys:\\
-% \begin{minipage}{.6\linewidth}
-% \begin{lstlisting}
-% \newcommand*\foo{\ekvoptarg\fooKV{}}
-% \ekvcSplitAndForward\fooKV\fooOUT
-% {
-% a=a
-% ,...
-% ,b=b
-% ,...={}
-% }
-% \newcommand\fooOUT[5]
-% {%
-% a is #1 and b is #3.\par
-% \includegraphics[{#2}]{#5}\par
-% \texttt{...} is #4.\par
-% }
-% \foo[width=.5\linewidth, b=c,
-% ...={a stupid key name, but works}]
-% {example-image-duck}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.4\linewidth}
-% \newcommand*\foo{\ekvoptarg\fooKV{}}
-% \ekvcSplitAndForward\fooKV\fooOUT
-% {
-% a=a
-% ,...
-% ,b=b
-% ,...={}
-% }
-% \newcommand\fooOUT[5]
-% {%
-% a is #1 and b is #3.\par
-% \includegraphics[{#2}]{#5}\par
-% \texttt{...} is #4.\par
-% }
-% \foo[width=.5\linewidth, b=c,
-% ...={a stupid key name, but works}]
-% {example-image-duck}
-% \end{exresult}
-%
-% Inside the hash variants the unknown keys list will be put inside the hash
-% named |...| (we have to use some name, so why not this). As a consequence a
-% primary key named |...| would clash with the unknown key handler. If you still
-% used such a key it would remove any unknown key stored there until that point
-% and replace the list with its value.
-%
-% \example The following is more or less equivalent to the example above, but
-% with the hash variant, and it will not contain the primary |...| key. We have
-% to make sure that |\includegraphics| sees the \kv\ list, so need to expand
-% |\ekvcValue{...}{#1}| before |\includegraphics| parses it.\\
-% \begin{minipage}{.76\linewidth}
-% \begin{lstlisting}
-% \newcommand*\foo{\ekvoptarg\fooKV{}}
-% \ekvcHashAndForward\fooKV\fooOUT
-% {a=a, b=b, ...}
-% \newcommand\fooOUT[2]
-% {%
-% a is \ekvcValue{a}{#1} and
-% b is \ekvcValue{b}{#1}.\par
-% \expanded{\noexpand\includegraphics
-% [{\ekvcValue{...}{#1}}]}
-% {#2}\par
-% }
-% \foo[width=\linewidth, b=c]
-% {example-image-duck-portrait}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.24\linewidth}
-% \newcommand*\foo{\ekvoptarg\fooKV{}}
-% \ekvcHashAndForward\fooKV\fooOUT
-% {a=a, b=b, ...}
-% \newcommand\fooOUT[2]
-% {%
-% a is \ekvcValue{a}{#1} and
-% b is \ekvcValue{b}{#1}.\par
-% \expanded{\noexpand\includegraphics
-% [{\ekvcValue{...}{#1}}]}
-% {#2}\par
-% }
-% \foo[width=\linewidth, b=c]
-% {example-image-duck-portrait}
-% \end{exresult}
-%
-%
-% \subsection{Flags}\label{sec:flags}
-%
-% The idea of flags is taken from \pkg{expl3}. They provide a way to store
-% numerical information expandably, however only incrementing and accessing
-% works expandably, decrementing is unexpandable. A flag has a height, which
-% is a numerical value, and which can be raised by $1$. Flags come at a high
-% computational cost (accessing them is slow and they require more memory than
-% normal \TeX\ data types like registers, both getting linearly worse with the
-% height), so don't use them if not necessary.
-%
-% The state of flags is always changed locally to the current group, but not to
-% the current macro, so if you're using one of the |t|-types involving flags
-% bear in mind that they can affect other macros using the same flags at the
-% current group level!
-%
-% \expkvc\ provides some macros to access, alter, and use flags. Flags of
-% \expkvc\ don't share a name space with the flags of \pkg{expl3}.
-%
-% \begin{function}{\ekvcFlagNew}
-% \begin{syntax}
-% \cs{ekvcFlagNew}\meta{flag}
-% \end{syntax}
-% This initialises the macro \meta{flag} as a new flag. It isn't checked
-% whether the macro \meta{flag} is currently undefined. A \meta{flag} will
-% expand to the flag's current height with a trailing space (so you can use it
-% directly with |\ifnum| for example and it will terminate the number scanning
-% on its own).
-% \end{function}
-%
-% All other macros dealing with flags take as a parameter a macro defined as a
-% \meta{flag} with |\ekvcFlagNew|.
-%
-% \begin{function}{\ekvcFlagHeight}
-% \begin{syntax}
-% \cs{ekvcFlagHeight}\meta{flag}
-% \end{syntax}
-% This expands to the current height of \meta{flag} in a single step of
-% expansion (without a trailing space).
-% \end{function}
-%
-% \begin{function}{\ekvcFlagRaise}
-% \begin{syntax}
-% \cs{ekvcFlagRaise}\meta{flag}
-% \end{syntax}
-% This expandably raises the height of \meta{flag} by $1$.
-% \end{function}
-%
-% \begin{function}{\ekvcFlagSetTrue,\ekvcFlagSetFalse}
-% \begin{syntax}
-% \cs{ekvcFlagSetTrue}\meta{flag}
-% \end{syntax}
-% By interpreting an even value as false and an odd value as true we can use a
-% flag as a boolean. This expandably sets \meta{flag} to true or false,
-% respectively, by raising it if necessary.
-% \end{function}
-%
-% \begin{function}{\ekvcFlagIf}
-% \begin{syntax}
-% \cs{ekvcFlagIf}\meta{flag}\marg{true}\marg{false}
-% \end{syntax}
-% This interprets a \meta{flag} as a boolean and expands to either \meta{true}
-% or \meta{false}.
-% \end{function}
-%
-% \begin{function}{\ekvcFlagIfRaised}
-% \begin{syntax}
-% \cs{ekvcFlagIfRaised}\meta{flag}\marg{true}\marg{false}
-% \end{syntax}
-% This tests whether the \meta{flag} is raised, meaning it has a height
-% greater than zero, and if so expands to \meta{true} else to \meta{false}.
-% \end{function}
-%
-% \begin{function}{\ekvcFlagReset}
-% \begin{syntax}
-% \cs{ekvcFlagReset}\meta{flag}
-% \end{syntax}
-% This resets a flag (so restores its height to $0$). This operation is
-% \emph{not} expandable and done locally. If you really intend to use flags
-% you can reset them every now and then to keep the performance hit low.
-% \end{function}
-%
-% \begin{function}{\ekvcFlagGetHeight}
-% \begin{syntax}
-% \cs{ekvcFlagGetHeight}\meta{flag}\marg{next}
-% \end{syntax}
-% This retrieves the current height of the \meta{flag} and provides it as a
-% braced argument to \meta{next}, leaving \meta{next}\marg{height} in the
-% input stream.
-% \end{function}
-%
-% \begin{function}{\ekvcFlagGetHeights}
-% \begin{syntax}
-% \cs{ekvcFlagGetHeights}\marg{flag-list}\marg{next}
-% \end{syntax}
-% This retrieves the current height of each \meta{flag} in the
-% \meta{flag-list} and provides them as a single argument to \meta{next}.
-% Inside that argument each height is enclosed in a set of braces
-% individually. The \meta{flag-list} is just a single argument containing the
-% \meta{flag}s.
-% So a usage like
-% \texttt
-% {^^A
-% \cs[no-index]{ekvcFlagGetHeights}\hskip0pt^^A
-% \{\cs[no-index]{myflagA}\cs[no-index]{myflagB}\}\hskip0pt^^A
-% \{\cs[no-index]{stuff}\}^^A
-% }
-% will expand to
-% \texttt{\cs[no-index]{stuff}\{\marg{height-A}\marg{height-B}\}}.
-% \end{function}
-%
-%
-% \subsection{Further Examples}\label{sec:examples}
-%
-% How could a documentation be a good documentation without enough basic
-% examples? Say we want to define a small macro expanding to some character
-% description (who knows why this has to be expandable?). A character
-% description will not have too many items to it, so we use |\ekvcSplit| (the
-% comments with the parameter numbers are of course not necessary and just ease
-% reading the example).
-% \begin{lstlisting}
-% \ekvcSplit\character
-% {
-% name=John Doe, % #1
-% age=any, % #2
-% nationality=the Universe, % #3
-% hobby=to exist, % #4
-% type=Mister, % #5
-% pronoun=He, % #6
-% possessive=his, % #7
-% }
-% {#1 is a #5 from #3. #6 is of #2 age and #7 hobby is #4.\par}
-% \end{lstlisting}
-% Also we want to give some short cuts so that it's easier to describe several
-% persons.
-% \begin{lstlisting}
-% \ekvcSecondaryKeys\character
-% {
-% alias pro = pronoun,
-% alias pos = possessive,
-% nmeta me =
-% {
-% name=Jonathan,
-% age=a young,
-% nationality=Germany,
-% hobby=\TeX\ coding,
-% },
-% meta lady =
-% {type=Lady, pronoun=She, possessive=her, name=Jane Doe, #1},
-% nmeta paulo =
-% {
-% name=Paulo,
-% type=duck,
-% age=a young,
-% nationality=Brazil,
-% hobby=to quack,
-% }
-% }
-% \end{lstlisting}
-% Now we can describe people using
-% \begin{lstlisting}
-% \character{}
-% \character{me}
-% \character{paulo}
-% \character
-% {lady={name=Evelyn,nationality=Ireland,age=the best,hobby=reading}}
-% \character
-% {
-% name=Our sun, type=star, nationality=our solar system, pro=It,
-% age=an old, pos=its, hobby=shining
-% }
-% \end{lstlisting}
-% As one might see, the |lady| key could actually have been an |nmeta| key as
-% well, as all that is done with the argument is using it as a \kv\ list.
-%
-% The result of only the first two usages would be:
-% \begin{exresult}{\linewidth}
-% \ekvcSplit\character
-% {
-% name=John Doe,
-% age=any,
-% nationality=the Universe,
-% hobby=to exist,
-% type=Mister,
-% pronoun=He,
-% possessive=his,
-% }
-% {#1 is a #5 from #3. #6 is of #2 age and #7 hobby is #4.\par}
-% \ekvcSecondaryKeys\character
-% {
-% alias pro = pronoun,
-% alias pos = possessive,
-% nmeta me =
-% {
-% name=Jonathan,
-% age=a young,
-% nationality=Germany,
-% hobby=\TeX\ coding,
-% },
-% meta lady =
-% {type=Lady, pronoun=She, possessive=her, name=Jane Doe, #1},
-% nmeta paulo =
-% {
-% name=Paulo,
-% type=duck,
-% age=a young,
-% nationality=Brazil,
-% hobby=to quack,
-% }
-% }
-% \character{}
-% \character{me}
-% \end{exresult}
-%
-% Using \pkg{xparse} or \expkv's \cs{ekvoptarg} or \cs{ekvoptargTF} and
-% forwarding arguments one can easily define \kv\ macros with actual optional
-% and mandatory arguments as well. A small nonsense example (which should
-% perhaps use |\ekvcSplitAndForward| instead of |\ekvcHashAndForward| since it
-% only uses four keys and one other argument -- and isn't expandable since it
-% uses a \env{tabular} environment, so it would've been better to use a more
-% feature rich \kv\ interface most likely, \emph{e.g.}, the one provided by
-% \expkvd):
-% \begin{lstlisting}
-% \makeatletter
-% \newcommand*\nonsense{\ekvoptarg\nonsense@a{}}
-% \ekvcHashAndForward\nonsense@a\nonsense@b
-% {
-% keyA = A,
-% keyB = B,
-% keyC = c,
-% keyD = d,
-% }
-% \newcommand*\nonsense@b[2]
-% {%
-% \begin{tabular}{lll}
-% key & A & \ekvcValue{keyA}{#1} \\
-% & B & \ekvcValue{keyB}{#1} \\
-% & C & \ekvcValue{keyC}{#1} \\
-% & D & \ekvcValue{keyD}{#1} \\
-% \multicolumn{2}{l}{mandatory} & #2 \\
-% \end{tabular}%
-% }
-% \makeatother
-% \end{lstlisting}
-% And then we would be able to do some nonsense
-% \begin{lstlisting}
-% \nonsense{}
-% \nonsense[keyA=hihi]{haha}
-% \nonsense[keyA=hihi, keyB=A]{hehe}
-% \nonsense[keyC=huhu, keyA=hihi, keyB=A]{haha}
-% \end{lstlisting}
-% resulting in
-% \begin{exresult}{\linewidth}
-% \makeatletter
-% \newcommand*\nonsense{\ekvoptarg\nonsense@a{}}
-% \ekvcHashAndForward\nonsense@a\nonsense@b
-% {
-% keyA = A,
-% keyB = B,
-% keyC = c,
-% keyD = d,
-% }
-% \newcommand*\nonsense@b[2]
-% {%
-% \begin{tabular}{lll}
-% key & A & \ekvcValue{keyA}{#1} \\
-% & B & \ekvcValue{keyB}{#1} \\
-% & C & \ekvcValue{keyC}{#1} \\
-% & D & \ekvcValue{keyD}{#1} \\
-% \multicolumn{2}{l}{mandatory} & #2 \\
-% \end{tabular}%
-% }
-% \makeatother
-% \nonsense{}
-% \nonsense[keyA=hihi]{haha}
-% \nonsense[keyA=hihi, keyB=A]{hehe}
-% \nonsense[keyC=huhu, keyA=hihi, keyB=A]{haha}
-% \end{exresult}
-%
-%
-% \subsection{Freedom for Keys!}
-%
-% If this was the \TeX book this subsection would have a double bend sign. Not
-% because it is overly complicated, but because it shows things which could
-% break \expkvc's expandability and its alignment safety. This is for
-% experienced users wanting to get the most flexibility and knowing what they
-% are doing.
-%
-% In case you're wondering, it is possible to define other keys than the
-% primaries and the secondary types listed in \autoref{sec:secondaries} for a
-% macro defined with \expkvc\ by using the low-level interface of \expkv\ or
-% even the interface provided by \expkvd. The set name used for \expkvc's keys
-% is the macro name, including the leading backslash, or more precisely
-% |\string|\meta{cs} is used. This can be exploited to define additional keys
-% with arbitrary code. Consider the following \emph{bad} example:
-% \begin{lstlisting}
-% \ekvcSplit\foo{a=A,b=B}{a is #1.\par b is #2\par}
-% \protected\ekvdef{\string\foo}{c}{\def\fooC{#1}}
-% \end{lstlisting}
-% This would define a key named |c| that will store its value inside a macro.
-% The issue with this is that this can't be done expandably. As a result, the
-% macro |\foo| isn't always expandable any more (not that bad if this was never
-% required; killjoy if it was) and as soon as the key |c| is used, it is also no
-% longer alignment safe\footnote{This means that the \kv-list can't contain
-% alignment markers that are not inside an additional set of braces if used
-% inside a \TeX\ alignment.}
-% (might be bad depending on the usage).
-%
-% So why do I show you this? Because we could as well do something useful like
-% create a key that pre-parses the input and after that passes the parsed value
-% on. This parsing would have to be completely expandable though. For the
-% pass-on part we can use the following function:
-%
-% \begin{function}{\ekvcPass}
-% \begin{syntax}
-% \cs{ekvcPass}\meta{cs}\marg{key}\marg{value}
-% \end{syntax}
-% This passes \meta{value} on to \meta{key} for the \expkvc-macro \meta{cs}.
-% It should be used inside the key parsing of a macro defined with \expkvc,
-% else this most likely results in a low level \TeX\ error. You can't forward
-% anything to the special unknown key handler |...| as that is no defined key.
-% \end{function}
-%
-% With this we could for example split the value of a key at a hyphen and pass
-% the parts to different keys:\\
-% \begin{minipage}[c]{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcSplit\foo{a=A,b=B}{a is #1.\par b is #2.\par}
-% \ekvdef{\string\foo}{c}{\fooSplit#1\par}
-% \def\fooSplit#1-#2\par
-% {\ekvcPass\foo{a}{#1}\ekvcPass\foo{b}{#2}}
-% \foo{}
-% \foo{c=1-2}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcSplit\foo{a=A,b=B}{a is #1.\par b is #2.\par}
-% \ekvdef{\string\foo}{c}{\fooSplit#1\par}
-% \def\fooSplit#1-#2\par{\ekvcPass\foo{a}{#1}\ekvcPass\foo{b}{#2}}
-% \foo{}
-% \foo{c=1-2}
-% \end{exresult}
-%
-% Additionally, there is a more general version of the |aggregate| secondary key
-% type (described in \autoref{sec:secondaries}), namely the |process| key type:
-%
-% \begin{function}{process}
-% \begin{syntax}
-% process \key\ = \marg{primary}\marg{definition} \prefixes2
-% \end{syntax}
-% This will grab the current value of a \meta{primary} key as |#1| (without
-% changing the current value) and the new value as |#2| and leave all the
-% processing to \meta{definition}. You should use |\ekvcPass| to forward the
-% values afterwards. Unlike |aggregate| you can specify whether the \key\
-% should be long or not, this isn't inherited from the \meta{primary} key.
-% Keep in mind that you could easily break things here if your code does not
-% work by expansion.
-% \end{function}
-% \example We could define a key that only accepts values greater than the
-% current value with this:\\
-% \begin{minipage}[c]{.75\linewidth}
-% \begin{lstlisting}
-% \ekvcSplit\foo{internal=5}{a is #1.\par}
-% \ekvcSecondaryKeys\foo
-% {
-% process a={internal}
-% {%
-% \ifnum#1<#2
-% \ekvcPass\foo{internal}{#2}%
-% \fi
-% }
-% }
-% \foo{a=1}
-% \foo{a=5}
-% \foo{a=9}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \ekvcSplit\foo{internal=5}{a is #1.\par}
-% \ekvcSecondaryKeys\foo
-% {process a={internal}{\ifnum#1<#2 \ekvcPass\foo{internal}{#2}\fi}}
-% \foo{a=1}
-% \foo{a=5}
-% \foo{a=9}
-% \end{exresult}
-%
-%
-% \subsection{Speed Considerations}\label{sec:speed}
-%
-% As already mentioned in the introduction there are some speed considerations
-% implied if you choose to define macros via \expkvc. However the overhead isn't
-% the factor which should hinder you to use \expkvc\ if you found a reasonable
-% use case. The key-parsing is still faster than with most other \kv\ packages
-% (see the ``Comparisons'' subsection in the \expkv\ documentation).
-%
-% The speed considerations in this subsection use the first example of
-% \autoref{sec:examples} as the benchmark. So we have seven keys and a short
-% sentence which should be typeset. For comparisons I use the following
-% equivalent \expkvd\ definitions. Each result is the average between changing
-% no keys from their initial values and altering four. Furthermore I'll compare
-% three variants of \expkvc\ with the \expkvd\ definitions, namely the split
-% example from above, a hash variant using |\ekvcValue| and a hash variant using
-% |\ekvcValueFast|.
-% \begin{lstlisting}
-% \usepackage{expkv-def}
-% \ekvdefinekeys{keys}
-% {%
-% ,store name = \KEYSname
-% ,initial name = John Doe
-% ,store age = \KEYSage
-% ,initial age = any
-% ,store nationality = \KEYSnationality
-% ,initial nationality = the Universe
-% ,store hobby = \KEYShobby
-% ,initial hobby = to exist
-% ,store type = \KEYStype
-% ,initial type = Mister
-% ,store pronoun = \KEYSpronoun
-% ,initial pronoun = He
-% ,store possessive = \KEYSpossessive
-% ,initial possessive = his
-% }
-% \newcommand*\KEYS[1]
-% {%
-% \begingroup
-% \ekvset{keys}{#1}%
-% \KEYSname\ is a \KEYStype\ from \KEYSnationality.
-% \KEYSpronoun\ is of \KEYSage\ age and
-% \KEYSpossessive\ hobby is \KEYShobby.%
-% \endgroup
-% }
-% \end{lstlisting}
-%
-% The first comparison removes the typesetting part from all the definitions, so
-% that only the key parsing is compared. In this comparison the |\ekvcValue|
-% and |\ekvcValueFast| variants will not differ, as they are exactly the same
-% until the key usage. We find that the split approach is $1.4$ times slower
-% than the \expkvd\ setup and the hash variants end up in the middle at $1.17$
-% times slower.
-%
-% Next we put the typesetting part back in. Every call of the macros will
-% typeset the sentences into a box register in horizontal mode. With the
-% typesetting part (which includes the accessing of values) the fastest remains
-% the \expkvd\ definitions, but split is close at $1.16$ times slower, followed
-% by the hash variant with fast accesses at $1.36$ times slower, and the safe
-% hash access variant ranks in the slowest $1.8$ times slower than \expkvd.
-%
-% Just in case you're wondering now, a simple macro taking seven arguments is
-% $30$ to $40$ times faster than any of those in the argument grabbing and \kv\
-% parsing part and only $1.5$ to $2.8$ times faster if the typesetting part is
-% factored in. So the real choke isn't the parsing.
-%
-% So to summarise this, if you have a use case for expandable \kv\
-% parsing macros you should go on and define them using \expkvc. If you just
-% want to define a simple macro with a few keys |\ekvcSplit| might be the
-% easiest interface there is. If you have a reasonable use case for \kv\ parsing
-% macros but defining them expandable isn't necessary for your use you should
-% take advantage of the greater flexibility of non-expandable \kv\ setups (but
-% if you're after maximum speed there aren't that many \kv\ parsers beating
-% \expkvc). And if you are after maximum performance maybe ditching the \kv\
-% interface altogether is a good idea, but depending on the number of arguments
-% your interface might get convoluted.
-%
-%
-% \subsection{Useless Macros}
-%
-% Perhaps these macros aren't completely useless, but I figured from a user's
-% point of view I wouldn't know what I should do with these.
-%
-% \begin{function}{\ekvcDate,\ekvcVersion}
-% These two macros store the version and the date of the package/generic code.
-% \end{function}
-%
-%
-% \subsection{Bugs}
-%
-% Of course I don't think there are any bugs (who would knowingly distribute
-% buggy software as long as he isn't a multi-million dollar corporation?). But
-% if you find some please let me know. For this one might find my email address
-% on the first page or file an issue on Github:
-% \url{https://github.com/Skillmon/tex_expkv-cs}
-%
-%
-% \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}^^A>>=
-%^^A the LaTeX package >>=
-% \subsection{The \LaTeX\ Package}
-% Just like for \expkv\ we provide a small \LaTeX\ package that sets up things
-% such that we behave nicely on \LaTeX\ packages and files system. It'll
-% |\input| the generic code which implements the functionality.
-% \gobbledocstriptag
-%<*pkg>
-% \begin{macrocode}
-\RequirePackage{expkv}
-\def\ekvc@tmp
- {%
- \ProvidesFile{expkv-cs.tex}%
- [%
- \ekvcDate\space v\ekvcVersion\space
- define expandable key=val macros using expkv%
- ]%
- }
-\input{expkv-cs.tex}
-\ProvidesPackage{expkv-cs}%
- [%
- \ekvcDate\space v\ekvcVersion\space
- define expandable key=val macros using expkv%
- ]
-% \end{macrocode}
-% \gobbledocstriptag
-%</pkg>
-%^^A=<<
-%^^A the ConTeXt module >>=
-% \subsection{The \ConTeXt\ module}
-% \gobbledocstriptag
-%<*ctx>
-% \begin{macrocode}
-\writestatus{loading}{ConTeXt User Module / expkv-cs}
-\usemodule[expkv]
-\unprotect
-\input expkv-cs.tex
-\writestatus{loading}
- {ConTeXt User Module / expkv-cs / Version \ekvcVersion\space loaded}
-\protect\endinput
-% \end{macrocode}
-% \gobbledocstriptag
-%</ctx>
-%^^A=<<
-%^^A main file >>=
-% \subsection{The Generic Code}
-% The rest of this implementation will be the generic code.
-% \gobbledocstriptag
-%<*tex>
-%
-% Load \expkv\ if the package didn't already do so -- since \expkv\ has
-% safeguards against being loaded twice this does no harm and the overhead
-% isn't that big. Also we reuse some of the internals of \expkv\ to save us from
-% retyping them.
-% \begin{macrocode}
-\input expkv
-% \end{macrocode}
-%
-% We make sure that \file{expkv-cs.tex} is only input once:
-% \begin{macrocode}
-\expandafter\ifx\csname ekvcVersion\endcsname\relax
-\else
- \expandafter\endinput
-\fi
-% \end{macrocode}
-%
-% \begin{macro}{\ekvcVersion,\ekvcDate}
-% We're on our first input, so lets store the version and date in a macro.
-% \begin{macrocode}
-\def\ekvcVersion{1.2}
-\def\ekvcDate{2022-02-13}
-% \end{macrocode}
-% \end{macro}
-%
-% If the \LaTeX\ format is loaded we want to be a good file and report back who
-% we are, for this the package will have defined |\ekvc@tmp| to use
-% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
-% \begin{macrocode}
-\csname ekvc@tmp\endcsname
-% \end{macrocode}
-%
-% Store the category code of |@| to later be able to reset it and change it to
-% 11 for now.
-% \begin{macrocode}
-\expandafter\chardef\csname ekvc@tmp\endcsname=\catcode`\@
-\catcode`\@=11
-% \end{macrocode}
-% |\ekvc@tmp| will be reused later, but we don't need it to ever store
-% information long-term after \expkvc\ was initialized.
-%
-% \begin{macro}[internal]{\ekvc@tripledots}
-% This macro just serves as a marker for a comparison to allow the syntax
-% for the unknown key handlers.
-% \begin{macrocode}
-\def\ekvc@tripledots{...}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@keycount}
-% We'll need to keep count how many keys must be defined for each macro in the
-% |split| variants.
-% \begin{macrocode}
-\newcount\ekvc@keycount
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@long,\ekvc@any@long}
-% Some macros will have to be defined long. These two will be let to |\long|
-% when this should be the case.
-% \begin{macrocode}
-\let\ekvc@long\ekv@empty
-\let\ekvc@any@long\ekv@empty
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@ifdefined}
-% We want to test whether a macro is already defined. This test checks for a
-% defined macro that isn't |\relax|.
-% \begin{macrocode}
-\long\def\ekvc@ifdefined#1%
- {%
- \ifdefined#1%
- \ifx\relax#1%
- \ekv@fi@gobble
- \fi
- \@firstofone
- \ekv@fi@firstoftwo
- \fi
- \@secondoftwo
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@ekvset@pre@expander,
-% \ekvc@ekvset@pre@expander@a,
-% \ekvc@ekvset@pre@expander@b
-% }
-% This macro expands |\ekvset| twice so that the first two steps of expansion
-% don't have to be made every time the \expkvc\ macros are used. We have to do
-% a little magic trick to get the macro parameter |#1| for the macro
-% definition this is used in, even though we're calling |\unexpanded|. We do
-% that by splitting the expanded |\ekvset| at some marks and place |##1| in
-% between. At this spot we also add |\ekv@alignsafe| and |\ekv@endalignsafe|
-% to ensure that macros created with \expkvc\ are alignment safe.
-% \begin{macrocode}
-\def\ekvc@ekvset@pre@expander#1%
- {%
- \expandafter\ekvc@ekvset@pre@expander@a\ekvset{#1}\ekvc@stop\ekvc@stop
- }
-\def\ekvc@ekvset@pre@expander@a
- {%
- \expandafter\ekvc@ekvset@pre@expander@b
- }
-\def\ekvc@ekvset@pre@expander@b#1\ekvc@stop#2\ekvc@stop
- {%
- \ekv@unexpanded\expandafter{\ekv@alignsafe}%
- \ekv@unexpanded{#1}##1\ekv@unexpanded{#2}%
- \ekv@unexpanded\expandafter{\ekv@endalignsafe}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcSplitAndUse}
-% The first user macro we want to set up can be reused for
-% \cs[no-index]{ekvcSplitAndForward} and \cs[no-index]{ekvcSplit}. We'll split
-% this one up so that the test whether the macro is already defined doesn't
-% run twice.
-% \begin{macrocode}
-\protected\long\def\ekvcSplitAndUse#1#2%
- {%
- \let\ekvc@helpers@needed\@firstoftwo
- \ekvc@ifdefined#1%
- {\ekvc@err@already@defined#1}%
- {\ekvcSplitAndUse@#1{}{#2}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvcSplitAndUse@}
-% The actual macro setting up things. We need to set some variables, forward
-% the key list to |\ekvc@SetupSplitKeys|, and afterwards define the front
-% facing macro to call |\ekvset| and put the initials and the argument sorting
-% macro behind it. The internals |\ekvc@any@long|, |\ekvc@initials| and
-% |\ekvc@keycount| will be set correctly by |\ekvc@SetupSplitKeys|.
-% \begin{macrocode}
-\protected\long\def\ekvcSplitAndUse@#1#2#3%
- {%
- \edef\ekvc@set{\string#1}%
- \ekvc@SetupSplitKeys{#3}%
- \ekvc@helpers@needed
- {%
- \ekvc@any@long\edef#1##1%
- {%
- \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
- \ekv@unexpanded\expandafter
- {\csname ekvc@split@\the\ekvc@keycount\endcsname}%
- \ekv@unexpanded\expandafter{\ekvc@initials{}#2}%
- }%
- }%
- {%
- \ekvc@any@long\edef#1##1%
- {%
- \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
- \ekv@unexpanded{#2}%
- \ekv@unexpanded\expandafter{\ekvc@initials}%
- }%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \begin{macro}{\ekvcSplitAndForward}
-% This just reuses |\ekvcSplitAndUse@| with a non-empty second argument,
-% resulting in that argument to be called after the splitting.
-% \begin{macrocode}
-\protected\long\def\ekvcSplitAndForward#1#2#3%
- {%
- \let\ekvc@helpers@needed\@firstoftwo
- \ekvc@ifdefined#1%
- {\ekvc@err@already@defined#1}%
- {\ekvcSplitAndUse@#1{{#2}}{#3}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcSplit}
-% The first half is just |\ekvcSplitAndForward| then we define the macro to
-% which the parsed key list is forwarded. There we need to allow for up to
-% nine arguments.
-% \begin{macrocode}
-\protected\long\def\ekvcSplit#1#2#3%
- {%
- \let\ekvc@helpers@needed\@secondoftwo
- \ekvc@ifdefined#1%
- {\ekvc@err@already@defined#1}%
- {%
- \expandafter
- \ekvcSplitAndUse@\expandafter#1\csname ekvc@\string#1\endcsname{#2}%
- \ifnum\ekvc@keycount<1
- \ekvc@any@long\expandafter\def\csname ekvc@\string#1\endcsname{#3}%
- \else
- \ifnum\ekvc@keycount>9
- \ekvc@err@toomany{#1}%
- \let#1\ekvc@undefined
- \else
- \ekvcSplit@build@argspec
- \ekvc@any@long\expandafter
- \def\csname ekvc@\string#1\expandafter\endcsname\ekvc@tmp{#3}%
- \fi
- \fi
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvcSplit@build@argspec,\ekvcSplit@build@argspec@}
-% \begin{macrocode}
-\protected\def\ekvcSplit@build@argspec
- {%
- \begingroup
- \edef\ekvc@tmp
- {\endgroup\def\ekv@unexpanded{\ekvc@tmp}{\ekvcSplit@build@argspec@{1}}}%
- \ekvc@tmp
- }
-\def\ekvcSplit@build@argspec@#1%
- {%
- \ifnum#1>\ekvc@keycount
- \ekv@fi@gobble
- \fi
- \@firstofone
- {%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@#1\endcsname####}#1%
- \expandafter\ekvcSplit@build@argspec@\expandafter{\the\numexpr#1+1}%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@SetupSplitKeys, \ekvc@SetupSplitKeys@a, \ekvc@SetupSplitKeys@b,
-% \ekvc@SetupSplitKeys@c, \ekvc@SetupSplitKeys@d, \ekvc@SetupSplitKeys@e,
-% \ekvc@SetupSplitKeys@check@unknown,\ekvc@SetupSplitKeys@unknown
-% }
-% These macros parse the list of keys and set up the key macros. First we need
-% to initialise some macros and start |\ekvparse|.
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupSplitKeys
- {%
- \ekvc@keycount=\ekv@zero
- \let\ekvc@any@long\ekv@empty
- \let\ekvc@initials\ekv@empty
- \ekvparse\ekvc@SetupSplitKeys@check@unknown\ekvc@SetupSplitKeys@a
- }
-% \end{macrocode}
-% Then we need to step the key counter for each key. Also we have to check
-% whether this key has a |long| prefix so we initialise |\ekvc@long|.
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupSplitKeys@a#1%
- {\expandafter\ekvc@SetupSplitKeys@b\detokenize{#1}\ekvc@stop}
-\protected\def\ekvc@SetupSplitKeys@b#1\ekvc@stop
- {%
- \advance\ekvc@keycount1
- \let\ekvc@long\ekv@empty
- \ekvc@ifspace{#1}%
- {\ekvc@SetupSplitKeys@c#1\ekvc@stop}%
- {\ekvc@SetupSplitKeys@d{#1}}%
- }
-% \end{macrocode}
-% If there was a space, there might be a prefix. If so call the prefix macro,
-% else call the next step |\ekvc@SetupSplitKeys@d| which will define the key
-% macro and add the key's value to the initials list.
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupSplitKeys@c#1 #2\ekvc@stop
- {%
- \ekv@ifdefined{ekvc@split@p@#1}%
- {\csname ekvc@split@p@#1\endcsname{#2}}%
- {\ekvc@SetupSplitKeys@d{#1 #2}}%
- }
-% \end{macrocode}
-% The inner definition is grouped, because we don't want to actually define
-% the marks we build with |\csname|. We have to append the value to the
-% |\ekvc@initials| list here with the correct split mark. The key macro will
-% read everything up to those split marks and change the value following it to
-% the value given to the key. Additionally we'll need a sorting macro for each
-% key count in use so we set it up with |\ekvc@setup@splitmacro|.
-% \begin{macrocode}
-\protected\def\ekvc@SetupSplitKeys@d
- {%
- \begingroup\expandafter\endgroup
- \expandafter\ekvc@SetupSplitKeys@e
- \csname ekvc@splitmark@\the\ekvc@keycount\endcsname
- }
-\protected\long\def\ekvc@SetupSplitKeys@e#1#2#3%
- {%
- \long\def\ekvc@tmp##1##2#1##3{##2#1{##1}}%
-% \end{macrocode}
-% The short variant needs a bit of special treatment. The key macro will be
-% short to throw the correct error, but since there might be long macros
-% somewhere the reordering of arguments needs to be long, so for short keys we
-% use a two step approach, first grabbing only the short argument, then
-% reordering.
-% \begin{macrocode}
- \unless\ifx\ekvc@long\long
- \expandafter\let\csname ekvc@\ekvc@set(#2)\endcsname\ekvc@tmp
- \edef\ekvc@tmp##1%
- {%
- \ekv@unexpanded\expandafter{\csname ekvc@\ekvc@set(#2)\endcsname}%
- {##1}%
- }%
- \fi
- \ekvlet\ekvc@set{#2}\ekvc@tmp
- \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{#3}}}%
- \ekvc@helpers@needed
- {\expandafter\ekvc@setup@splitmacro\expandafter{\the\ekvc@keycount}}%
- {}%
- }
-% \end{macrocode}
-% If no value was provided this could either be an error, or the unknown key
-% forwarding. We have to check this (comparing against |...| inside
-% |\ekvc@tripledots|) and if this is the unknown key list type, set it up
-% accordingly (advancing the key count and setting up the unknown handlers of
-% \expkv). Else we simply throw an error and ignore the incident.
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupSplitKeys@check@unknown#1%
- {%
- \begingroup
- \edef\ekvc@tmp{\detokenize{#1}}%
- \expandafter
- \endgroup
- \ifx\ekvc@tripledots\ekvc@tmp
- \advance\ekvc@keycount1
-% \end{macrocode}
-% The |\begingroup\expandafter\endgroup| ensures that the split mark isn't
-% actually defined (even if it just were with meaning |\relax|).
-% \begin{macrocode}
- \begingroup\expandafter\endgroup
- \expandafter\ekvc@SetupSplitKeys@unknown
- \csname ekvc@splitmark@\the\ekvc@keycount\endcsname
- \let\ekvc@any@long\long
- \else
- \ekvc@err@value@required{#1}%
- \fi
- }
-% \end{macrocode}
-%
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupSplitKeys@unknown#1%
- {%
- \long\expandafter\def\csname\ekv@name\ekvc@set{}u\endcsname##1##2##3#1##4%
- {##3#1{##4,##2= {##1} }}%
- \long\expandafter\def\csname\ekv@name\ekvc@set{}uN\endcsname##1##2#1##3%
- {##2#1{##3,##1}}%
- \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{}}}%
- \ekvc@helpers@needed
- {\expandafter\ekvc@setup@splitmacro\expandafter{\the\ekvc@keycount}}%
- {}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@split@p@long}
-% The |long| prefix lets the internals |\ekvc@long| and |\ekvc@any@long| to
-% |\long| so that the key macro will be long.
-% \begin{macrocode}
-\protected\def\ekvc@split@p@long
- {%
- \let\ekvc@long\long
- \let\ekvc@any@long\long
- \ekvc@SetupSplitKeys@d
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@split@p@short}
-% The |short| prefix does essentially nothing, it is only provided to allow
-% key names starting with |long| that aren't |\long|.
-% \begin{macrocode}
-\def\ekvc@split@p@short{\ekvc@SetupSplitKeys@d}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@defarggobbler}
-% This is needed to define a macro with 1-9 parameters programmatically.
-% \LaTeX's \cs[no-index]{newcommand} does something similar for example.
-% \begin{macrocode}
-\protected\def\ekvc@defarggobbler#1{\def\ekvc@tmp##1#1##2##{##1#1}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@setup@splitmacro,
-% \ekvc@split@1, \ekvc@split@2, \ekvc@split@3,
-% \ekvc@split@4, \ekvc@split@5, \ekvc@split@6,
-% \ekvc@split@7
-% }
-% Since the first few split macros are different from the others we manually
-% set those up now. All the others will be defined as needed (always
-% globally). The split macros just read up until the correct split mark, move
-% that argument into a list and reinsert the rest, calling the next split
-% macro afterwards.
-% \begin{macrocode}
-\begingroup
-\edef\ekvc@tmp
- {%
- \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@1\endcsname}%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}%
- ##1##2##3%
- {##3{##1}##2}%
- \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@2\endcsname}%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
- ##3##4%
- {##4{##1}{##2}##3}%
- \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@3\endcsname}%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
- ##4##5%
- {##5{##1}{##2}{##3}##4}%
- \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@4\endcsname}%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
- ##5##6%
- {##6{##1}{##2}{##3}{##4}##5}%
- \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@5\endcsname}%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
- ##6##7%
- {##7{##1}{##2}{##3}{##4}{##5}##6}%
- \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@6\endcsname}%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@6\endcsname}##6%
- ##7##8%
- {##8{##1}{##2}{##3}{##4}{##5}{##6}##7}%
- \long\gdef\ekv@unexpanded\expandafter{\csname ekvc@split@7\endcsname}%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@1\endcsname}##1%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@2\endcsname}##2%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@3\endcsname}##3%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@4\endcsname}##4%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@5\endcsname}##5%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@6\endcsname}##6%
- \ekv@unexpanded\expandafter{\csname ekvc@splitmark@7\endcsname}##7%
- ##8##9%
- {##9{##1}{##2}{##3}{##4}{##5}{##6}{##7}##8}%
- }
-\ekvc@tmp
-\endgroup
-\protected\def\ekvc@setup@splitmacro#1%
- {%
- \ekv@ifdefined{ekvc@split@#1}{}%
- {%
- \begingroup
- \edef\ekvc@tmp
- {%
- \long\gdef
- \ekv@unexpanded\expandafter{\csname ekvc@split@#1\endcsname}%
- ####1%
- \ekv@unexpanded\expandafter
- {\csname ekvc@splitmark@#1\endcsname}%
- ####2####3%
- {%
- \ekv@unexpanded\expandafter
- {\csname ekvc@split@\the\numexpr#1-1\relax\endcsname}%
- ####1{{####2}####3}%
- }%
- }%
- \ekvc@tmp
- \endgroup
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcHashAndUse}
-% |\ekvcHashAndUse| works just like |\ekvcSplitAndUse|.
-% \begin{macrocode}
-\protected\long\def\ekvcHashAndUse#1#2%
- {%
- \let\ekvc@helpers@needed\@firstoftwo
- \ekvc@ifdefined#1%
- {\ekvc@err@already@defined#1}%
- {\ekvcHashAndUse@#1{}{#2}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvcHashAndUse@}
-% This is more or less the same as |\ekvcSplitAndUse@|. Instead of an empty
-% group we place a marker after the initials, we don't use the sorting macros
-% of |split|, but instead pack all the values in one argument.
-% \begin{macrocode}
-\protected\long\def\ekvcHashAndUse@#1#2#3%
- {%
- \edef\ekvc@set{\string#1}%
- \ekvc@SetupHashKeys{#3}%
- \ekvc@helpers@needed
- {%
- \ekvc@any@long\edef#1##1%
- {%
- \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
- \ekv@unexpanded{\ekvc@hash@pack@argument}%
- \ekv@unexpanded\expandafter{\ekvc@initials\ekvc@stop#2}%
- }%
- }%
- {%
- \ekvc@any@long\edef#1##1%
- {%
- \expandafter\ekvc@ekvset@pre@expander\expandafter{\ekvc@set}%
- \ekv@unexpanded{#2}%
- \ekv@unexpanded\expandafter{\ekvc@initials\ekvc@stop}%
- }%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcHashAndForward}
-% |\ekvcHashAndForward| works just like |\ekvcSplitAndForward|.
-% \begin{macrocode}
-\protected\long\def\ekvcHashAndForward#1#2#3%
- {%
- \let\ekvc@helpers@needed\@firstoftwo
- \ekvc@ifdefined#1%
- {\ekvc@err@already@defined#1}%
- {\ekvcHashAndUse@#1{{#2}}{#3}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcHash}
-% |\ekvcHash| does the same as |\ekvcSplit|, but has the advantage of not
-% needing to count arguments, so the definition of the internal macro is a bit
-% more straight forward.
-% \begin{macrocode}
-\protected\long\def\ekvcHash#1#2#3%
- {%
- \let\ekvc@helpers@needed\@secondoftwo
- \ekvc@ifdefined#1%
- {\ekvc@err@already@defined#1}%
- {%
- \expandafter
- \ekvcHashAndUse@\expandafter#1\csname ekvc@\string#1\endcsname{#2}%
- \ekvc@any@long\expandafter\def\csname ekvc@\string#1\endcsname
- ##1\ekvc@stop
- {#3}%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@hash@pack@argument}
-% All this macro does is pack the values into one argument and forward that to
-% the next macro.
-% \begin{macrocode}
-\long\def\ekvc@hash@pack@argument#1\ekvc@stop#2{#2{#1}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@SetupHashKeys,\ekvc@SetupHashKeys@a,\ekvc@SetupHashKeys@b,
-% \ekvc@SetupHashKeys@c,\ekvc@SetupHashKeys@d,\ekvc@SetupHashKeys@e,
-% \ekvc@SetupHashKeys@check@unknown,\ekvc@SetupHashKeys@unknown
-% }
-% This should look awfully familiar as well, since it's just the same as for
-% the split keys with a few other names here and there.
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupHashKeys#1%
- {%
- \let\ekvc@any@long\ekv@empty
- \let\ekvc@initials\ekv@empty
- \ekvparse\ekvc@SetupHashKeys@check@unknown\ekvc@SetupHashKeys@a{#1}%
- }
-\protected\long\def\ekvc@SetupHashKeys@a#1%
- {\expandafter\ekvc@SetupHashKeys@b\detokenize{#1}\ekvc@stop}
-\protected\def\ekvc@SetupHashKeys@b#1\ekvc@stop
- {%
- \let\ekvc@long\ekv@empty
- \ekvc@ifspace{#1}%
- {\ekvc@SetupHashKeys@c#1\ekvc@stop}%
- {\ekvc@SetupHashKeys@d{#1}}%
- }
-\protected\def\ekvc@SetupHashKeys@c#1 #2\ekvc@stop
- {%
- \ekv@ifdefined{ekvc@hash@p@#1}%
- {\csname ekvc@hash@p@#1\endcsname{#2}}%
- {\ekvc@SetupHashKeys@d{#1 #2}}%
- }
-% \end{macrocode}
-% Again we build the marker, this time instead of a numbered one a named
-% hashmark, inside a group to not actually define the macro used as a marker.
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupHashKeys@d#1%
- {%
- \begingroup\expandafter\endgroup
- \expandafter\ekvc@SetupHashKeys@e\csname ekvc@hashmark@#1\endcsname{#1}%
- }
-% \end{macrocode}
-% Yes, even the defining macro looks awfully familiar. Instead of numbered we
-% have named marks. Still the key macros grab everything up to their
-% respective mark and reorder the arguments. The same quirk is applied for
-% short keys. And instead of the |\ekvc@setup@splitmacro| we use
-% |\ekvc@setup@hashmacro|.
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupHashKeys@e#1#2#3%
- {%
- \long\def\ekvc@tmp##1##2#1##3{##2#1{##1}}%
- \unless\ifx\ekvc@long\long
- \expandafter\let\csname ekvc@\ekvc@set(#2)\endcsname\ekvc@tmp
- \edef\ekvc@tmp##1%
- {%
- \ekv@unexpanded\expandafter{\csname ekvc@\ekvc@set(#2)\endcsname}%
- {##1}%
- }%
- \fi
- \ekvlet\ekvc@set{#2}\ekvc@tmp
- \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{#3}}}%
- \ekvc@setup@hashmacro{#2}%
- }
-% \end{macrocode}
-% \begin{macrocode}
-\protected\long\def\ekvc@SetupHashKeys@check@unknown#1%
- {%
- \begingroup
- \edef\ekvc@tmp{\detokenize{#1}}%
- \expandafter
- \endgroup
- \ifx\ekvc@tripledots\ekvc@tmp
- \ekvc@SetupHashKeys@unknown
- \let\ekvc@any@long\long
- \else
- \ekvc@err@value@required{#1}%
- \fi
- }
-% \end{macrocode}
-% \begin{macrocode}
-\def\ekvc@SetupHashKeys@unknown#1%
- {%
- \protected\def\ekvc@SetupHashKeys@unknown
- {%
- \expandafter
- \let\csname\ekv@name\ekvc@set{}u\endcsname\ekvc@hash@unknown@kv
- \expandafter
- \let\csname\ekv@name\ekvc@set{}uN\endcsname\ekvc@hash@unknown@k
- \edef\ekvc@initials{\ekv@unexpanded\expandafter{\ekvc@initials#1{}}}%
- \ekvc@setup@hashmacro{...}%
- }%
- \long\def\ekvc@hash@unknown@kv##1##2##3#1##4{##3#1{##4,##2= {##1} }}%
- \long\def\ekvc@hash@unknown@k##1##2#1##3{##2#1{##3,##1}}%
- }
-\expandafter\ekvc@SetupHashKeys@unknown
- \csname ekvc@hashmark@\ekvc@tripledots\endcsname
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@hash@p@long}
-% Nothing astonishing here either.
-% \begin{macrocode}
-\protected\def\ekvc@hash@p@long
- {%
- \let\ekvc@long\long
- \let\ekvc@any@long\long
- \ekvc@SetupHashKeys@d
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@hash@p@short}
-% The |short| prefix does essentially nothing, it is only provided to allow
-% key names starting with |long| that aren't |\long|.
-% \begin{macrocode}
-\def\ekvc@hash@p@short{\ekvc@SetupHashKeys@d}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@setup@hashmacro}
-% The safe hash macros will be executed inside of an |\unexpanded| expansion
-% context, so they have to insert braces for that once they are done.
-% Most of the tests which have to be executed will already be done, but we
-% have to play safe if the hash doesn't show up in the hash list. Therefore we
-% use some |\ekvc@mark|s and |\ekvc@stop| to throw errors if the hash isn't
-% found in the right place. The fast variants have an easier life and just
-% return the correct value.
-% \begin{macrocode}
-\protected\def\ekvc@setup@hashmacro#1%
- {%
- \ekv@ifdefined{ekvc@fasthash@#1}{}%
- {%
- \begingroup
- \edef\ekvc@tmp
- {%
- \long\gdef
- \ekv@unexpanded\expandafter{\csname ekvc@fasthash@#1\endcsname}%
- ####1%
- \ekv@unexpanded\expandafter
- {\csname ekvc@hashmark@#1\endcsname}%
- ####2####3\ekv@unexpanded{\ekvc@stop}%
- {####2}%
- \long\gdef
- \ekv@unexpanded\expandafter{\csname ekvc@safehash@#1\endcsname}%
- ####1%
- {%
- \ekv@unexpanded\expandafter
- {\csname ekvc@@safehash@#1\endcsname}%
- ####1\ekv@unexpanded{\ekvc@mark}{}%
- \ekv@unexpanded\expandafter
- {%
- \csname ekvc@hashmark@#1\endcsname{}%
- \ekvc@mark{\ekvc@err@missing@hash{#1}}\ekvc@stop
- }%
- }%
- \long\gdef
- \ekv@unexpanded\expandafter
- {\csname ekvc@@safehash@#1\endcsname}%
- ####1%
- \ekv@unexpanded\expandafter
- {\csname ekvc@hashmark@#1\endcsname}%
- ####2####3\ekv@unexpanded{\ekvc@mark}####4####5%
- \ekv@unexpanded{\ekvc@stop}%
- {%
- ####4{####2}%
- }%
- \long\gdef\ekv@unexpanded\expandafter
- {\csname ekvc@fastsplithash@#1\endcsname}%
- ####1%
- \ekv@unexpanded\expandafter
- {\csname ekvc@hashmark@#1\endcsname}%
- ####2####3\ekv@unexpanded{\ekvc@stop}####4%
- {%
- ####4{####2}%
- }%
- \long\gdef\ekv@unexpanded\expandafter
- {\csname ekvc@safesplithash@#1\endcsname}####1%
- {%
- \ekv@unexpanded\expandafter
- {\csname ekvc@@safesplithash@#1\endcsname}%
- ####1\ekv@unexpanded{\ekvc@mark\ekvc@safe@after@hash}%
- \ekv@unexpanded\expandafter
- {%
- \csname ekvc@hashmark@#1\endcsname{}%
- \ekvc@mark
- {\ekvc@err@missing@hash{#1}\ekvc@safe@after@hash}%
- \ekvc@stop
- }%
- }%
- \long\gdef\ekv@unexpanded\expandafter
- {\csname ekvc@@safesplithash@#1\endcsname}%
- ####1%
- \ekv@unexpanded\expandafter
- {\csname ekvc@hashmark@#1\endcsname}%
- ####2####3\ekv@unexpanded{\ekvc@mark}####4####5%
- \ekv@unexpanded{\ekvc@stop}%
- {%
- ####4{####2}%
- }%
- }%
- \ekvc@tmp
- \endgroup
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcValue}
-% \begin{macro}[internal]{\ekvcValue@}
-% All this does is a few consistency checks on the first argument (not empty,
-% hash macro exists) and then call that hash-grabbing macro that will also
-% test whether the hash is inside of |#2| or not.
-% \begin{macrocode}
-\long\def\ekvcValue#1%
- {%
- \ekv@unexpanded
- \expandafter\ekvcValue@\detokenize{#1}\ekvc@stop
- }
-\def\ekvcValue@#1\ekvc@stop
- {%
- \ekv@ifdefined{ekvc@safehash@#1}%
- {\csname ekvc@safehash@#1\endcsname}%
- {\ekvc@err@unknown@hash{#1}\@firstoftwo{{}}}%
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\ekvcValueFast}
-% To be as fast as possible, this doesn't test for anything, assuming the user
-% knows best.
-% \begin{macrocode}
-\long\def\ekvcValueFast#1#2%
- {\csname ekvc@fasthash@\detokenize{#1}\endcsname#2\ekvc@stop}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcValueSplit}
-% \begin{macro}[internal]{\ekvcValueSplit@,\ekvcValueSplit@recover}
-% This splits off a single value.
-% \begin{macrocode}
-\long\def\ekvcValueSplit#1%
- {\expandafter\ekvcValueSplit@\detokenize{#1}\ekvc@stop}
-\def\ekvcValueSplit@#1\ekvc@stop
- {%
- \ekv@ifdefined{ekvc@safesplithash@#1}%
- {\csname ekvc@safesplithash@#1\endcsname}%
- {\ekvc@err@unknown@hash{#1}\ekvcValueSplit@recover}%
- }
-\long\def\ekvcValueSplit@recover#1#2{#2{}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@safe@after@hash}
-% \begin{macrocode}
-\long\def\ekvc@safe@after@hash#1#2%
- {%
- #2{#1}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcValueSplitFast}
-% Again a fast approach which doesn't provide too many safety measurements.
-% This needs to build the hash function and expand it before passing the
-% results to the next control sequence. The first step only builds the control
-% sequence.
-% \begin{macrocode}
-\long\def\ekvcValueSplitFast#1#2%
- {\csname ekvc@fastsplithash@\detokenize{#1}\endcsname#2\ekvc@stop}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@safehash@,\ekvc@fasthash@,
-% \ekvc@safesplithash@,\ekvc@fastsplithash@
-% }
-% At least in the empty hash case we can provide a meaningful error message
-% without affecting performance by just defining the macro that would be build
-% in that case. There is of course a downside to this, the error will not be
-% thrown by |\ekvcValueFast| in three expansion steps. The safe hash variant
-% has to also stop the |\unexpanded| expansion.
-% \begin{macrocode}
-\long\def\ekvc@safehash@#1{\ekvc@err@empty@hash{}}
-\long\def\ekvc@fasthash@#1\ekvc@stop{\ekvc@err@empty@hash}
-\long\def\ekvc@safesplithash@#1#2{\ekvc@err@empty@hash#2{}}
-\long\def\ekvc@fastsplithash@#1\ekvc@stop#2{\ekvc@err@empty@hash#2{}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcSecondaryKeys}
-% \begin{macro}[internal]
-% {\ekvcSecondaryKeys@a,\ekvcSecondaryKeys@b,\ekvcSecondaryKeys@c}
-% The secondary keys are defined pretty similar to the way the originals are,
-% but here we also introduce some key types (those have a |@t@| in their name)
-% additionally to the prefixes.
-% \begin{macrocode}
-\protected\long\def\ekvcSecondaryKeys#1#2%
- {%
- \edef\ekvc@set{\string#1}%
- \ekvparse\ekvc@err@value@required\ekvcSecondaryKeys@a{#2}%
- }
-\protected\long\def\ekvcSecondaryKeys@a#1%
- {\expandafter\ekvcSecondaryKeys@b\detokenize{#1}\ekvc@stop}
-\protected\def\ekvcSecondaryKeys@b#1\ekvc@stop
- {%
- \let\ekvc@long\ekv@empty
- \ekvc@ifspace{#1}%
- {\ekvcSecondaryKeys@c#1\ekvc@stop}%
- {\ekvc@err@missing@type{#1}\@gobble}%
- }
-\protected\def\ekvcSecondaryKeys@c#1 #2\ekvc@stop
- {%
- \ekv@ifdefined{ekvc@p@#1}%
- {\csname ekvc@p@#1\endcsname}%
- {%
- \ekv@ifdefined{ekvc@t@#1}%
- {\csname ekvc@t@#1\endcsname}%
- {\ekvc@err@unknown@keytype{#1}\@firstoftwo\@gobble}%
- }%
- {#2}%
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\ekvcChange}
-% This can be used to change the defaults of an \expkvc\ defined macro. It
-% checks whether there is a set with the correct name and that the macro is
-% defined. If both is true the real work is done by |\ekvc@change|.
-% \begin{macrocode}
-\protected\long\def\ekvcChange#1%
- {%
- \ekvifdefinedset{\string#1}%
- {%
- \ekvc@ifdefined#1%
- {\ekvc@change#1}%
- {\ekvc@err@no@key@macro#1\@gobble}%
- }%
- {\ekvc@err@no@key@macro#1\@gobble}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@change ,\ekvc@change@a,\ekvc@change@b,
-% \ekvc@change@c,\ekvc@change@d,\ekvc@change@e
-% }
-% First we need to see whether the macro is currently |\long|. For this we get
-% the meaning and will parse it. |#1| is the macro name in which we want to
-% change the defaults.
-% \begin{macrocode}
-\protected\def\ekvc@change#1%
- {\expandafter\ekvc@change@a\meaning#1\ekv@stop#1}
-% \end{macrocode}
-% A temporary definition to get the stringified |macro:|. |##1| will be the
-% list of prefixes, we don't care for the exact contents of |##2| and |##3|.
-% \begin{macrocode}
-\def\ekvc@change@a#1%
- {%
- \protected\def\ekvc@change@a##1#1##2->##3\ekv@stop
- {%
- \ekvc@change@iflong{##1}%
- {\ekvc@change@b{}}%
- {\ekvc@change@b{\long}}%
- }%
- }
-\expandafter\ekvc@change@a\expandafter{\detokenize{macro:}}
-% \end{macrocode}
-% Next we expand the macro once to get its contents (including the current
-% default values with their markers) and place |\ekvc@stop| instead of an
-% argument as a marker for the last step. |#1| is either |\long| or empty,
-% |#2| is the macro.
-% \begin{macrocode}
-\protected\def\ekvc@change@b#1#2%
- {\expandafter\ekvc@change@c\expandafter{#2\ekvc@stop}{#1}#2}
-% \end{macrocode}
-% Here we place an unbalanced closing brace after the expansion of the macro.
-% Then we just parse the \kv-list with |\ekvset|, that will exchange the
-% values behind the markers. Once those are changed we give control to
-% |\ekvc@change@d|. The |\ekvset| step might horribly fail if the user defined
-% some keys that don't behave nice. |#1| is the expansion of the macro, |#2|
-% is either |\long| or empty, |#3| is the macro, and |#4| is the \kv-list
-% containing the new defaults.
-% \begin{macrocode}
-\ekv@exparg{\protected\long\def\ekvc@change@c#1#2#3#4}%
- {%
- \expandafter\iffalse\expandafter{\expandafter{\expandafter\fi
- \ekvset{\string#3}{#4}%
- \ekvc@change@d{#2}{#3}%
- #1%
- }}%
- }
-% \end{macrocode}
-% The final step needs to put an unbalanced opening brace after |\edef|. Also
-% we have to protect everything from further expanding with the exception of
-% the redefined macro's argument, which is why we placed the |\ekvc@stop|
-% earlier. Then we need to also protect the rest of the contents from further
-% expanding using |\unexpanded| with another unbalanced opening brace.
-% |#1| will be either empty or |\long| and |#2| is the macro.
-% \begin{macrocode}
-\protected\def\ekvc@change@d#1#2%
- {#1\edef#2##1{\expandafter\ekvc@change@e\iffalse}\fi}
-\long\def\ekvc@change@e#1\ekvc@stop
- {\ekv@unexpanded{#1}##1\ekv@unexpanded\expandafter{\iffalse}\fi}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@change@iflong,\ekvc@change@iflong@}
-% Checking whether a string contains the string representation of |\long| can
-% be done by gobbling everything up to the first |\long| and checking whether
-% the result is completely empty. We need a temporary macro to get the result
-% of |\string\long| inside the definitions.
-% \begin{macrocode}
-\def\ekvc@change@iflong#1%
- {%
- \protected\def\ekvc@change@iflong##1%
- {\expandafter\ekv@ifempty\expandafter{\ekvc@change@iflong@##1#1}}%
- \def\ekvc@change@iflong@##1#1{}
- }
-\expandafter\ekvc@change@iflong\expandafter{\string\long}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcPass}
-% This macro can be used to pass a value to a key of some macro (this way
-% more complicated key codes are possible that in the end pass processed
-% values on to some macro). The implemantation is pretty straight forward.
-% \begin{macrocode}
-\long\def\ekvcPass#1#2%
- {%
- \ekvifdefined{\string#1}{#2}%
- {\csname\ekv@name{\string#1}{#2}\endcsname}%
- {\ekvc@err@unknown@key@or@macro{#1}{#2}\@gobble}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \subsubsection{Secondary Key Types}
-%
-% \begin{macro}[internal]{\ekvc@p@long,\ekvc@after@ptype}
-% The prefixes are pretty straight forward again. Just set |\ekvc@long| and
-% forward to the |@t@| type.
-% \begin{macrocode}
-\protected\def\ekvc@p@long#1%
- {%
- \ekvc@ifspace{#1}%
- {%
- \let\ekvc@long\long
- \ekvc@after@ptype#1\ekvc@stop
- }%
- {\ekvc@err@missing@type{long #1}\@gobble}%
- }
-\protected\def\ekvc@after@ptype#1 #2\ekvc@stop
- {%
- \ekv@ifdefined{ekvc@t@#1}%
- {\csname ekvc@t@#1\endcsname{#2}}%
- {\ekvc@err@unknown@keytype{#1}\@gobble}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@t@meta, \ekvc@t@nmeta,
-% \ekvc@type@meta, \ekvc@type@meta@a, \ekvc@type@meta@b
-% }
-% The |meta| and |nmeta| key types use a nested |\ekvset| to set other keys in
-% the same macro's \set.
-% \begin{macrocode}
-\protected\def\ekvc@t@meta
- {%
- \edef\ekvc@tmp{\ekvc@set}%
- \expandafter\ekvc@type@meta\expandafter{\ekvc@tmp}\ekvc@long{##1}\ekvlet
- }
-\protected\def\ekvc@t@nmeta#1%
- {%
- \ekvc@assert@not@long{nmeta #1}%
- \edef\ekvc@tmp{\ekvc@set}%
- \expandafter\ekvc@type@meta\expandafter{\ekvc@tmp}{}{}\ekvletNoVal{#1}%
- }
-\protected\long\def\ekvc@type@meta#1#2#3#4#5#6%
- {%
- \expandafter\ekvc@type@meta@a\expandafter{\ekvset{#1}{#6}}{#2}{#3}%
- #4\ekvc@set{#5}\ekvc@tmp
- }
-\protected\def\ekvc@type@meta@a
- {%
- \expandafter\ekvc@type@meta@b\expandafter
- }
-\protected\long\def\ekvc@type@meta@b#1#2#3%
- {%
- #2\def\ekvc@tmp#3{#1}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@t@alias}
-% |alias| just checks whether there is a key and/or |NoVal| key defined with
-% the target name and |\let| the key to those.
-% \begin{macrocode}
-\protected\def\ekvc@t@alias#1#2%
- {%
- \ekvc@assert@not@long{alias #1}%
- \let\ekvc@tmp\@firstofone
- \ekvifdefined\ekvc@set{#2}%
- {%
- \ekvletkv\ekvc@set{#1}\ekvc@set{#2}%
- \let\ekvc@tmp\@gobble
- }%
- {}%
- \ekvifdefinedNoVal\ekvc@set{#2}%
- {%
- \ekvletkvNoVal\ekvc@set{#1}\ekvc@set{#2}%
- \let\ekvc@tmp\@gobble
- }%
- {}%
- \ekvc@tmp{\ekvc@err@unknown@key{#2}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@t@default}
-% The |default| key can be used to set a |NoVal| key for an existing key. It
-% will just pass the \val\ to the key macro of that other key.
-% \begin{macrocode}
-\protected\long\def\ekvc@t@default#1#2%
- {%
- \ekvifdefined\ekvc@set{#1}%
- {%
- \ekvc@assert@not@long{default #1}%
- \edef\ekvc@tmp
- {%
- \ekv@unexpanded\expandafter
- {\csname\ekv@name\ekvc@set{#1}\endcsname{#2}}%
- }%
- \ekvletNoVal\ekvc@set{#1}\ekvc@tmp
- }%
- {\ekvc@err@unknown@key{#1}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@t@enum}
-% \begin{macro}[internal]
-% {\ekvc@type@enum,\ekvc@h@enum,\ekvc@h@enum@,\ekvc@enum@name}
-% Enums don't need to apply special trickery to make the parts of the names
-% retrievable, so unlike in \expkvd\ we don't need catcode juggling.
-% The setup of an |enum| requires unpacking the value in two different
-% arguments so we need an auxiliary here.
-% \begin{macrocode}
-\def\ekvc@enum@name#1#2#3{ekvc#1(#2)#3}
-\protected\long\def\ekvc@t@enum#1#2%
- {\ekvc@assert@twoargs{#2}{enum #1}{\ekvc@type@enum{#1}#2}}
-\protected\long\def\ekvc@type@enum#1#2%
- {%
- \ekvifdefined\ekvc@set{#2}%
- {%
-% \end{macrocode}
-% At run time we need another helper and we need to expand the current
-% |\ekvc@set| now. The helper will build a control sequence from each given
-% value, those will be set up in the |\ekvcsvloop|.
-% \begin{macrocode}
- \ekvc@long\edef\ekvc@tmp##1%
- {%
- \ekv@unexpanded{\expandafter\ekvc@h@enum\detokenize}{##1}%
- \ekv@unexpanded{\ekvc@stop}%
- {\ekvc@set}{#1}%
- }%
- \ekvlet\ekvc@set{#1}\ekvc@tmp
- \def\ekvc@tmp{0}%
- \expandafter\ekvcsvloop\expandafter
- {%
- \expandafter\ekvc@type@enum@
- \csname\ekv@name\ekvc@set{#2}\endcsname
- {#1}%
- }%
- }%
- {%
- \ekvc@err@unknown@key{#2}%
- \@gobble
- }%
- }
-% \end{macrocode}
-% Here |#1| will be the key-macro of the underlying primary or secondary key,
-% |#2| is the |enum| key's name, and |#3| will be the choice. The rest is
-% pretty obvious.
-% \begin{macrocode}
-\ekv@exparg{\protected\long\def\ekvc@type@enum@#1#2#3}%
- {%
- \expandafter\expandafter\expandafter\edef\expandafter
- \csname\ekvc@enum@name\ekvc@set{#2}{\detokenize{#3}}\endcsname
- {\ekv@unexpanded{#1}{\ekvc@tmp}}%
- \edef\ekvc@tmp{\the\numexpr\ekvc@tmp+1\relax}%
- }
-% \end{macrocode}
-% The use-time helper will check if the macro for the passed in choice exists,
-% if it doesn't throws an error, else calls that macro which will set the
-% correct value.
-% \begin{macrocode}
-\ekv@if@lastnamedcs
- {%
- \ekv@exparg{\def\ekvc@h@enum#1\ekvc@stop#2#3}%
- {%
- \expandafter\ifcsname\ekvc@enum@name{#2}{#3}{#1}\endcsname
- \expandafter\ekvc@h@enum@\lastnamedcs
- \fi
- \ekvc@err@unknown@enum{#2}{#3}{#1}%
- }
- \def\ekvc@h@enum@#1\fi\ekvc@err@unknown@enum#2#3#4%
- {%
- \fi
- \ifx#1\relax
- \ekvc@err@unknown@enum{#2}{#3}{#4}%
- \expandafter\@gobble
- \fi
- #1%
- }
- }
- {%
- \def\ekvc@h@enum#1%
- {%
- \def\ekvc@h@enum##1\ekvc@stop##2##3%
- {%
- \expandafter\ekvc@h@enum@
- \csname\ifcsname#1\endcsname#1\else relax\fi\endcsname
- {##2}{##3}{##1}%
- }%
- }
- \expandafter\ekvc@h@enum\expandafter{\ekvc@enum@name{#2}{#3}{#1}}
- \def\ekvc@h@enum@#1#2#3#4%
- {%
- \ifx#1\relax
- \ekvc@err@unknown@enum{#2}{#3}{#4}%
- \expandafter\@gobble
- \fi
- #1%
- }
- }
-% \end{macrocode}
-% We don't need |\ekvc@enum@name| anymore, so let's undefine it.
-% \begin{macrocode}
-\let\ekvc@enum@name\ekvc@undefined
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@t@aggregate}
-% Aggregating isn't easy to define. We'll have to extract the correct mark for
-% the specified key, branch correctly for short and long keys, and use a small
-% hack to have the correct arguments on the user interface (|#1| as the
-% current contents, |#2| as the new value). This is split into a few steps
-% here.
-%
-% First, assert that the user input is well-behaved.
-% \begin{macrocode}
-\protected\def\ekvc@t@aggregate#1%
- {%
- \ekvc@assert@not@long{aggregate #1}%
- \ekvc@type@aggregate
- \ekvc@type@aggregate@long\ekvc@type@aggregate@short
- {process}%
- {#1}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvc@type@aggregate,\ekvc@type@aggregate@a,\ekvc@type@aggregate@b}
-% The next step stores the user defined processing in a temporary macro that's
-% used to do the parameter number swapping later. It also builds the names of
-% the key macro and the helper which would be used for processing a short key.
-% \begin{macrocode}
-\protected\long\def\ekvc@type@aggregate#1#2#3#4#5%
- {%
- \ekvc@assert@twoargs{#5}{#3 #4}{\ekvc@type@aggregate@a#1#2{#4}#5}%
- }
-\protected\long\def\ekvc@type@aggregate@a#1#2#3#4#5%
- {%
- \ekvifdefined\ekvc@set{#4}%
- {%
- \def\ekvc@type@aggregate@tmp##1##2{#5}%
- \begingroup\expandafter\endgroup
- \expandafter\ekvc@type@aggregate@b
- \csname\ekv@name\ekvc@set{#4}\expandafter\endcsname
- \csname ekvc@\ekvc@set(#4)\endcsname
- #1#2%
- {#3}%
- }%
- {\ekvc@err@unknown@key{#4}}%
- }
-\protected\long\def\ekvc@type@aggregate@b#1#2#3#4%
- {%
- \ekvc@type@aggregate@check@long#1#2%
- {#3#1}%
- {#4#2}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@type@aggregate@check@long,
-% \ekvc@type@aggregate@check@long@a,\ekvc@type@aggregate@check@long@b
-% }
-% To check whether the primary key is long we see whether its |\meaning|
-% contains the helper which would only be there for short keys. For this we
-% have to get the stringified name of the internal (using |\detokenize|),
-% and afterwards get the |\meaning| of the macro. A temporary helper does the
-% real test by gobbling and forwarding the result to |\ekv@ifempty|.
-% \begin{macrocode}
-\protected\long\def\ekvc@type@aggregate@check@long#1#2%
- {\expandafter\ekvc@type@aggregate@check@long@a\detokenize{#2}\ekv@stop#1}
-\protected\long\def\ekvc@type@aggregate@check@long@a#1\ekv@stop#2%
- {%
- \def\ekvc@type@aggregate@check@long@@##1#1{}%
- \expandafter\ekvc@type@aggregate@check@long@b\meaning#2\ekv@stop{#1}%
- }
-\protected\def\ekvc@type@aggregate@check@long@b#1\ekv@stop#2%
- {\expandafter\ekv@ifempty\expandafter{\ekvc@type@aggregate@check@long@@#1#2}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@type@aggregate@long,\ekvc@type@aggregate@long@}
-% The long variant just builds the split mark we extract, uses the hack to
-% swap argument order, and then does the definition via |\ekvlet| and a
-% temporary macro.
-% \begin{macrocode}
-\protected\long\def\ekvc@type@aggregate@long#1%
- {%
- \begingroup\expandafter\endgroup\expandafter
- \ekvc@type@aggregate@long@
- \csname\ekvc@extract@mark#1\expandafter\endcsname
- \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
- }
-\protected\long\def\ekvc@type@aggregate@long@#1#2#3%
- {%
- \long\def\ekvc@type@aggregate@tmp##1##2#1##3{##2#1{#2}}
- \ekvlet\ekvc@set{#3}\ekvc@type@aggregate@tmp
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvc@type@aggregate@short,\ekvc@type@aggregate@short@}
-% The short variant will have to build the marker and the name of the helper
-% function, and swap the user argument order. Hence here are a few more
-% |\expandafter|s involved. But afterwards we can do the definition of the key
-% and the helper macro directly.
-% \begin{macrocode}
-\protected\long\def\ekvc@type@aggregate@short#1#2%
- {%
- \begingroup\expandafter\endgroup\expandafter
- \ekvc@type@aggregate@short@
- \csname\ekvc@extract@mark#1\expandafter\endcsname
- \csname ekvc@\ekvc@set(#2)\expandafter\endcsname
- \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
- {#2}%
- }
-\protected\long\def\ekvc@type@aggregate@short@#1#2#3#4%
- {%
- \ekvdef\ekvc@set{#4}{#2{##1}}%
- \long\def#2##1##2#1##3{##2#1{#3}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@t@process}
-% The |process| type can reuse much of |aggregate|, just the last step of
-% definition differ.
-% \begin{macrocode}
-\protected\def\ekvc@t@process
- {%
- \ifx\ekvc@long\long
- \ekv@fi@firstoftwo
- \fi
- \@secondoftwo
- {%
- \ekvc@type@aggregate
- \ekvc@type@process@long\ekvc@type@process@long
- }%
- {%
- \ekvc@type@aggregate
- \ekvc@type@process@short\ekvc@type@process@short
- }%
- {process}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@type@process@long,\ekvc@type@process@long@}
-% This defines a temporary macro to grab the current value (found after the
-% marker |#1|), executes the user code and puts everything back to where it
-% belongs. Then |\ekvlet| is used to assign that meaning to the key macro.
-% \begin{macrocode}
-\protected\long\def\ekvc@type@process@long#1%
- {%
- \begingroup\expandafter\endgroup\expandafter
- \ekvc@type@process@long@
- \csname\ekvc@extract@mark#1\expandafter\endcsname
- \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
- }
-\protected\long\def\ekvc@type@process@long@#1#2#3%
- {%
- \long\def\ekvc@type@aggregate@tmp##1##2#1##3{#2##2#1{##3}}%
- \ekvlet\ekvc@set{#3}\ekvc@type@aggregate@tmp
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@type@process@short,\ekvc@type@process@short@}
-% We define the key macro directly to just grab the argument once and forward
-% it to the auxiliary. That one does essentially the same as the long variant.
-% \begin{macrocode}
-\protected\long\def\ekvc@type@process@short#1#2%
- {%
- \begingroup\expandafter\endgroup\expandafter
- \ekvc@type@process@short@
- \csname\ekvc@extract@mark#1\expandafter\endcsname
- \csname ekvc@\ekvc@set(#2)\expandafter\endcsname
- \expandafter{\ekvc@type@aggregate@tmp{##3}{##1}}%
- {#2}%
- }
-\protected\long\def\ekvc@type@process@short@#1#2#3#4%
- {%
- \ekvdef\ekvc@set{#4}{#2{##1}}%
- \long\def#2##1##2#1##3{#3##2#1{##3}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@t@flag-bool}
-% \begin{macrocode}
-\protected\expandafter\def\csname ekvc@t@flag-bool\endcsname#1#2%
- {%
- \ekvc@assert@not@long{flag-bool #1}%
- \unless\ifdefined#2\ekvcFlagNew#2\fi
- \ekvdef\ekvc@set{#1}%
- {%
- \ekv@ifdefined{ekvc@flag@set@##1}%
- {%
- \csname ekvc@flag@set@##1\expandafter\endcsname
- \ekvcFlagHeight#2\ekv@stop#2%
- }%
- {\ekvc@err@invalid@bool{##1}}%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvc@t@flag-true,\ekvc@t@flag-false,\ekvc@t@flag-raise,\ekvc@type@flag}
-% \begin{macrocode}
-\protected\def\ekvc@type@flag#1#2#3#4%
- {%
- \ekvc@assert@not@long{flag-#1 #3}%
- \unless\ifdefined#4\ekvcFlagNew#4\fi
- \ekv@exparg{\ekvdefNoVal\ekvc@set{#3}}{#2#4}%
- }
-\protected\expandafter\def\csname ekvc@t@flag-true\endcsname
- {\ekvc@type@flag{true}\ekvcFlagSetTrue}
-\protected\expandafter\def\csname ekvc@t@flag-false\endcsname
- {\ekvc@type@flag{false}\ekvcFlagSetFalse}
-\protected\expandafter\def\csname ekvc@t@flag-raise\endcsname
- {\ekvc@type@flag{raise}\ekvcFlagRaise}
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \subsubsection{Flags}
-%
-% The basic idea of flags is to store information by the fact that \TeX\
-% expandably assigns the meaning |\relax| to undefined control sequences which
-% were built with |\csname|. This mechanism is borrowed from \pkg{expl3}.
-%
-% \begin{macro}[internal]{\ekvc@flag@name,\ekvc@flag@namescheme}
-% Flags follow a simple naming scheme which we define here. |\ekvc@flag@name|
-% will store the name of an internal function that is used to build names of
-% the second naming scheme defined by |\ekvc@flag@namescheme|.
-% \begin{macrocode}
-\def\ekvc@flag@name{ekvcf\string}
-\def\ekvc@flag@namescheme#1#2{ekvch#2#1}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagHeight}
-% For semantic reasons we use |\number| with another name.
-% \begin{macrocode}
-\let\ekvcFlagHeight\number
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagNew}
-% This macro defines a new flag. It stores the function build with the
-% |\ekvc@flag@name| naming scheme after the internal function
-% |\ekvc@flag@height| that'll determine the current flag height. It'll also
-% define the macro named via |\ekvc@flag@name| to build names according to
-% |\ekvc@flag@namescheme|.
-% \begin{macrocode}
-\protected\def\ekvcFlagNew#1%
- {%
- \edef#1%
- {%
- \ekv@unexpanded{\ekvc@flag@height}%
- \ekv@unexpanded\expandafter{\csname\ekvc@flag@name#1\endcsname}%
- }%
- \ekv@expargtwice
- {\expandafter\def\csname\ekvc@flag@name#1\endcsname##1}%
- {\expandafter\ekvc@flag@namescheme\expandafter{\string#1}{##1}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@flag@height,\ekvc@flag@height@}
-% This macro gets the height of a flag by a simple loop. The first loop
-% iteration differs a bit from the following in that it doesn't have to get
-% the current iteration count. The space at the end of |\ekvc@flag@height|
-% ends the |\number| evaluation.
-% \begin{macrocode}
-\def\ekvc@flag@height#1%
- {%
- \ifcsname#10\endcsname
- \ekvc@flag@height@1\ekv@stop#1%
- \fi
- \@firstofone{0} % leave this space
- }
-\def\ekvc@flag@height@#1\ekv@stop#2\fi\@firstofone#3%
- {%
- \fi
- \ifcsname#2{#1}\endcsname
- \expandafter\ekvc@flag@height@\the\numexpr#1+1\relax\ekv@stop#2%
- \fi
- \@firstofone{#1}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagRaise}
-% Raising a flag simply means letting the |\ekvc@flag@namescheme| macro for
-% the current height to relax. The result of raising a flag is that its height
-% is bigger by $1$.
-% \begin{macrocode}
-\ekv@exparg{\def\ekvcFlagRaise#1}%
- {%
- \expandafter\expandafter\expandafter\@gobble\expandafter
- \csname\ekvc@flag@namescheme{\string#1}{\ekvcFlagHeight#1}\endcsname
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagSetTrue,\ekvcFlagSetFalse}
-% \begin{macro}[internal]{\ekvc@flag@set@true,\ekvc@flag@set@false}
-% A flag is considered true if its current height is odd, and as false if it
-% is even. Therefore |\ekvcFlagSetTrue| and |\ekvcFlagSetFalse| only need to
-% raise the flag if the opposing boolean value is the current one.
-% \begin{macrocode}
-\def\ekvcFlagSetTrue#1%
- {\expandafter\ekvc@flag@set@true\ekvcFlagHeight#1\ekv@stop#1}
-\def\ekvcFlagSetFalse#1%
- {\expandafter\ekvc@flag@set@false\ekvcFlagHeight#1\ekv@stop#1}
-% \end{macrocode}
-% We can expand |\ekvc@flag@namescheme| at definition time here, which is why
-% we're using a temporary definition to set up |\ekvc@flag@set@true| and
-% |\ekvc@flag@set@false|.
-% \begin{macrocode}
-\def\ekvc@flag@set@true#1%
- {%
- \def\ekvc@flag@set@true##1\ekv@stop##2%
- {%
- \ifodd##1
- \ekv@fi@gobble
- \fi
- \@firstofone{\expandafter\@gobble\csname#1\endcsname}%
- }%
- \def\ekvc@flag@set@false##1\ekv@stop##2%
- {%
- \ifodd##1
- \ekv@fi@firstofone
- \fi
- \@gobble{\expandafter\@gobble\csname#1\endcsname}%
- }%
- }
-\expandafter\ekvc@flag@set@true\expandafter
- {\ekvc@flag@namescheme{\string#2}{#1}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagIf}
-% As already explained, truthiness is defined as a flag's height being odd, so
-% we just branch accordingly here.
-% \begin{macrocode}
-\def\ekvcFlagIf#1%
- {%
- \ifodd#1%
- \ekv@fi@firstoftwo
- \fi
- \@secondoftwo
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagIfRaised}
-% This macro uses flags as a switch, if a flag's current height is bigger than
-% $0$ this test yields true.
-% \begin{macrocode}
-\ekv@exparg{\def\ekvcFlagIfRaised#1}%
- {%
- \expandafter\ifcsname\ekvc@flag@namescheme{\string#1}0\endcsname
- \ekv@fi@firstoftwo
- \fi
- \@secondoftwo
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagReset}
-% \begin{macro}[internal]{\ekvc@flag@reset,\ekvc@flag@reset@}
-% Resetting works by locally letting all the defined internal macros named
-% after |\ekvc@flag@namescheme| to undefined.
-% \begin{macrocode}
-\protected\def\ekvcFlagReset#1%
- {\expandafter\ekvc@flag@reset\csname\ekvc@flag@name#1\endcsname}
-\protected\def\ekvc@flag@reset#1%
- {%
- \ifcsname#10\endcsname
- \expandafter\let\csname#10\endcsname\ekvc@undefined
- \ekvc@flag@reset@1\ekv@stop#1%
- \fi
- }
-\protected\def\ekvc@flag@reset@#1\ekv@stop#2\fi
- {%
- \fi
- \ifcsname#2{#1}\endcsname
- \expandafter\let\csname#2{#1}\endcsname\ekvc@undefined
- \expandafter\ekvc@flag@reset@\the\numexpr#1+1\relax\ekv@stop#2%
- \fi
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagGetHeight}
-% \begin{macro}[internal]{\ekvc@flag@get@height@single}
-% These are just small helpers, first getting the height of the flag and then
-% passing it on to the user supplied code.
-% \begin{macrocode}
-\def\ekvcFlagGetHeight#1%
- {\expandafter\ekvc@flag@get@height@single\ekvcFlagHeight#1\ekv@stop}
-\long\def\ekvc@flag@get@height@single#1\ekv@stop#2{#2{#1}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\ekvcFlagGetHeights}
-% \begin{macro}[internal]
-% {\ekvc@flag@get@heights,\ekvc@flag@get@heights@,\ekvc@flag@get@heights@done}
-% This works by a simple loop that stops at |\ekv@stop|. As long as that
-% marker isn't hit, get the next flags height and put it into a list after
-% |\ekv@stop|. |\ekvc@flag@get@heights@| uses the same marker name for the
-% end of the height, which shouldn't clash in any case. Once we're done we
-% remove the remainder of the current iteration and leave the user supplied
-% code in the input stream with all the flags' heights as a single argument.
-% \begin{macrocode}
-\def\ekvcFlagGetHeights#1%
- {%
- \ekvc@flag@get@heights#1\ekv@stop{}%
- }
-\def\ekvc@flag@get@heights#1%
- {%
- \ekv@gobbleto@stop#1\ekvc@flag@get@heights@done\ekv@stop
- \expandafter\ekvc@flag@get@heights@\ekvcFlagHeight#1\ekv@stop
- }
-\def\ekvc@flag@get@heights@#1\ekv@stop#2\ekv@stop#3%
- {\ekvc@flag@get@heights#2\ekv@stop{#3{#1}}}
-\long\def\ekvc@flag@get@heights@done
- \ekv@stop
- \expandafter\ekvc@flag@get@heights@\ekvcFlagHeight\ekv@stop\ekv@stop#1#2%
- {#2{#1}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-%
-% \subsubsection{Helper Macros}
-%
-% \begin{macro}[internal]{\ekvc@ifspace,\ekvc@ifspace@}
-% A test which can be reduced to an if-empty by gobbling everything up to the
-% first space.
-% \begin{macrocode}
-\long\def\ekvc@ifspace#1%
- {%
- \ekvc@ifspace@#1 \ekv@ifempty@B
- \ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- }
-\long\def\ekvc@ifspace@#1 % keep this space
- {%
- \ekv@ifempty@\ekv@ifempty@A
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@ifnottwoargs,\ekvc@ifempty@gtwo}
-% Used to test whether a token list contains exactly two \TeX\ arguments.
-% \begin{macrocode}
-\long\def\ekvc@ifnottwoargs#1%
- {%
- \ekvc@ifempty@gtwo#1\ekv@ifempty@B
- \ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- }
-\long\def\ekvc@ifempty@gtwo#1#2{\ekv@ifempty@\ekv@ifempty@A}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@extract@mark,\ekvc@extract@mark@}
-% This is used to extract the mark of a split or hash key from its definition.
-% This is kind of fragile, it assumes |#1| is always a macro used for hashing
-% or splitting. Also it assumes that the escape character is a backslash.
-% \begin{macrocode}
-\def\ekvc@extract@mark#1{\expandafter\ekvc@extract@mark@\meaning#1\ekv@stop}
-\begingroup
-\lccode`;=`#
-\lccode`/=`\\
-\lowercase{\endgroup
-\def\ekvc@extract@mark@#1:#2/#3 ;#4\ekv@stop{#3}%
-}
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \subsubsection{Assertions}
-% \begin{macro}[internal]{\ekvc@assert@not@long}
-% Some keys don't want to be |long| and we have to educate the user, so let's
-% throw an error if someone wanted these to be long.
-% \begin{macrocode}
-\long\def\ekvc@assert@not@long#1{\ifx\ekvc@long\long\ekvc@err@no@long{#1}\fi}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@assert@twoargs}
-% Some keys need exactly two arguments as their definition, so we have to
-% somehow assert this.
-% \begin{macrocode}
-\protected\long\def\ekvc@assert@twoargs#1#2%
- {\ekvc@ifnottwoargs{#1}{\ekvc@err@not@two{#2}}}
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \subsubsection{Messages}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@err@toomany,\ekvc@err@value@required,\ekvc@err@missing@type,
-% \ekvc@err@already@defined,\ekvc@err@no@key@macro,
-% \ekvc@err@not@two
-% }
-% Boring unexpandable error messages.
-% \begin{macrocode}
-\protected\def\ekvc@err@toomany#1%
- {%
- \errmessage{expkv-cs Error: Too many keys for macro `\string#1'}%
- }
-\protected\long\def\ekvc@err@value@required#1%
- {%
- \errmessage{expkv-cs Error: Missing value for key `\ekv@unexpanded{#1}'}%
- }
-\protected\long\def\ekvc@err@missing@type#1%
- {%
- \errmessage
- {expkv-cs Error: Missing type for secondary key `\ekv@unexpanded{#1}'}%
- }
-\protected\long\def\ekvc@err@no@long#1%
- {%
- \errmessage
- {expkv-cs Error: prefix `long' not accepted for `\ekv@unexpanded{#1}'}%
- }
-\protected\long\def\ekvc@err@already@defined#1%
- {%
- \errmessage{expkv-cs Error: Macro `\string#1' already defined}%
- }
-\protected\long\def\ekvc@err@unknown@keytype#1%
- {%
- \errmessage{expkv-cs Error: Unknown key type `\ekv@unexpanded{#1}'}%
- }
-\protected\long\def\ekvc@err@unknown@key#1%
- {%
- \errmessage
- {expkv-cs Error: Unknown key `\ekv@unexpanded{#1}' for macro `\ekvc@set'}%
- }
-\protected\long\def\ekvc@err@no@key@macro#1%
- {\errmessage{expkv-cs Error: \string#1 is no key=val macro}}
-\protected\long\def\ekvc@err@not@two#1%
- {%
- \errmessage
- {%
- expkv-cs Error: Definition of `\ekv@unexpanded{#1}' doesn't contain
- exactly two arguments%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvc@err}
-% We need a way to throw error messages expandably in some contexts.
-% \begin{macrocode}
-\ekv@exparg{\long\def\ekvc@err#1}{\ekverr{expkv-cs}{#1}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvc@err@unknown@hash,\ekvc@err@empty@hash,\ekvc@err@missing@hash,
-% \ekvc@err@invalid@bool,\ekvc@err@unknown@enum
-% }
-% And here are the expandable error messages.
-% \begin{macrocode}
-\long\def\ekvc@err@unknown@hash#1{\ekvc@err{unknown hash `#1'}}
-\long\def\ekvc@err@missing@hash#1{\ekvc@err{hash `#1' not found}}
-\long\def\ekvc@err@empty@hash{\ekvc@err{empty hash}}
-\def\ekvc@err@invalid@bool#1{\ekvc@err{invalid boolean value `#1'}}
-\long\def\ekvc@err@unknown@key@or@macro#1#2%
- {\ekvc@err{unknown key `#2' for macro #1}}
-\def\ekvc@err@unknown@enum#1#2#3%
- {\ekvc@err{unknown value `#3' for enum `#2' in macro #1}}
-% \end{macrocode}
-% \end{macro}
-%
-%
-% Now everything that's left is to reset the category code of |@|.
-% \begin{macrocode}
-\catcode`\@=\ekvc@tmp
-% \end{macrocode}
-%
-% \gobbledocstriptag
-%</tex>
-%^^A=<<
-%
-%^^A=<<
-%
-% \end{implementation}^^A=<<
-%
-% \clearpage
-% \PrintIndex
-%
-\endinput
-%
-^^A vim: ft=tex fdm=marker fmr=>>=,=<<
diff --git a/macros/generic/expkv-cs/expkv-cs.pdf b/macros/generic/expkv-cs/expkv-cs.pdf
deleted file mode 100644
index 0c37223ebf..0000000000
--- a/macros/generic/expkv-cs/expkv-cs.pdf
+++ /dev/null
Binary files differ
diff --git a/macros/generic/expkv-def/README.md b/macros/generic/expkv-def/README.md
deleted file mode 100644
index 79a69057e4..0000000000
--- a/macros/generic/expkv-def/README.md
+++ /dev/null
@@ -1,32 +0,0 @@
--------------------------------------------------------------------------------
-# expkv-def -- a key-defining frontend for expkv
-
-Version 2022-01-29 v0.9
-
-Released under the LaTeX Project Public License v1.3c or later
-See http://www.latex-project.org/lppl.txt
-
-Hosted at https://github.com/Skillmon/tex_expkv-def
-
--------------------------------------------------------------------------------
-
-Copyright (C) 2020-2021 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 provides a key=val frontend to define keys for
-[`expkv`](https://github.com/Skillmon/tex_expkv). It is generic code and only
-requires `expkv` for its parsing. There is a LaTeX package `expkv-def.sty`
-included to play nice on LaTeX's package loading system, but that package is not
-needed and does not provide more functionality than the generic code in
-`expkv-def.tex`.
diff --git a/macros/generic/expkv-def/expkv-def.dtx b/macros/generic/expkv-def/expkv-def.dtx
deleted file mode 100644
index 059c7dda01..0000000000
--- a/macros/generic/expkv-def/expkv-def.dtx
+++ /dev/null
@@ -1,2493 +0,0 @@
-% \iffalse meta-comment
-%
-% File: expkv-def.dtx Copyright (C) 2020-2022 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-def -- a key-defining frontend for 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-2022 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-def.dtx
-and the derived files expkv-def.pdf
- expkv-def.sty
- expkv-def.tex
- t-expkv-def.tex
-
-\endpreamble
-% stop docstrip adding \endinput
-\postamble
-\endpostamble
-\generate{\file{expkv-def.sty}{\from{expkv-def.dtx}{pkg}}}
-\generate{\file{expkv-def.tex}{\from{expkv-def.dtx}{tex}}}
-\generate{\file{t-expkv-def.tex}{\from{expkv-def.dtx}{ctx}}}
-\ifx\fmtname\nameofplainTeX
- \expandafter\endbatchfile
-\else
- \expandafter\endgroup
-\fi
-%
-\IfFileExists{expkv-def.tex}{\input{expkv-def.tex}}{}
-\ProvidesFile{expkv-def.dtx}
- [\csname ekvdDate\endcsname\ a key-defining frontend for expkv]
-\PassOptionsToPackage{full}{textcomp}
-\documentclass{l3doc}
-\RequirePackage[oldstylenums,nott]{kpfonts}
-\input{glyphtounicode}
-\pdfgentounicode=1
-\RequirePackage{tcolorbox}
-\newtcolorbox{exresult}[2][]
- {colback=expkvgrey!10!white,colframe=expkvgrey,fontupper=\small,width={#2},#1}
-\newtcbox\exres[1][]
- {
- colback=expkvgrey!10!white
- ,colframe=expkvgrey
- ,size=small
- ,nobeforeafter
- ,tcbox raise base
- ,fontupper=\small
- ,#1
- }
-\RequirePackage{listings}
-\RequirePackage{booktabs}
-\RequirePackage{array}
-\RequirePackage{collcell}
-\RequirePackage{siunitx}
-\RequirePackage{xcolor}
-\RequirePackage{caption}
-\RequirePackage{microtype}
-\RequirePackage{accsupp}
-\lstdefinelanguage{expkvd}[primitive]{TeX}
- {
- ,moretexcs=[4]^^A e-TeX
- {
- expanded,
- numexpr,
- protected,
- }
- ,moretexcs=[5]^^A plain/LaTeX
- {
- approx,
- begin,
- empty,
- item,
- LaTeX,
- makeatletter,makeatother,
- newcommand,newdimen,
- RequirePackage,
- rule,
- TeX,
- textit,texttt,
- usepackage,
- }
- ,moretexcs=[6]^^A used packages
- {
- ^^A xfp
- fpeval,
- ^^A keyval
- setkeys,
- ^^A yax
- defactiveparameter,storevalue,setparameterlist
- }
- ,moretexcs=[2]^^A expkv-def macros
- {
- ekvdefinekeys
- }
- ,moretexcs=[3]^^A expkv-pkg macros
- {
- ^^A expkv
- ekvdef,ekvdefNoVal,^^A
- ekvlet,ekvletNoVal,ekvletkv,ekvletkvNoVal,^^A
- ekvdefunknown,ekvdefunknownNoVal,^^A
- ekvredirectunknown,ekvredirectunknownNoVal,^^A
- ekvset,ekvsetSneaked,^^A
- ekvsetdef,ekvsetSneakeddef,ekvsetdefSneaked,^^A
- ekvparse,^^A
- ekvVersion,ekvDate,^^A
- ekvifdefined,ekvifdefinedNoVal,ekvifdefinedset,^^A
- ekvbreak,ekvbreakPreSneak,ekvbreakPostSneak,^^A
- ekvsneak,ekvsneakPre,^^A
- ekvchangeset,^^A
- ekvoptarg,ekvoptargTF,^^A
- ekverr,
- ^^A expkv-cs
- ekvcSecondaryKeys,ekvcSplitAndForward,
- }
- }
-\colorlet{codeparam}{cyan!65!black}
-\def\mylstwd{.55em}
-\lstset
- {
- ,language=expkvd
- ,flexiblecolumns=false
- ,basewidth=\mylstwd
- ,gobble=2
- ,basicstyle=\fontfamily{jkp}\itshape
- ,texcsstyle=*[1]{\bfseries\color{expkvgrey}} ^^A primitives
- ,texcsstyle=*[2]{\bfseries\color{expkvred}} ^^A expkv
- ,texcsstyle=*[3]{\color{expkvred}} ^^A expkv-pkg
- ,texcsstyle=*[4]{\bfseries\color{expkvgrey}} ^^A e-TeX
- ,texcsstyle=*[5]{\bfseries\color{expkvgrey}} ^^A plain/LaTeX macros
- ,texcsstyle=*[6]{} ^^A macros of other packages
- ,commentstyle=\color[gray]{0.4}
- ,literate=
- {\{} {{\CodeUpBf\{}}{1}
- {\}} {{\CodeUpBf\}}}{1}
- {$} {{\CodeUpBf\$}}{1}
- {[} {{\CodeUp[}}{1}
- {]} {{\CodeUp]}}{1}
- {(} {{\CodeUp(}}{1}
- {)} {{\CodeUp)}}{1}
- {*} {{$*$}}{1}
- {1} {{\CodeUp{1}}}{1}
- {2} {{\CodeUp{2}}}{1}
- {3} {{\CodeUp{3}}}{1}
- {4} {{\CodeUp{4}}}{1}
- {5} {{\CodeUp{5}}}{1}
- {6} {{\CodeUp{6}}}{1}
- {7} {{\CodeUp{7}}}{1}
- {8} {{\CodeUp{8}}}{1}
- {9} {{\CodeUp{9}}}{1}
- {0} {{\CodeUp{0}}}{1}
- {##} {{\CodeColored{codeparam}{1}{\#}}}{1}
- {##1}{{\CodeColored{codeparam}{2}{\#1}}}{2}
- {##2}{{\CodeColored{codeparam}{2}{\#2}}}{2}
- {##3}{{\CodeColored{codeparam}{2}{\#3}}}{2}
- {##4}{{\CodeColored{codeparam}{2}{\#4}}}{2}
- {##5}{{\CodeColored{codeparam}{2}{\#5}}}{2}
- {##6}{{\CodeColored{codeparam}{2}{\#6}}}{2}
- {##7}{{\CodeColored{codeparam}{2}{\#7}}}{2}
- {##8}{{\CodeColored{codeparam}{2}{\#8}}}{2}
- {##9}{{\CodeColored{codeparam}{2}{\#9}}}{2}
- {<key>}{{$\langle$}key{$\rangle$}}{5}
- {<set>}{{$\langle$}set{$\rangle$}}{5}
- {<set1>}{{$\langle$}set1{$\rangle$}}{6}
- {<set2>}{{$\langle$}set2{$\rangle$}}{6}
- ^^A,literate=*{<key>}{\key}{4}{<set>}{\set}{4}
- }
-\newcommand*\CodeColored[3]{\textcolor{#1}{\makebox[\dimexpr\mylstwd*#2]{#3}}}
-\newcommand*\CodeUpBf[1]{\makebox[\mylstwd]{\textup{\textbf{#1}}}}
-\newcommand*\CodeUp[1]{\makebox[\mylstwd]{\textup{#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*\expkvd
- {^^A
- \texorpdfstring
- {^^A
- \mbox
- {^^A
- \BeginAccSupp{ActualText=expkv-def}^^A
- \href{https://github.com/Skillmon/tex_expkv-def}
- {^^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{def}^^A
- }^^A
- }^^A
- \EndAccSupp{}^^A
- }^^A
- }
- {expkv-def}^^A
- }
-\newcommand\kv{\meta{key}=\meta{value}}
-\newcommand\key{\meta{key}}
-\newcommand\val{\meta{value}}
-\newcommand\set{\meta{set}}
-\newcommand\enfprefix{\textcolor{black}}
-\newcommand\allprefix{\textcolor{gray}}
-\newcommand\notprefix{\textcolor{red!80!black}}
-\newcommand\printprefix[2]
- {^^A
- \ifcase\numexpr#1\relax\or
- \enfprefix{#2}\or
- \allprefix{#2}\or
- \notprefix{#2}\fi
- }
-\newcommand\prefixes[4]
- {^^A
- \hfill
- \printprefix{#1}{new}
- \printprefix{#2}{also}
- \printprefix{#3}{protected}
- \printprefix{#4}{long}^^A
- }
-\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,\meaning,\detokenize}
-\DoNotIndex{\romannumeral,\^}
-\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\expkvd
- \\[\medskipamount]
- \Large a key-defining frontend for \expkv
- }{expkv-def - a key-defining frontend for expkv}^^A
- }
- \date{\ekvdDate\space v\ekvdVersion}
- \author{Jonathan P. Spratte\thanks{\protect\randomize{jspratte@yahoo.de}}}
- \DocInput{expkv-def.dtx}
-\end{document}
-%</driver>^^A=<<
-% \fi
-%
-% \maketitle
-% \renewcommand*\thefootnote{\arabic{footnote}}
-%
-% \begin{abstract}
-% \noindent\parfillskip=0pt
-% \expkvd\ provides a small \kv\ interface to define keys for \expkv. Key-types
-% are declared using prefixes, similar to static typed languages. The stylised
-% name is \expkvd\ but the files use \file{expkv-def}, 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}
-%
-% Since the trend for the last couple of years goes to defining keys for a \kv\
-% interface using a \kv\ interface, I thought that maybe providing such an
-% interface for \expkv\ will make it more attractive for actual use, besides its
-% unique selling points of being fully expandable, and fast and reliable. But at
-% the same time I don't want to widen \expkv's initial scope. So here it is
-% \expkvd, go define \kv\ interfaces with \kv\ interfaces.
-%
-% Unlike many of the other established \kv\ interfaces to define keys, \expkvd\
-% works using prefixes instead of suffixes (\emph{e.g.}, |.tl_set:N| of
-% \pkg{l3keys}) or directory like handlers (\emph{e.g.}, |/.store in| of
-% \pkg{pgfkeys}). This was decided as a personal preference, more over in \TeX\
-% parsing for the first space is way easier than parsing for the last one.
-% \expkvd's prefixes are sorted into two categories: |p|-type, which are
-% equivalent to \TeX's prefixes like |\long|, and |t|-type defining the type of
-% the key. For a description of the available |p|-prefixes take a look at
-% \autoref{sec:prefix:p}, the |t|-prefixes are described in
-% \autoref{sec:prefix:t}.
-%
-% \expkvd\ is usable as generic code, as a \LaTeX\ package, and as a \ConTeXt\
-% module. It'll automatically load \expkv\ in the same mode as well. To use it,
-% just use one of
-% \begin{lstlisting}
-% \input expkv-def % plainTeX
-% \usepackage{expkv-def} % LaTeX
-% \usemodule[expkv-def] % ConTeXt
-% \end{lstlisting}
-%
-% \subsection{Macros}
-% Apart from version and date containers there is only a single user-facing
-% macro, and that should be used to define keys.
-%
-% \begin{function}{\ekvdefinekeys}
-% \begin{syntax}
-% \cs{ekvdefinekeys}\marg{set}\{\kv, \ldots\}
-% \end{syntax}
-% In \set, define \key\ to have definition \val. The general syntax for \key\
-% should be
-% \begin{quote}\ttfamily\small
-% \meta{prefix} \meta{name}
-% \end{quote}
-% Where \meta{prefix} is a space separated list of optional |p|-type prefixes
-% followed by one |t|-type prefix. The syntax of \val\ is dependent on the
-% used |t|-prefix.
-% \end{function}
-%
-% \begin{function}{\ekvdDate,\ekvdVersion}
-% These two macros store the version and date of the package.
-% \end{function}
-%
-% \subsection{Prefixes}
-% As already said there are |p|-prefixes and |t|-prefixes. Not every |p|-prefix
-% is allowed for all |t|-prefixes.
-%
-% \subsubsection{\texttt{p}-Prefixes}\label{sec:prefix:p}
-% The two |p|-type prefixes |long| and |protected| are pretty simple by nature,
-% so their description is pretty simple. They affect the \key\ at use-time, so
-% omitting |long| doesn't mean that a \meta{definition} can't contain a |\par|
-% token, only that the \key\ will not accept a |\par| in \val. On the other
-% hand |new| and |also| might be simple on first sight as well, but their rules
-% are a bit more complicated.
-%
-% \begin{function}{also}
-% The following key type will be \emph{added} to an existing \key's
-% definition. You can't add a type taking an argument at use time to an
-% existing key which doesn't take an argument and vice versa. Also you'll get
-% an error if you try to add an action which isn't allowed to be either |long|
-% or |protected| to a key which already is |long| or |protected| (the opposite
-% order would be suboptimal as well, but can't be really captured with the
-% current code).
-%
-% A key already defined as |long| or |protected| will stay |long| or
-% |protected|, but you can as well add |long| or |protected| with the |also|
-% definition.
-%
-% As a small example, suppose you want to create a boolean key, but
-% additionally to setting a boolean value you want to execute some more code
-% as well, you can use the following
-% \begin{lstlisting}
-% \ekvdefinekeys{also-example}
-% {
-% bool key = \ifmybool
-% ,also code key = \domystuff{#1}
-% }
-% \end{lstlisting}
-%
-% If you use |also| on a |choice|, |bool|, |invbool|, or |boolpair| key it is
-% tried to determine if the key already is of one of those types. If this test
-% is true the declared choices will be added to the possible choices but the
-% key's definition will not be changed other than that. If that wouldn't have
-% been done, the callbacks of the different choices could get called multiple
-% times.
-% \end{function}
-%
-% \begin{function}{protected,protect}
-% The following key will be defined |\protected|. Note that key-types which
-% can't be defined expandable will always use |\protected|.
-% \end{function}
-%
-% \begin{function}{long}
-% The following key will be defined |\long|.
-% \end{function}
-%
-% \begin{function}{new}
-% The following key must be new (so previously undefined). An error is thrown
-% if it is already defined and the new definition is ignored. |new| only
-% asserts that there are no conflicts between |NoVal| keys and other |NoVal|
-% keys or value taking keys and other value taking keys. For example you can
-% use the following without an error:
-% \begin{lstlisting}
-% \ekvdefinekeys{new-example}
-% {
-% code key = \domystuffwitharg{#1}
-% ,new noval key = \domystuffwithoutarg
-% }
-% \end{lstlisting}
-% \end{function}
-%
-% \subsubsection{\texttt{t}-Prefixes}\label{sec:prefix:t}
-% Since the |p|-type prefixes apply to some of the |t|-prefixes automatically
-% but sometimes one might be disallowed we need some way to highlight this
-% behaviour. In the following an enforced prefix will be printed black
-% (\texttt{\enfprefix{protected}}), allowed prefixes will be grey
-% (\texttt{\allprefix{protected}}), and disallowed prefixes will be red
-% (\texttt{\notprefix{protected}}). This will be put flush-right in the syntax
-% showing line.
-%
-% \begin{function}{code,ecode}
-% \begin{syntax}
-% code \key\ = \marg{definition} \prefixes2222
-% \end{syntax}
-% Define \key\ to expand to \meta{definition}. The \key\ will require a \val\
-% for which you can use |#1| inside \meta{definition}. The |ecode| variant
-% will fully expand \meta{definition} inside an |\edef|.
-% \end{function}
-%
-% \begin{function}{noval,enoval}
-% \begin{syntax}
-% noval \key\ = \marg{definition} \prefixes2223
-% \end{syntax}
-% The |noval| type defines \key\ to expand to \meta{definition}. The \key\
-% will not take a \val. |enoval| fully expands \meta{definition} inside an
-% |\edef|.
-% \end{function}
-%
-% \begin{function}{default,qdefault,odefault,fdefault,edefault}
-% \begin{syntax}
-% default \key\ = \marg{definition} \prefixes3223
-% \end{syntax}
-% This serves to place a default \val\ for a \key\ that takes an argument, the
-% \key\ can be of any argument-grabbing kind, and when used without a \val\
-% it will be passed \meta{definition} instead. The |qdefault| variant will
-% expand the \key's code once, so will be slightly quicker, but not change if
-% you redefine \key. |odefault| is just another name for |qdefault|. The
-% |fdefault| version will expand the key code until a non-expandable token or
-% a space is found, a space would be gobbled.\footnotemark{} The |edefault| on
-% the other hand fully expands the \key-code with \meta{definition} as its
-% argument inside of an |\edef|.
-% \end{function}
-% \footnotetext
-% {^^A
-% For those familiar with \TeX-coding: This uses a
-% \cs[no-index]{romannumeral}-expansion.
-% }
-%
-% \begin{function}{initial,oinitial,finitial,einitial}
-% \begin{syntax}
-% initial \key\ = \{\val\} \prefixes3333
-% initial \key
-% \end{syntax}
-% With |initial| you can set an initial \val\ for an already defined argument
-% taking \key. It'll just call the key-macro of \key\ and pass it \val. The
-% |einitial| variant will expand \val\ using an |\edef| expansion prior to
-% passing it to the key-macro and the |oinitial| variant will expand the first
-% token in \val\ once. |finitial| will expand \val\ until a non-expandable
-% token or a space is found, a space would be
-% gobbled.\footnotemark
-%
-% If you don't provide a value (and no equals sign) a |noval| \key\ of the
-% same name is called once (or, if you specified a |default| for a value
-% taking key that would be used).
-% \end{function}
-% \footnotetext{Again using \cs[no-index]{romannumeral}.}
-%
-% \begin{function}{bool,gbool,boolTF,gboolTF}
-% \begin{syntax}
-% bool \key\ = \meta{cs} \prefixes2223
-% \end{syntax}
-% The \meta{cs} should be a single control sequence, such as |\iffoo|.
-% This will define \key\ to be a boolean key, which only takes the values
-% |true| or |false| and will throw an error for other values. If the key is
-% used without a \val\ it'll have the same effect as if you use
-% \texttt{\key=true}. |bool| and |gbool| will behave like \TeX-ifs so either
-% be |\iftrue| or |\iffalse|. The |boolTF| and |gboolTF| variants will both
-% take two arguments and if true the first will be used else the second, so
-% they are always either |\@firstoftwo| or |\@secondoftwo|. The variants with
-% a leading |g| will set the control sequence globally, the others locally. If
-% \meta{cs} is not yet defined it'll be initialised as the |false| version.
-% Note that the initialisation is \emph{not} done with |\newif|, so you will
-% not be able to do |\footrue| outside of the \kv\ interface, but you could
-% use |\newif| yourself. Even if the \key\ will not be |\protected| the
-% commands which execute the |true| or |false| choice will be, so the usage
-% should be safe in an expansion context (\emph{e.g.}, you can use
-% \texttt{edefault \key\ = false} without an issue to change the default
-% behaviour to execute the |false| choice). Internally a |bool| \key\ is the
-% same as a |choice| key which is set up to handle |true| and |false| as
-% choices.
-% \end{function}
-%
-% \begin{function}{invbool,ginvbool,invboolTF,ginvboolTF}
-% \begin{syntax}
-% bool \key\ = \meta{cs} \prefixes2223
-% \end{syntax}
-% These are inverse boolean keys, they behave like |bool| and friends but set
-% the opposite meaning to the macro \meta{cs} in each case. So if
-% \texttt{key=true} is used |invbool| will set \meta{cs} to |\iffalse| and
-% vice versa.
-% \end{function}
-%
-% \begin{function}{boolpair,gboolpair,boolpairTF,gboolpairTF}
-% \begin{syntax}
-% boolpair \key\ = \meta{cs_1}\meta{cs_2} \prefixes2223
-% \end{syntax}
-% The |boolpair| key type behaves like both |bool| and |invbool|, the
-% \meta{cs_1} will be set to the meaning according to the rules of |bool|, and
-% \meta{cs_2} will be set to the opposite.
-% \end{function}
-%
-% \begin{function}{store,estore,gstore,xstore}
-% \begin{syntax}
-% store \key\ = \meta{cs} \prefixes2212
-% \end{syntax}
-% The \meta{cs} should be a single control sequence, such as |\foo|.
-% This will define \key\ to store \val\ inside of the control sequence. If
-% \meta{cs} isn't yet defined it will be initialised as empty. The variants
-% behave similarly to their |\def|, |\edef|, |\gdef|, and |\xdef|
-% counterparts, but |store| and |gstore| will allow you to store macro
-% parameters inside of them by using |\unexpanded|.
-% \end{function}
-%
-% \begin{function}{data,edata,gdata,xdata}
-% \begin{syntax}
-% data \key\ = \meta{cs} \prefixes2212
-% \end{syntax}
-% The \meta{cs} should be a single control sequence, such as |\foo|. This will
-% define \key\ to store \val\ inside of the control sequence. But unlike the
-% |store| type, the macro \meta{cs} will be a switch at the same time, it'll
-% take two arguments and if \key\ was used expands to the first argument
-% followed by \val\ in braces, if \key\ was not used \meta{cs} will expand to
-% the second argument (so behave like |\@secondoftwo|). The idea is that with
-% this type you can define a key which should be typeset formatted. The
-% |edata| and |xdata| variants will fully expand \val, the |gdata| and |xdata|
-% variants will store \val\ inside \meta{cs} globally. The |p|-prefixes will
-% only affect the key-macro, \meta{cs} will always be expandable and |\long|.
-% \end{function}
-%
-% \begin{function}{dataT,edataT,gdataT,xdataT}
-% \begin{syntax}
-% dataT \key\ = \meta{cs} \prefixes2212
-% \end{syntax}
-% Just like |data|, but instead of \meta{cs} grabbing two arguments it'll only
-% grab one, so by default it'll behave like |\@gobble|, and if a \val\ was
-% given to \key\ the \meta{cs} will behave like |\@firstofone| appended by
-% \marg{value}.
-% \end{function}
-%
-% \begin{function}{int,eint,gint,xint}
-% \begin{syntax}
-% int \key\ = \meta{cs} \prefixes2212
-% \end{syntax}
-% The \meta{cs} should be a single control sequence, such as |\foo|.
-% An |int| key will be a \TeX-count register. If \meta{cs} isn't defined yet,
-% |\newcount| will be used to initialise it. The |eint| and |xint| versions
-% will use |\numexpr| to allow basic computations in their \val. The |gint|
-% and |xint| variants set the register globally.
-% \end{function}
-%
-% \begin{function}{dimen,edimen,gdimen,xdimen}
-% \begin{syntax}
-% dimen \key\ = \meta{cs} \prefixes2212
-% \end{syntax}
-% The \meta{cs} should be a single control sequence, such as |\foo|.
-% This is just like |int| but uses a dimen register, |\newdimen| and
-% |\dimexpr| instead.
-% \end{function}
-%
-% \begin{function}{skip,eskip,gskip,xskip}
-% \begin{syntax}
-% skip \key\ = \meta{cs} \prefixes2212
-% \end{syntax}
-% The \meta{cs} should be a single control sequence, such as |\foo|.
-% This is just like |int| but uses a skip register, |\newskip| and |\glueexpr|
-% instead.
-% \end{function}
-%
-% \begin{function}{toks,gtoks,apptoks,gapptoks,pretoks,gpretoks}
-% \begin{syntax}
-% toks \key\ = \meta{cs} \prefixes2212
-% \end{syntax}
-% The \meta{cs} should be a single control sequence, such as |\foo|.
-% Store \val\ inside of a toks-register. The |g| variants use |\global|, the
-% |app| variants append \val\ to the contents of that register, the |pre|
-% variants will prepend \val. If \meta{cs} is not yet defined it will be
-% initialised with |\newtoks|.
-% \end{function}
-%
-% \begin{function}{box,gbox}
-% \begin{syntax}
-% box \key\ = \meta{cs} \prefixes2212
-% \end{syntax}
-% The \meta{cs} should be a single control sequence, such as |\foo|.
-% Typesets \val\ into a |\hbox| and stores the result in a box register. The
-% boxes are colour safe. \expkvd\ doesn't provide a |vbox| type.
-% \end{function}
-%
-% \begin{function}{meta}
-% \begin{syntax}
-% meta \key\ = \{\kv, \ldots\} \prefixes2222
-% \end{syntax}
-% This key type can set other keys, you can access the \val\ which was passed
-% to \key\ inside the \kv\ list with |#1|. It works by calling a sub-|\ekvset|
-% on the \kv\ list, so a |set| key will only affect that \kv\ list and not the
-% current |\ekvset|. Since it runs in a separate |\ekvset| you can't use
-% |\ekvsneak| using keys or similar macros in the way you normally could.
-% \end{function}
-%
-% \begin{function}{nmeta}
-% \begin{syntax}
-% nmeta \key\ = \{\kv, \ldots\} \prefixes2223
-% \end{syntax}
-% This key type can set other keys, the difference to |meta| is, that this key
-% doesn't take a value, so the \kv\ list is static.
-% \end{function}
-%
-% \begin{function}{smeta}
-% \begin{syntax}
-% smeta \key\ = \marg{set}\{\kv, \ldots\} \prefixes2222
-% \end{syntax}
-% Yet another |meta| variant. An |smeta| key will take a \val\ which you can
-% access using |#1|, but it sets the \kv\ list inside of \set, so is equal to
-% \texttt{\cs[no-index]{ekvset}\marg{set}\{\kv, \ldots\}}.
-% \end{function}
-%
-% \begin{function}{snmeta}
-% \begin{syntax}
-% snmeta \key\ = \marg{set}\{\kv, \ldots\} \prefixes2223
-% \end{syntax}
-% And the last |meta| variant. |snmeta| is a combination of |smeta| and
-% |nmeta|. It doesn't take an argument and sets the \kv\ list inside of \set.
-% \end{function}
-%
-% \begin{function}{set}
-% \begin{syntax}
-% set \key\ = \marg{set} \prefixes2233
-% \end{syntax}
-% This will define \key\ to change the set of the current |\ekvset|
-% invocation to \set. You can omit \set\ (including the equals sign),
-% which is the same as using \texttt{set \key\ = \{\key\}}. The created |set|
-% key will not take a \val. Note that just like in \expkv\ it'll not be
-% checked whether \set\ is defined and you'll get a low-level \TeX\ error if
-% you use an undefined \set.
-% \end{function}
-%
-% \begin{function}{choice}
-% \begin{syntax}
-% choice \key\ = \{\val=\meta{definition}, \ldots\} \prefixes2223
-% \end{syntax}
-% Defines \key\ to be a |choice| key, meaning it will only accept a limited
-% set of values. You should define each possible \val\ inside of the
-% \val=\meta{definition} list. If a defined \val\ is passed to \key\ the
-% \meta{definition} will be left in the input stream. You can make
-% individual values |protected| inside the \val=\meta{definition} list. By
-% default a |choice| key is expandable, an undefined \val\ will throw an error
-% in an expandable way (but see the |unknown-choice| prefix). You can add
-% additional choices after the \key\ was created by using |choice| again for
-% the same \key, redefining choices is possible the same way, but there is no
-% interface to remove certain choices.
-% \end{function}
-%
-% \begin{function}{choice-store}
-% \begin{syntax}
-% choice-store \key\ = \meta{cs}\{\val, \ldots\} \prefixes2223
-% \end{syntax}
-% This is defines a special type of |choice| key that'll store the given
-% choice inside the macro \meta{cs} (so \meta{cs} should be a single control
-% sequence name such as |\foo|). Since storing inside a macro can't be done
-% expandably every choice-code is |\protected|, you might define the
-% |choice-store| key itself as |protected| as well if you want. Since the
-% definition of each choice is predefined with this key type the choice list
-% should just be a comma separated list of valid choices.
-% \end{function}
-% This means that the following |choice| and |choice-store| keys are equivalent
-% at use time:
-% \begin{lstlisting}
-% \newcommand*\mya{}
-% \ekvdefinekeys{example}
-% {
-% choice key1 = {a=\def\mya{a}, b=\def\mya{b}, c=\def\mya{c}}
-% ,choice-store key2 = \mya{a,b,c}
-% }
-% \end{lstlisting}
-%
-% \begin{function}{choice-enum}
-% \begin{syntax}
-% choice-enum \key\ = \meta{cs}\{\val, \ldots\} \prefixes2223
-% \end{syntax}
-% This is similar to |choice-store|, the differences are: \meta{cs} should be
-% a count-register or is initialised as such if the \meta{cs} is undefined
-% (via |\newcount|); instead of the value the position of the value in the
-% given list is stored in this register (zero-based).
-% \end{function}
-% This means that the following |choice| and |choice-enum| keys are equivalent
-% at use time:
-% \begin{lstlisting}
-% \newcount\myb
-% \ekvdefinekeys{example}
-% {
-% choice key1 = {a={\myb=0 }, b={\myb=1 }, c={\myb=2 }}
-% ,choice-enum key2 = \myb{a,b,c}
-% }
-% \end{lstlisting}
-%
-% \begin{function}{unknown-choice}
-% \begin{syntax}
-% unknown-choice \key\ = \marg{definition} \prefixes2323
-% \end{syntax}
-% By default an unknown \val\ passed to a |choice| or |bool| key will throw an
-% error. However, with this prefix you can define an alternative action which
-% should be executed if \key\ received an unknown choice. In \meta{definition}
-% you can refer to the choice which was passed in with |#1|.
-% \end{function}
-%
-% \begin{function}{unknown code}
-% \begin{syntax}
-% unknown code = \marg{definition} \prefixes2322
-% \end{syntax}
-% By default \expkv\ throws errors when it encounters unknown keys in a set.
-% With the |unknown| prefix you can define handlers that deal with undefined
-% keys, instead of a \key\ name you have to specify a subtype for this prefix,
-% here the subtype is |code|.\par
-% With |unknown code| the \meta{definition} is used for unknown keys which
-% were provided a value (so corresponds to |\ekvdefunknown|), you can access
-% the key name with |#1| and the value with |#2|.\footnotemark
-% \end{function}
-% \footnotetext
-% {^^A
-% There is some trickery involved to get this more intuitive argument order
-% without any performance hit if you compare this to
-% \cs[no-index]{ekvdefunknown} directly.^^A
-% }
-%
-% \begin{function}{unknown noval}
-% \begin{syntax}
-% unknown noval = \marg{definition} \prefixes2323
-% \end{syntax}
-% This is like |unknown code| but uses \meta{definition} for unknown keys to
-% which no value was passed (so corresponds to |\ekvdefunknownNoVal|). You can
-% access the key name with |#1|.
-% \end{function}
-%
-% \begin{function}{unknown redirect-code}
-% \begin{syntax}
-% unknown redirect-code = \marg{set-list} \prefixes2331
-% \end{syntax}
-% This uses a predefined action for |unknown code|. Instead of throwing an
-% error, it is tried to find the \key\ in each \set\ in the comma separated
-% \meta{set-list}. The first found match will be used and the remaining
-% options from the list discarded. If the \key\ isn't found in any \set\ an
-% expandable error will be thrown eventually. Internally \expkv's
-% |\ekvredirectunknown| will be used.
-% \end{function}
-%
-% \begin{function}{unknown redirect-noval}
-% \begin{syntax}
-% unknown redirect-noval = \marg{set-list} \prefixes2333
-% \end{syntax}
-% This behaves just like |unknown redirect-code| but will set up means to
-% forward keys for |unknown noval|. Internally \expkv's
-% |\ekvredirectunknownNoVal| will be used.
-% \end{function}
-%
-% \begin{function}{unknown redirect}
-% \begin{syntax}
-% unknown redirect = \marg{set-list} \prefixes2333
-% \end{syntax}
-% This is a short cut to apply both, |unknown redirect-code| and
-% |unknown redirect-noval|, as a result you might get doubled error messages,
-% one from each.
-% \end{function}
-%
-% \subsection{Bugs}
-% I don't think there are any (but every developer says that), if you find some
-% please let me know, either via the email address on the first page or on
-% GitHub:
-% \url{https://github.com/Skillmon/tex_expkv-def}
-%
-% \subsection{Example}
-% The following is an example code defining each base key-type once. Please
-% admire the very creative key-name examples.
-%
-% \begin{lstlisting}
-% \ekvdefinekeys{example}
-% {
-% long code keyA = #1
-% ,noval keyA = NoVal given
-% ,bool keyB = \keyB
-% ,boolTF keyC = \keyC
-% ,store keyD = \keyD
-% ,data keyE = \keyE
-% ,dataT keyF = \keyF
-% ,int keyG = \keyG
-% ,dimen keyH = \keyH
-% ,skip keyI = \keyI
-% ,toks keyJ = \keyJ
-% ,default keyJ = \empty test
-% ,new box keyK = \keyK
-% ,qdefault keyK = K
-% ,choice keyL =
-% {
-% protected 1 = \texttt{a}
-% ,2 = b
-% ,3 = c
-% ,4 = d
-% ,5 = e
-% }
-% ,edefault keyL = 2
-% ,meta keyM = {keyA={#1},keyB=false}
-% ,invbool keyN = \keyN
-% ,boolpair keyO = \keyOa\keyOb
-% }
-% \end{lstlisting}
-%
-% \bigskip
-% Since the |data| type might be a bit strange, here is another usage example
-% for it.
-% \begin{lstlisting}
-% \ekvdefinekeys{ex}
-% {
-% data name = \Pname
-% ,data age = \Page
-% ,dataT hobby = \Phobby
-% }
-% \newcommand\Person[1]
-% {%
-% \begingroup
-% \ekvset{ex}{#1}%
-% \begin{description}
-% \item[\Pname{}{\errmessage{A person requires a name}}]
-% \item[Age] \Page{\textit}{\errmessage{A person requires an age}}
-% \Phobby{\item[Hobbies]}
-% \end{description}
-% \endgroup
-% }
-% \Person{name=Jonathan P. Spratte, age=young, hobby=\TeX\ coding}
-% \Person{name=Some User, age=unknown, hobby=Reading Documentation}
-% \Person{name=Anybody, age=any}
-% \end{lstlisting}
-% In this example a person should have a name and an age, but doesn't have to
-% have hobbies. The name will be displayed as the description item and the age
-% in Italics. If a person has no hobbies the description item will be silently
-% left out. The result of the above code looks like this:
-%
-% \begin{exresult}{\linewidth}
-% \ekvdefinekeys{ex}
-% {
-% data name = \Pname
-% ,data age = \Page
-% ,dataT hobby = \Phobby
-% }
-% \newcommand\Person[1]
-% {%
-% \begingroup
-% \ekvset{ex}{#1}%
-% \begin{description}
-% \item[\Pname{}{\errmessage{A person requires a name}}]
-% \item[Age] \Page{\textit}{\errmessage{A person requires an age}}
-% \Phobby{\item[Hobbies]}
-% \end{description}
-% \endgroup
-% }
-% \Person{name=Jonathan P. Spratte, age=young, hobby=\TeX\ coding}
-% \Person{name=Some User, age=unknown, hobby=Reading Documentation}
-% \Person{name=Anybody, age=any}
-% \end{exresult}
-%
-% \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}^^A>>=
-%^^A the LaTeX package >>=
-% \subsection{The \LaTeX\ Package}
-% Just like for \expkv\ we provide a small \LaTeX\ package that sets up things
-% such that we behave nicely on \LaTeX\ packages and files system. It'll
-% |\input| the generic code which implements the functionality.
-% \gobbledocstriptag
-%<*pkg>
-% \begin{macrocode}
-\RequirePackage{expkv}
-\def\ekvd@tmp
- {%
- \ProvidesFile{expkv-def.tex}%
- [\ekvdDate\space v\ekvdVersion\space a key-defining frontend for expkv]%
- }
-\input{expkv-def.tex}
-\ProvidesPackage{expkv-def}%
- [\ekvdDate\space v\ekvdVersion\space a key-defining frontend for expkv]
-% \end{macrocode}
-% \gobbledocstriptag
-%</pkg>
-%^^A=<<
-%^^A the ConTeXt module >>=
-% \subsection{The \ConTeXt\ module}
-% \gobbledocstriptag
-%<*ctx>
-% \begin{macrocode}
-\writestatus{loading}{ConTeXt User Module / expkv-def}
-\usemodule[expkv]
-\unprotect
-\input expkv-def.tex
-\writestatus{loading}
- {ConTeXt User Module / expkv-def / Version \ekvdVersion\space loaded}
-\protect\endinput
-% \end{macrocode}
-% \gobbledocstriptag
-%</ctx>
-%^^A=<<
-%^^A main file >>=
-% \subsection{The Generic Code}
-% The rest of this implementation will be the generic code.
-% \gobbledocstriptag
-%<*tex>
-%
-% Load \expkv\ if the package didn't already do so -- since \expkv\ has
-% safeguards against being loaded twice this does no harm and the overhead
-% isn't that big. Also we reuse some of the internals of \expkv\ to save us from
-% retyping them.
-% \begin{macrocode}
-\input expkv
-% \end{macrocode}
-%
-% We make sure that \file{expkv-def.tex} is only input once:
-% \begin{macrocode}
-\expandafter\ifx\csname ekvdVersion\endcsname\relax
-\else
- \expandafter\endinput
-\fi
-% \end{macrocode}
-%
-% \begin{macro}{\ekvdVersion,\ekvdDate}
-% We're on our first input, so lets store the version and date in a macro.
-% \begin{macrocode}
-\def\ekvdVersion{0.9}
-\def\ekvdDate{2022-01-29}
-% \end{macrocode}
-% \end{macro}
-%
-% If the \LaTeX\ format is loaded we want to be a good file and report back who
-% we are, for this the package will have defined |\ekvd@tmp| to use
-% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
-% \begin{macrocode}
-\csname ekvd@tmp\endcsname
-% \end{macrocode}
-%
-% Store the category code of |@| to later be able to reset it and change it to
-% 11 for now.
-% \begin{macrocode}
-\expandafter\chardef\csname ekvd@tmp\endcsname=\catcode`\@
-\catcode`\@=11
-% \end{macrocode}
-% |\ekvd@tmp| will be reused later to handle expansion during the key
-% defining. But we don't need it to ever store information long-term after
-% \expkvd\ was initialized.
-%
-% \begin{macro}[internal]{\ekvd@ifprimitive}
-% \begin{macrocode}
-\protected\long\def\ekvd@ifprimitive#1%
- {%
- \begingroup
- \edef\ekvd@tmpa{\string #1}%
- \edef\ekvd@tmpb{\meaning#1}%
- \expandafter
- \endgroup
- \ifx\ekvd@tmpa\ekvd@tmpb
- \ekv@fi@firstoftwo
- \fi
- \@secondoftwo
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvd@long,\ekvd@prot,\ekvd@clear@prefixes,\ekvd@ifalso}
-% \expkvd\ will use |\ekvd@long|, |\ekvd@prot|, and |\ekvd@ifalso| to store
-% whether a key should be defined as |\long| or |\protected| or adds an action
-% to an existing key, and we have to clear them for every new key. By default
-% |long| and |protected| will just be empty, |ifalso| will be
-% |\@secondoftwo|, and |ifnew| will just use its third argument.
-% \begin{macrocode}
-\protected\def\ekvd@clear@prefixes
- {%
- \let\ekvd@long\ekv@empty
- \let\ekvd@prot\ekv@empty
- \let\ekvd@ifalso\@secondoftwo
- \long\def\ekvd@ifnew##1##2##3{##3}%
- }
-\ekvd@clear@prefixes
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvdefinekeys}
-% This is the one front-facing macro which provides the interface to define
-% keys. It's using |\ekvparse| to handle the \kv\ list, the interpretation will
-% be done by |\ekvd@noarg| and |\ekvd@|. The \set\ for which the keys should be
-% defined is stored in |\ekvd@set|.
-% \begin{macrocode}
-\protected\def\ekvdefinekeys#1%
- {%
- \def\ekvd@set{#1}%
- \ekvparse\ekvd@noarg\ekvd@arg
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@noarg,\ekvd@arg,\ekvd@handle}
-% |\ekvd@noarg| and |\ekvd@arg| store whether there was a value in the \kv\
-% pair. |\ekvd@handle| has to test whether there is a space inside the key and
-% if so calls the prefix grabbing routine, else we throw an error and ignore the
-% key.
-% \begin{macrocode}
-\protected\long\def\ekvd@noarg#1%
- {%
- \let\ekvd@ifnoarg\@firstoftwo
- \expandafter\ekvd@handle\detokenize{#1}\ekvd@stop{}%
- }
-\protected\long\def\ekvd@arg#1%
- {%
- \let\ekvd@ifnoarg\@secondoftwo
- \expandafter\ekvd@handle\detokenize{#1}\ekvd@stop
- }
-\protected\long\def\ekvd@handle#1\ekvd@stop#2%
- {%
- \ekvd@clear@prefixes
- \def\ekvd@cur{#1}%
- \ekvd@ifspace{#1}%
- {\ekvd@prefix\ekv@mark#1\ekv@stop{#2}}%
- \ekvd@err@missing@type
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@prefix,\ekvd@prefix@}
-% \expkvd\ separates prefixes into two groups, the first being prefixes in the
-% \TeX\ sense (|long| and |protected|) which use |@p@| in their name, the other
-% being key-types (|code|, |int|, \emph{etc.}) which use |@t@| instead.
-% |\ekvd@prefix| splits at the first space and checks whether its a |@p@|
-% or |@t@| type prefix. If it is neither throw an error and gobble the
-% definition (the value).
-% \begin{macrocode}
-\protected\def\ekvd@prefix#1 {\ekv@strip{#1}\ekvd@prefix@\ekv@mark}
-\protected\def\ekvd@prefix@#1#2\ekv@stop
- {%
- \ekv@ifdefined{ekvd@t@#1}%
- {\ekv@strip{#2}{\csname ekvd@t@#1\endcsname}}%
- {%
- \ekv@ifdefined{ekvd@p@#1}%
- {\csname ekvd@p@#1\endcsname\ekvd@prefix@after@p{#2}}%
- {\ekvd@err@undefined@prefix{#1}\@gobble}%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@prefix@after@p}
-% The |@p@| type prefixes are all just modifying a following |@t@| type, so they
-% will need to search for another prefix. This is true for all of them, so we
-% use a macro to handle this. It'll throw an error if there is no other prefix.
-% \begin{macrocode}
-\protected\def\ekvd@prefix@after@p#1%
- {%
- \ekvd@ifspace{#1}%
- {\ekvd@prefix#1\ekv@stop}%
- {\ekvd@err@missing@type\@gobble}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvd@p@long,\ekvd@p@protected,\ekvd@p@protect,\ekvd@p@also,\ekvd@p@new}
-% Define the |@p@| type prefixes, they all just store some information in a
-% temporary macro.
-% \begin{macrocode}
-\protected\def\ekvd@p@long{\let\ekvd@long\long}
-\protected\def\ekvd@p@protected{\let\ekvd@prot\protected}
-\let\ekvd@p@protect\ekvd@p@protected
-\protected\def\ekvd@p@also{\let\ekvd@ifalso\@firstoftwo}
-\protected\def\ekvd@p@new{\let\ekvd@ifnew\ekvd@assert@new}
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Key Types}
-%
-% \begin{macro}[internal]{\ekvd@type@set,\ekvd@t@set}
-% The |set| type is quite straight forward, just define a |NoVal| key to call
-% |\ekvchangeset|.
-% \begin{macrocode}
-\protected\def\ekvd@type@set#1#2%
- {%
- \ekvd@assert@not@long
- \ekvd@assert@not@protected
- \ekvd@ifnew{NoVal}{#1}%
- {%
- \ekv@ifempty{#2}%
- {\ekvd@err@missing@definition}%
- {%
- \ekvd@ifalso
- {%
- \ekv@expargtwice{\ekvd@add@noval{#1}}%
- {\ekvchangeset{#2}}%
- \ekvd@assert@not@protected@also
- }%
- {\ekv@expargtwice{\ekvdefNoVal\ekvd@set{#1}}{\ekvchangeset{#2}}}%
- }%
- }%
- }
-\protected\def\ekvd@t@set#1#2%
- {%
- \ekvd@ifnoarg
- {\ekvd@type@set{#1}{#1}}%
- {\ekvd@type@set{#1}{#2}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@type@noval,\ekvd@t@noval,\ekvd@t@enoval}
-% Another pretty simple type, |noval| just needs to assert that there is a
-% definition and that |long| wasn't specified.
-% There are types where the difference in the variants is so small, that we
-% define a common handler for them, those common handlers are named with
-% |@type@|. |noval| and |enoval| are so similar that we can use such a |@type@|
-% macro, even if we could've done |noval| in a slightly faster way without it.
-% \begin{macrocode}
-\protected\long\def\ekvd@type@noval#1#2#3%
- {%
- \ekvd@ifnew{NoVal}{#2}%
- {%
- \ekvd@assert@arg
- {%
- \ekvd@assert@not@long
- \ekvd@prot#1\ekvd@tmp{#3}%
- \ekvd@ifalso
- {\ekv@exparg{\ekvd@add@noval{#2}}\ekvd@tmp{}}%
- {\ekvletNoVal\ekvd@set{#2}\ekvd@tmp}%
- }%
- }%
- }
-\protected\def\ekvd@t@noval{\ekvd@type@noval\def}
-\protected\def\ekvd@t@enoval{\ekvd@type@noval\edef}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@type@code,\ekvd@t@code,\ekvd@t@ecode}
-% |code| is simple as well, |ecode| has to use |\edef| on a temporary macro,
-% since \expkv\ doesn't provide an |\ekvedef|.
-% \begin{macrocode}
-\protected\long\def\ekvd@type@code#1#2#3%
- {%
- \ekvd@ifnew{}{#2}%
- {%
- \ekvd@assert@arg
- {%
- \ekvd@prot\ekvd@long#1\ekvd@tmp##1{#3}%
- \ekvd@ifalso
- {\ekv@exparg{\ekvd@add@val{#2}}{\ekvd@tmp{##1}}{}}%
- {\ekvlet\ekvd@set{#2}\ekvd@tmp}%
- }%
- }%
- }
-\protected\def\ekvd@t@code{\ekvd@type@code\def}
-\protected\def\ekvd@t@ecode{\ekvd@type@code\edef}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@type@default,\ekvd@t@default,\ekvd@t@qdefault,\ekvd@t@odefault,
-% \ekvd@t@fdefault
-% }
-% |\ekvd@type@default| asserts there was an argument, also the key for which one
-% wants to set a default has to be already defined (this is not so important for
-% |default|, but |qdefault| requires is). If everything is good, |\edef| a
-% temporary macro that expands |\ekvd@set| and the |\csname| for the key, and in
-% the case of |qdefault| does the first expansion step of the key-macro.
-% \begin{macrocode}
-\protected\long\def\ekvd@type@default#1#2#3#4%
- {%
- \ekvd@assert@arg
- {%
- \ekvifdefined\ekvd@set{#3}%
- {%
- \ekvd@assert@not@new
- \ekvd@assert@not@long
- \ekvd@prot\edef\ekvd@tmp
- {%
- \ekv@unexpanded\expandafter#1%
- {#2\csname\ekv@name\ekvd@set{#3}\endcsname{#4}}%
- }%
- \ekvd@ifalso
- {\ekv@exparg{\ekvd@add@noval{#3}}\ekvd@tmp{}}%
- {\ekvletNoVal\ekvd@set{#3}\ekvd@tmp}%
- }%
- {\ekvd@err@undefined@key{#3}}%
- }%
- }
-\protected\def\ekvd@t@default{\ekvd@type@default{}{}}
-\protected\def\ekvd@t@qdefault{\ekvd@type@default{\expandafter\expandafter}{}}
-\let\ekvd@t@odefault\ekvd@t@qdefault
-\protected\def\ekvd@t@fdefault{\ekvd@type@default{}{\romannumeral`\^^@}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@t@edefault}
-% |edefault| is too different from |default| and |qdefault| to reuse the
-% |@type@| macro, as it doesn't need |\unexpanded| inside of |\edef|.
-% \begin{macrocode}
-\protected\long\def\ekvd@t@edefault#1#2%
- {%
- \ekvd@assert@arg
- {%
- \ekvifdefined\ekvd@set{#1}%
- {%
- \ekvd@assert@not@new
- \ekvd@assert@not@long
- \ekvd@prot\edef\ekvd@tmp
- {\csname\ekv@name\ekvd@set{#1}\endcsname{#2}}%
- \ekvd@ifalso
- {\ekv@exparg{\ekvd@add@noval{#1}}\ekvd@tmp{}}%
- {\ekvletNoVal\ekvd@set{#1}\ekvd@tmp}%
- }%
- {\ekvd@err@undefined@key{#1}}%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvd@t@initial,\ekvd@t@oinitial,\ekvd@t@finitial,\ekvd@t@einitial}
-% \begin{macrocode}
-\long\def\ekvd@type@initial#1#2#3#4%
- {%
- \ekvd@assert@not@new
- \ekvd@assert@not@also
- \ekvd@assert@not@long
- \ekvd@assert@not@protected
- \ekvd@ifnoarg
- {%
- \ekvifdefinedNoVal\ekvd@set{#3}%
- {\csname\ekv@name\ekvd@set{#3}N\endcsname}%
- {\ekvd@err@undefined@noval{#3}}%
- }%
- {%
- \ekvifdefined\ekvd@set{#3}%
- {%
- #1{#2#4}%
- \csname\ekv@name\ekvd@set{#3}\expandafter\endcsname\expandafter
- {\ekvd@tmp}%
- }%
- {\ekvd@err@undefined@key{#3}}%
- }%
- }
-\def\ekvd@t@initial{\ekvd@type@initial{\def\ekvd@tmp}{}}
-\def\ekvd@t@oinitial{\ekvd@type@initial{\ekv@exparg{\def\ekvd@tmp}}{}}
-\def\ekvd@t@einitial{\ekvd@type@initial{\edef\ekvd@tmp}{}}
-\def\ekvd@t@finitial
- {\ekvd@type@initial{\ekv@exparg{\def\ekvd@tmp}}{\romannumeral`\^^@}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@type@bool,\ekvd@t@bool,\ekvd@t@gbool,\ekvd@t@boolTF,\ekvd@t@gboolTF,
-% \ekvd@t@invbool,\ekvd@t@ginvbool,\ekvd@t@invboolTF,\ekvd@t@ginvboolTF,
-% }
-% The boolean types are a quicker version of a |choice| that accept |true| and
-% |false|, and set up the |NoVal| action to be identical to \texttt{\key=true}.
-% The |true| and |false| actions are always just |\let|ting the macro in |#7| to
-% some other macro (\emph{e.g.}, \cs[no-index]{iftrue}).
-% \begin{macrocode}
-\protected\def\ekvd@type@bool#1#2#3#4#5%
- {%
- \ekvd@ifnew{}{#4}%
- {%
- \ekvd@ifnew{NoVal}{#4}%
- {%
- \ekvd@assert@filledarg{#5}%
- {%
- \ekvd@newlet#5#3%
- \ekvd@type@choice{#4}%
- \protected\ekvdefNoVal\ekvd@set{#4}{#1\let#5#2}%
- \protected\expandafter\def
- \csname\ekvd@choice@name\ekvd@set{#4}{true}\endcsname
- {#1\let#5#2}%
- \protected\expandafter\def
- \csname\ekvd@choice@name\ekvd@set{#4}{false}\endcsname
- {#1\let#5#3}%
- }%
- }%
- }%
- }
-\protected\def\ekvd@t@bool{\ekvd@type@bool{}\iftrue\iffalse}
-\protected\def\ekvd@t@gbool{\ekvd@type@bool\global\iftrue\iffalse}
-\protected\def\ekvd@t@boolTF{\ekvd@type@bool{}\@firstoftwo\@secondoftwo}
-\protected\def\ekvd@t@gboolTF{\ekvd@type@bool\global\@firstoftwo\@secondoftwo}
-\protected\def\ekvd@t@invbool{\ekvd@type@bool{}\iffalse\iftrue}
-\protected\def\ekvd@t@ginvbool{\ekvd@type@bool\global\iffalse\iftrue}
-\protected\def\ekvd@t@invboolTF{\ekvd@type@bool{}\@secondoftwo\@firstoftwo}
-\protected\def\ekvd@t@ginvboolTF
- {\ekvd@type@bool\global\@secondoftwo\@firstoftwo}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@type@boolpair,
-% \ekvd@t@boolpair,\ekvd@t@gboolpair,\ekvd@t@boolpairTF,\ekvd@t@gboolpairTF
-% }
-% The boolean pair types are essentially the same as the boolean types, but set
-% two macros instead of one.
-% \begin{macrocode}
-\protected\def\ekvd@type@boolpair#1#2#3#4#5#6%
- {%
- \ekvd@ifnew{}{#4}%
- {%
- \ekvd@ifnew{NoVal}{#4}%
- {%
- \ekvd@newlet#5#3%
- \ekvd@newlet#6#2%
- \ekvd@type@choice{#4}%
- \protected\ekvdefNoVal\ekvd@set{#4}{#1\let#5#2#1\let#6#3}%
- \protected\expandafter\def
- \csname\ekvd@choice@name\ekvd@set{#4}{true}\endcsname
- {#1\let#5#2#1\let#6#3}%
- \protected\expandafter\def
- \csname\ekvd@choice@name\ekvd@set{#4}{false}\endcsname
- {#1\let#5#3#1\let#6#2}%
- }%
- }%
- }
-\protected\def\ekvd@t@boolpair#1#2%
- {\ekvd@assert@twoargs{#2}{\ekvd@type@boolpair{}\iftrue\iffalse{#1}#2}}
-\protected\def\ekvd@t@gboolpair#1#2%
- {\ekvd@assert@twoargs{#2}{\ekvd@type@boolpair\global\iftrue\iffalse{#1}#2}}
-\protected\def\ekvd@t@boolpairTF#1#2%
- {%
- \ekvd@assert@twoargs{#2}%
- {\ekvd@type@boolpair{}\@firstoftwo\@secondoftwo{#1}#2}%
- }
-\protected\def\ekvd@t@gboolpairTF#1#2%
- {%
- \ekvd@assert@twoargs{#2}%
- {\ekvd@type@boolpair\global\@firstoftwo\@secondoftwo{#1}#2}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@type@data,\ekvd@t@data,\ekvd@t@gdata,\ekvd@t@dataT,\ekvd@t@gdataT
-% }
-% \begin{macrocode}
-\protected\def\ekvd@type@data#1#2#3#4#5#6%
- {%
- \ekvd@ifnew{}{#5}%
- {%
- \ekvd@assert@filledarg{#6}%
- {%
- \ekvd@newlet#6#1%
- \ekvd@ifalso
- {%
- \let\ekvd@prot\protected
- \ekvd@add@val{#5}{\long#2#6####1#3{####1{#4}}}{}%
- }%
- {%
- \protected\ekvd@long\ekvdef\ekvd@set{#5}%
- {\long#2#6####1#3{####1{#4}}}%
- }%
- }%
- }%
- }
-\protected\def\ekvd@t@data
- {\ekvd@type@data\@secondoftwo\edef{####2}{\ekv@unexpanded{##1}}}
-\protected\def\ekvd@t@edata{\ekvd@type@data\@secondoftwo\edef{####2}{##1}}
-\protected\def\ekvd@t@gdata
- {\ekvd@type@data\@secondoftwo\xdef{####2}{\ekv@unexpanded{##1}}}
-\protected\def\ekvd@t@xdata{\ekvd@type@data\@secondoftwo\xdef{####2}{##1}}
-\protected\def\ekvd@t@dataT
- {\ekvd@type@data\@gobble\edef{}{\ekv@unexpanded{##1}}}
-\protected\def\ekvd@t@edataT{\ekvd@type@data\@gobble\edef{}{##1}}
-\protected\def\ekvd@t@gdataT
- {\ekvd@type@data\@gobble\xdef{}{\ekv@unexpanded{##1}}}
-\protected\def\ekvd@t@xdataT{\ekvd@type@data\@gobble\xdef{}{##1}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@type@box,\ekvd@t@box,\ekvd@t@gbox}
-% Set up our boxes. Though we're a generic package we want to be colour safe, so
-% we put an additional grouping level inside the box contents, for the case that
-% someone uses \pkg{color}. |\ekvd@newreg| is a small wrapper which tests
-% whether the first argument is defined and if not does
-% |\csname new#2\endcsname#1|.
-% \begin{macrocode}
-\protected\def\ekvd@type@box#1#2#3%
- {%
- \ekvd@ifnew{}{#2}%
- {%
- \ekvd@assert@filledarg{#3}%
- {%
- \ekvd@newreg#3{box}%
- \ekvd@ifalso
- {%
- \let\ekvd@prot\protected
- \ekvd@add@val{#2}{#1\setbox#3=\hbox{\begingroup##1\endgroup}}{}%
- }%
- {%
- \protected\ekvd@long\ekvdef\ekvd@set{#2}%
- {#1\setbox#3=\hbox{\begingroup##1\endgroup}}%
- }%
- }%
- }%
- }
-\protected\def\ekvd@t@box{\ekvd@type@box{}}
-\protected\def\ekvd@t@gbox{\ekvd@type@box\global}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@type@toks,\ekvd@t@toks,\ekvd@t@gtoks}
-% Similar to |box|, but set the |toks|.
-% \begin{macrocode}
-\protected\def\ekvd@type@toks#1#2#3%
- {%
- \ekvd@ifnew{}{#2}%
- {%
- \ekvd@assert@filledarg{#3}%
- {%
- \ekvd@newreg#3{toks}%
- \ekvd@ifalso
- {%
- \let\ekvd@prot\protected
- \ekvd@add@val{#2}{#1#3={##1}}{}%
- }%
- {\protected\ekvd@long\ekvdef\ekvd@set{#2}{#1#3={##1}}}%
- }%
- }%
- }
-\protected\def\ekvd@t@toks{\ekvd@type@toks{}}
-\protected\def\ekvd@t@gtoks{\ekvd@type@toks\global}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@type@preapptoks,\ekvd@t@apptoks,\ekvd@t@gapptoks}
-% Just like |toks|, but expand the current contents of the |toks| register to
-% append the new contents.
-% \begin{macrocode}
-\ekvd@ifprimitive\toksapp
- {%
- \protected\def\ekvd@type@preapptoks#1#2#3%
- {%
- \ekvd@ifnew{}{#2}%
- {%
- \ekvd@assert@filledarg{#3}%
- {%
- \ekvd@newreg#3{toks}%
- \ekvd@ifalso
- {%
- \let\ekvd@prot\protected
- \ekvd@add@val{#2}{#1#3{##1}}{}%
- }%
- {\protected\ekvd@long\ekvdef\ekvd@set{#2}{#1#3{##1}}}%
- }%
- }%
- }
- \protected\def\ekvd@t@apptoks{\ekvd@type@preapptoks\toksapp}
- \protected\def\ekvd@t@gapptoks{\ekvd@type@preapptoks\gtoksapp}
- \protected\def\ekvd@t@pretoks{\ekvd@type@preapptoks\tokspre}
- \protected\def\ekvd@t@gpretoks{\ekvd@type@preapptoks\gtokspre}
- }
- {%
- \protected\def\ekvd@type@apptoks#1#2#3%
- {%
- \ekvd@ifnew{}{#2}%
- {%
- \ekvd@assert@filledarg{#3}%
- {%
- \ekvd@newreg#3{toks}%
- \ekvd@ifalso
- {%
- \let\ekvd@prot\protected
- \ekvd@add@val{#2}{#1#3=\expandafter{\the#3##1}}{}%
- }%
- {%
- \protected\ekvd@long\ekvdef\ekvd@set{#2}%
- {#1#3=\expandafter{\the#3##1}}%
- }%
- }%
- }%
- }
- \protected\def\ekvd@t@apptoks{\ekvd@type@apptoks{}}
- \protected\def\ekvd@t@gapptoks{\ekvd@type@apptoks\global}
- \newtoks\ekvd@toks
- \protected\def\ekvd@type@pretoks#1#2#3%
- {%
- \ekvd@ifnew{}{#2}%
- {%
- \ekvd@assert@filledarg{#3}%
- {%
- \ekvd@newreg#3{toks}%
- \ekvd@ifalso
- {%
- \let\ekvd@prot\protected
- \ekvd@add@val{#2}%
- {%
- \ekvd@toks={##1}%
- #1#3=\expandafter{\the\expandafter\ekvd@toks\the#3}%
- }%
- {}%
- }%
- {%
- \protected\ekvd@long\ekvdef\ekvd@set{#2}%
- {%
- \ekvd@toks={##1}%
- #1#3=\expandafter{\the\expandafter\ekvd@toks\the#3}%
- }%
- }%
- }%
- }%
- }
- \protected\def\ekvd@t@pretoks{\ekvd@type@pretoks{}}
- \protected\def\ekvd@t@gpretoks{\ekvd@type@pretoks\global}
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@type@reg,\ekvd@t@int,\ekvd@t@eint,\ekvd@t@gint,\ekvd@t@xint,
-% \ekvd@t@dimen,\ekvd@t@edimen,\ekvd@t@gdimen,\ekvd@t@xdimen,
-% \ekvd@t@skip,\ekvd@t@eskip,\ekvd@t@gskip,\ekvd@t@xskip
-% }
-% The |\ekvd@type@reg| can handle all the types for which the assignment will
-% just be \texttt{\meta{register}=\meta{value}}.
-% \begin{macrocode}
-\protected\def\ekvd@type@reg#1#2#3#4#5#6%
- {%
- \ekvd@ifnew{}{#5}%
- {%
- \ekvd@assert@filledarg{#6}%
- {%
- \ekvd@newreg#6{#1}%
- \ekvd@ifalso
- {%
- \let\evkd@prot\protected
- \ekvd@add@val{#5}{#2#6=#3##1#4\relax}{}%
- }%
- {\protected\ekvd@long\ekvdef\ekvd@set{#5}{#2#6=#3##1#4\relax}}%
- }%
- }%
- }
-\protected\def\ekvd@t@int{\ekvd@type@reg{count}{}{}{}}
-\protected\def\ekvd@t@eint{\ekvd@type@reg{count}{}\numexpr\relax}
-\protected\def\ekvd@t@gint{\ekvd@type@reg{count}\global{}{}}
-\protected\def\ekvd@t@xint{\ekvd@type@reg{count}\global\numexpr\relax}
-\protected\def\ekvd@t@dimen{\ekvd@type@reg{dimen}{}{}{}}
-\protected\def\ekvd@t@edimen{\ekvd@type@reg{dimen}{}\dimexpr\relax}
-\protected\def\ekvd@t@gdimen{\ekvd@type@reg{dimen}\global{}{}}
-\protected\def\ekvd@t@xdimen{\ekvd@type@reg{dimen}\global\dimexpr\relax}
-\protected\def\ekvd@t@skip{\ekvd@type@reg{skip}{}{}{}}
-\protected\def\ekvd@t@eskip{\ekvd@type@reg{skip}{}\glueexpr\relax}
-\protected\def\ekvd@t@gskip{\ekvd@type@reg{skip}\global{}{}}
-\protected\def\ekvd@t@xskip{\ekvd@type@reg{skip}\global\glueexpr\relax}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@type@store,\ekvd@t@store,\ekvd@t@gstore}
-% The none-expanding |store| types use an |\edef| or |\xdef| and |\unexpanded|
-% to be able to also store |#| easily.
-% \begin{macrocode}
-\protected\def\ekvd@type@store#1#2#3#4%
- {%
- \ekvd@ifnew{}{#3}%
- {%
- \ekvd@assert@filledarg{#4}%
- {%
- \ekvd@newlet#4\ekv@empty
- \ekvd@ifalso
- {%
- \let\ekvd@prot\protected
- \ekvd@add@val{#3}{#1#4{#2}}{}%
- }%
- {\protected\ekvd@long\ekvdef\ekvd@set{#3}{#1#4{#2}}}%
- }%
- }%
- }
-\protected\def\ekvd@t@store{\ekvd@type@store\edef{\ekv@unexpanded{##1}}}
-\protected\def\ekvd@t@gstore{\ekvd@type@store\xdef{\ekv@unexpanded{##1}}}
-\protected\def\ekvd@t@estore{\ekvd@type@store\edef{##1}}
-\protected\def\ekvd@t@xstore{\ekvd@type@store\xdef{##1}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@type@meta,\ekvd@type@meta@a,\ekvd@type@meta@b,\ekvd@type@meta@c,
-% \ekvd@t@meta,\ekvd@t@nmeta
-% }
-% |meta| sets up things such that another instance of |\ekvset| will be run on
-% the argument, with the same \set.
-% \begin{macrocode}
-\protected\long\def\ekvd@type@meta#1#2#3#4#5#6#7%
- {%
- \ekvd@ifnew{#1}{#6}%
- {%
- \ekvd@assert@filledarg{#7}%
- {%
- \edef\ekvd@tmp{\ekvd@set}%
- \expandafter\ekvd@type@meta@a\expandafter{\ekvd@tmp}{#7}{#2}%
- \ekvd@ifalso
- {\ekv@exparg{#3{#6}}{\ekvd@tmp#4}{#5}}%
- {\csname ekvlet#1\endcsname\ekvd@set{#6}\ekvd@tmp}%
- }%
- }%
- }
-\protected\long\def\ekvd@type@meta@a#1#2%
- {%
- \expandafter\ekvd@type@meta@b\expandafter{\ekvset{#1}{#2}}%
- }
-\protected\def\ekvd@type@meta@b
- {%
- \expandafter\ekvd@type@meta@c\expandafter
- }
-\protected\long\def\ekvd@type@meta@c#1#2%
- {%
- \ekvd@prot\ekvd@long\def\ekvd@tmp#2{#1}%
- }
-\protected\def\ekvd@t@meta{\ekvd@type@meta{}{##1}\ekvd@add@val{{##1}}{}}
-\protected\def\ekvd@t@nmeta
- {%
- \ekvd@assert@not@long
- \ekvd@type@meta{NoVal}{}\ekvd@add@noval{}\ekvd@assert@not@long@also
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvd@type@smeta,\ekvd@type@smeta@,\ekvd@t@smeta,\ekvd@t@snmeta}
-% |smeta| is pretty similar to |meta|, but needs two arguments inside of \val,
-% such that the first is the \set\ for which the sub-|\ekvset| and the second is
-% the \kv\ list.
-% \begin{macrocode}
-\protected\long\def\ekvd@type@smeta#1#2#3#4#5#6#7%
- {%
- \ekvd@ifnew{#1}{#6}%
- {%
- \ekvd@assert@twoargs{#7}%
- {%
- \ekvd@type@meta@a#7{#2}%
- \ekvd@ifalso
- {\ekv@exparg{#3{#6}}{\ekvd@tmp#4}{#5}}%
- {\csname ekvlet#1\endcsname\ekvd@set{#6}\ekvd@tmp}%
- }%
- }%
- }
-\protected\def\ekvd@t@smeta{\ekvd@type@smeta{}{##1}\ekvd@add@val{{##1}}{}}
-\protected\def\ekvd@t@snmeta
- {%
- \ekvd@assert@not@long
- \ekvd@type@smeta{NoVal}{}\ekvd@add@noval{}\ekvd@assert@not@long@also
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@type@choice,
-% \ekvd@populate@choice,\ekvd@populate@choice@,\ekvd@populate@choice@noarg,
-% \ekvd@choice@prefix,\ekvd@choice@prefix@,\ekvd@choice@prefix@done,
-% \ekvd@choice@p@protected,\ekvd@choice@p@protect,
-% \ekvd@choice@p@long,\ekvd@choice@p@long@,
-% \ekvd@t@choice
-% }
-% The |choice| type is by far the most complex type, as we have to run a
-% sub-parser on the choice-definition list, which should support the |@p@| type
-% prefixes as well (but |long| will always throw an error, as they are not
-% allowed to be long). |\ekvd@type@choice| will just define the choice-key, the
-% handling of the choices definition will be done by |\ekvd@populate@choice|.
-% \begin{macrocode}
-\protected\def\ekvd@type@choice#1%
- {%
- \ekvd@assert@not@long
- \ekv@expargtwice{\ekvd@prot\def\ekvd@tmp##1}%
- {%
- \expandafter\expandafter\expandafter
- \ekvd@h@choice
- \expandafter\expandafter\expandafter
- {\expandafter\ekvd@choice@name\expandafter{\ekvd@set}{#1}{##1}}%
- }%
- \ekvd@ifalso
- {%
- \ekvd@assert@val{#1}%
- {%
- \ekvd@if@not@already@choice{#1}%
- {%
- \ekv@exparg
- {%
- \expandafter\ekvd@add@aux
- \csname\ekv@name\ekvd@set{#1}\endcsname{{##1}}{#1}%
- }%
- {\ekvd@tmp{##1}}%
- {\ekvd@long\ekvdef}\ekvd@assert@not@long@also
- }%
- }%
- }%
- {\ekvlet\ekvd@set{#1}\ekvd@tmp}%
- }
-% \end{macrocode}
-% |\ekvd@populate@choice| just uses |\ekvparse| and then gives control to
-% |\ekvd@populate@choice@noarg|, which throws an error, and
-% |\ekvd@populate@choice@|.
-% \begin{macrocode}
-\protected\def\ekvd@populate@choice
- {%
- \ekvparse\ekvd@populate@choice@noarg\ekvd@populate@choice@
- }
-\protected\long\def\ekvd@populate@choice@noarg#1%
- {%
- \expandafter\ekvd@err@missing@definition@msg\expandafter{\ekvd@cur : #1}%
- }
-% \end{macrocode}
-% |\ekvd@populate@choice@| runs the prefix-test, if there is none we can
-% directly define the choice, for that |\ekvd@set@choice| will expand to the
-% current choice-key's name, which will have been defined by |\ekvd@t@choice|.
-% If there is a prefix run the prefix grabbing routine, which was altered for
-% |@type@choice|.
-% \begin{macrocode}
-\protected\long\def\ekvd@populate@choice@#1#2%
- {%
- \ekvd@clear@prefixes
- \ekvd@ifspace{#1}%
- {\ekvd@choice@prefix{\ekv@mark#1}\ekv@mark#1\ekv@stop}%
- {%
- \expandafter\edef
- \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#1}\endcsname
- }%
- {\unexpanded{#2}}%
- }
-\protected\def\ekvd@choice@prefix#1#2
- {%
- \ekv@strip{#2}{\ekvd@choice@prefix@{#1}}\ekv@mark
- }
-\protected\def\ekvd@choice@prefix@#1#2#3\ekv@stop
- {%
- \ekv@ifdefined{ekvd@choice@p@#2}%
- {%
- \csname ekvd@choice@p@#2\endcsname
- \ekvd@ifspace{#3}%
- {\ekvd@choice@prefix{#3}#3\ekv@stop}%
- {\ekvd@choice@prefix@done{#3}}%
- }%
- {\ekvd@choice@prefix@done{#1}}%
- }
-\protected\def\ekvd@choice@prefix@done#1%
- {%
- \ekvd@prot\expandafter\edef
- \csname
- \ekv@strip{#1}{\ekvd@choice@name\ekvd@set\ekvd@set@choice}%
- \endcsname
- }
-\protected\def\ekvd@choice@p@protected{\let\ekvd@prot\protected}
-\let\ekvd@choice@p@protect\ekvd@choice@p@protected
-\protected\def\ekvd@choice@invalid@p#1\ekvd@ifspace#2%
- {%
- \expandafter\ekvd@choice@invalid@p@\expandafter{\ekv@gobble@mark#2}{#1}%
- \ekvd@ifspace{#2}%
- }
-\protected\def\ekvd@choice@invalid@p@#1#2%
- {%
- \expandafter\ekvd@err@no@prefix@msg\expandafter{\ekvd@cur : #2 #1}{#2}%
- }
-\protected\def\ekvd@choice@p@long{\ekvd@choice@invalid@p{long}}%
-\protected\def\ekvd@choice@p@also{\ekvd@choice@invalid@p{also}}%
-\protected\def\ekvd@choice@p@new{\ekvd@choice@invalid@p{new}}%
-% \end{macrocode}
-% Finally we're able to set up the |@t@choice| macro, which has to store the
-% current choice-key's name, define the key, and parse the available choices.
-% \begin{macrocode}
-\protected\long\def\ekvd@t@choice#1#2%
- {%
- \ekvd@ifnew{}{#1}%
- {%
- \ekvd@assert@arg
- {%
- \ekvd@type@choice{#1}%
- \def\ekvd@set@choice{#1}%
- \ekvd@populate@choice{#2}%
- }%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@t@choice-store,\ekvd@t@choice-enum}
-% These two types define a special kind of |choice| key and are quite similar,
-% the only difference is what the different choices do (hence they use a
-% shared initialisation which differs in the chosen |populate| step).
-% \begin{macrocode}
-\protected\long\expandafter\def\csname ekvd@t@choice-store\endcsname
- {\ekvd@type@choicespecial\ekvd@populate@choicestore}
-\protected\long\expandafter\def\csname ekvd@t@choice-enum\endcsname
- {\ekvd@type@choicespecial\ekvd@populate@choiceenum}
-% \end{macrocode}
-% \begin{macro}[internal]{\ekvd@type@choicespecial}
-% Initialise similar to a |choice| key. The difference is that we require two
-% arguments (which we assert), a macro to store things in, and a |csv|-list
-% containing the allowed values. |#1| is the |populate| macro according to the
-% type used.
-% \begin{macrocode}
-\protected\long\def\ekvd@type@choicespecial#1#2#3%
- {%
- \ekvd@ifnew{}{#2}%
- {%
- \ekvd@assert@twoargs{#3}%
- {%
- \ekvd@type@choice{#2}%
- \def\ekvd@set@choice{#2}%
- #1#3%
- }%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}[internal]
-% {\ekvd@populate@choicestore,\ekvd@populate@choicestore@}
-% We initialise the storing macro if it doesn't yet exist, and then we loop
-% over the value list. The |\edef|s with |\unexpanded| are both necessary to
-% be able to store macro parameter tokens (the outer protects at define time,
-% the inner at use time).
-% \begin{macrocode}
-\protected\long\def\ekvd@populate@choicestore#1%
- {%
- \ekvd@newlet#1\ekv@empty
- \ekvcsvloop{\ekvd@populate@choicestore@#1}%
- }
-\protected\long\def\ekvd@populate@choicestore@#1#2%
- {%
- \protected\expandafter\edef
- \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname
- {\unexpanded{\edef#1{\unexpanded{#2}}}}%
- }
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}[internal]
-% {\ekvd@populate@choiceenum,\ekvd@populate@choiceenum@}
-% This is similar to the population of a |choice-store| type, but instead of
-% storing the values in a macro this initialises a count and stores the
-% position of the value in the list inside that count (zero-indexed). The
-% space is necessary to terminate the number scanning, which is the reason we
-% use |\@firstofone| (so that the space after the macro name isn't gobbled by
-% \TeX).
-% \begin{macrocode}
-\protected\long\def\ekvd@populate@choiceenum#1%
- {%
- \ekvd@newreg#1{count}%
- \def\ekvd@tmp{0}%
- \ekvcsvloop{\ekvd@populate@choiceenum@#1}%
- }
-\protected\long\def\ekvd@populate@choiceenum@#1#2%
- {%
- \protected\expandafter\edef
- \csname\ekvd@choice@name\ekvd@set\ekvd@set@choice{#2}\endcsname
- {#1=\@firstofone{\ekvd@tmp} }%
- \edef\ekvd@tmp{\the\numexpr\ekvd@tmp+1\relax}%
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@t@unknown-choice}
-% \begin{macrocode}
-\protected\long\expandafter\def\csname ekvd@t@unknown-choice\endcsname#1#2%
- {%
- \ekvd@assert@new@for@name{\ekvd@unknown@choice@name\ekvd@set{#1}}%
- {%
- \ekvd@assert@arg
- {%
- \ekvd@assert@not@long
- \ekvd@assert@not@also
- \ekvd@prot\expandafter
- \def\csname\ekvd@unknown@choice@name\ekvd@set{#1}\endcsname##1{#2}%
- }%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvd@t@unknown,\ekvd@type@unknown@code,\ekvd@type@unknown@noval}
-% The |unknown| type has different subtypes which would be the key names for
-% other types. It is first checked whether that subtype is defined, if it
-% isn't throw an error, else use that subtype.
-% \begin{macrocode}
-\protected\long\def\ekvd@t@unknown#1#2%
- {%
- \ekv@ifdefined{ekvd@type@unknown@\detokenize{#1}}%
- {\csname ekvd@type@unknown@\detokenize{#1}\endcsname{#2}}%
- \ekvd@err@misused@unknown
- }
-% \end{macrocode}
-% The |unknown noval| type can use |\ekvdefunknownNoVal| directly (after
-% asserting some prefixes).
-% \begin{macrocode}
-\protected\long\def\ekvd@type@unknown@noval#1%
- {%
- \ekvd@assert@new@for@name{\ekv@name\ekvd@set{}uN}%
- {%
- \ekvd@assert@arg
- {%
- \ekvd@assert@not@also
- \ekvd@assert@not@long
- \ekvd@prot\ekvdefunknownNoVal\ekvd@set{#1}%
- }%
- }%
- }
-% \end{macrocode}
-% The |unknown code| type uses some trickery during the definition in order to
-% swap out |#1| and |#2| in the user supplied definition. This is done via a
-% temporary macro that stores the definition but gets the parameter numbers
-% reversed while the real definition is done.
-% \begin{macrocode}
-\protected\long\def\ekvd@type@unknown@code#1%
- {%
- \ekvd@assert@new@for@name{\ekv@name\ekvd@set{}u}%
- {%
- \ekvd@assert@arg
- {%
- \ekvd@assert@not@also
- \begingroup
- \def\ekvd@tmp##1##2{#1}%
- \ekv@exparg
- {%
- \endgroup
- \ekvd@prot\ekvd@long\ekvdefunknown\ekvd@set
- }%
- {\ekvd@tmp{##2}{##1}}%
- }%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@type@unknown@redirect,
-% \ekvd@type@unknown@redirect-code,
-% \ekvd@type@unknown@redirect-noval
-% }
-% The |unknown redirect| types also just forward to |\ekvredirectunknown|
-% after asserting some prefixes.
-% \begin{macrocode}
-\protected\edef\ekvd@type@unknown@redirect#1%
- {%
- \expandafter\noexpand\csname ekvd@type@unknown@redirect-code\endcsname{#1}%
- \expandafter\noexpand\csname ekvd@type@unknown@redirect-noval\endcsname{#1}%
- }
-\protected\expandafter\def\csname ekvd@type@unknown@redirect-code\endcsname#1%
- {%
- \ekvd@assert@new@for@name{\ekv@name\ekvd@set{}u}%
- {%
- \ekvd@assert@arg
- {%
- \ekvd@assert@not@also
- \ekvd@assert@not@protected
- \expandafter\ekvredirectunknown\expandafter{\ekvd@set}{#1}%
- }%
- }%
- }
-\protected\expandafter\def\csname ekvd@type@unknown@redirect-noval\endcsname#1%
- {%
- \ekvd@assert@new@for@name{\ekv@name\ekvd@set{}uN}%
- {%
- \ekvd@assert@arg
- {%
- \ekvd@assert@not@also
- \ekvd@assert@not@protected
- \ekvd@assert@not@long
- \expandafter\ekvredirectunknownNoVal\expandafter{\ekvd@set}{#1}%
- }%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Key Type Helpers}
-% There are some keys that might need helpers during their execution (not during
-% their definition, which are gathered as |@type@| macros). These helpers are
-% named |@h@|.
-%
-% \begin{macro}[internal]{\ekvd@h@choice,\ekvd@h@choice@}
-% The |choice| helper will just test whether the given choice was defined, if
-% not throw an error expandably, else call the macro which stores the code for
-% this choice.
-% \begin{macrocode}
-\def\ekvd@h@choice#1%
- {%
- \expandafter\ekvd@h@choice@
- \csname\ifcsname#1\endcsname#1\else relax\fi\endcsname
- {#1}%
- }
-\def\ekvd@h@choice@#1#2%
- {%
- \ifx#1\relax
- \ekvd@err@choice@invalid{#2}%
- \expandafter\@gobble
- \fi
- #1%
- }
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \subsubsection{Handling \texttt{also}}
-%
-% \begin{macro}[internal]
-% {\ekvd@add@val,\ekvd@add@noval,\ekvd@add@aux,\ekvd@add@aux@}
-% \begin{macrocode}
-\protected\long\def\ekvd@add@val#1#2#3%
- {%
- \ekvd@assert@val{#1}%
- {%
- \expandafter\ekvd@add@aux\csname\ekv@name\ekvd@set{#1}\endcsname{{##1}}%
- {#1}{#2}{\ekvd@long\ekvdef}{#3}%
- }%
- }
-\protected\long\def\ekvd@add@noval#1#2#3%
- {%
- \ekvd@assert@noval{#1}%
- {%
- \expandafter\ekvd@add@aux\csname\ekv@name\ekvd@set{#1}N\endcsname{}%
- {#1}{#2}\ekvdefNoVal{#3}%
- }%
- }
-\protected\long\def\ekvd@add@aux#1#2%
- {%
- \ekvd@extract@prefixes#1%
- \expandafter\ekvd@add@aux@\expandafter{#1#2}%
- }
-\protected\long\def\ekvd@add@aux@#1#2#3#4#5%
- {%
- #5%
- \ekvd@prot#4\ekvd@set{#2}{#1#3}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@extract@prefixes,\ekvd@extract@prefixes@,
-% \ekvd@extract@prefixes@long,\ekvd@extract@prefixes@prot
-% }
-% This macro checks which prefixes were used for the definition of a macro and
-% sets |\ekvd@long| and |\ekvd@prot| accordingly.
-% \begin{macrocode}
-\protected\def\ekvd@extract@prefixes#1%
- {%
- \expandafter\ekvd@extract@prefixes@\meaning#1\ekvd@stop
- }
-% \end{macrocode}
-% In the following definition |#1| will get replaced by |macro:|, |#2| by
-% |\long| and |#3| by |\protected| (in each, all tokens will have category
-% other). This allows us to parse the |\meaning| of a macro for those strings.
-% \begin{macrocode}
-\protected\def\ekvd@extract@prefixes@#1#2#3%
- {%
- \protected\def\ekvd@extract@prefixes@##1#1##2\ekvd@stop
- {%
- \ekvd@extract@prefixes@long
- ##1\ekvd@mark\@firstofone#2\ekvd@mark\@gobble\ekvd@stop
- {\let\ekvd@long\long}%
- \ekvd@extract@prefixes@prot
- ##1\ekvd@mark\@firstofone#3\ekvd@mark\@gobble\ekvd@stop
- {\let\ekvd@prot\protected}%
- }%
- \protected\def\ekvd@extract@prefixes@long##1#2##2\ekvd@mark##3##4\ekvd@stop
- {##3}%
- \protected\def\ekvd@extract@prefixes@prot##1#3##2\ekvd@mark##3##4\ekvd@stop
- {##3}%
- }
-% \end{macrocode}
-% We use a temporary macro to expand the three arguments of
-% |\ekvd@extract@prefixes@|, which will set up the real meaning of itself and
-% the parsing for |\long| and |\protected|.
-% \begin{macrocode}
-\begingroup
-\edef\ekvd@tmp
- {%
- \endgroup
- \ekvd@extract@prefixes@
- {\detokenize{macro:}}%
- {\string\long}%
- {\string\protected}%
- }
-\ekvd@tmp
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \subsubsection{Tests}
-%
-% \begin{macro}[internal]{\ekvd@newlet,\ekvd@newreg}
-% These macros test whether a control sequence is defined, if it isn't they
-% define it, either via |\let| or via the correct \cs[no-index]{new\meta{reg}}.
-% \begin{macrocode}
-\protected\def\ekvd@newlet#1#2%
- {%
- \ifdefined#1\ekv@fi@gobble\fi\@firstofone{\let#1#2}%
- }
-\protected\def\ekvd@newreg#1#2%
- {%
- \ifdefined#1\ekv@fi@gobble\fi\@firstofone{\csname new#2\endcsname#1}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekvd@assert@twoargs,\ekvd@ifnottwoargs,\ekvd@ifempty@gtwo}
-% A test for exactly two tokens can be reduced for an empty-test after gobbling
-% two tokens, in the case that there are fewer tokens than two in the argument,
-% only macros will be gobbled that are needed for the true branch, which doesn't
-% hurt, and if there are more this will not be empty.
-% \begin{macrocode}
-\long\def\ekvd@assert@twoargs#1%
- {%
- \ekvd@ifnottwoargs{#1}{\ekvd@err@missing@definition}%
- }
-\long\def\ekvd@ifnottwoargs#1%
- {%
- \ekvd@ifempty@gtwo#1\ekv@ifempty@B
- \ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- }
-\long\def\ekvd@ifempty@gtwo#1#2{\ekv@ifempty@\ekv@ifempty@A}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@assert@val,\ekvd@assert@val@,\ekvd@assert@noval,\ekvd@assert@noval@,
-% \ekvd@extract@args,\ekvd@extracted@args,\ekvd@one@arg@string
-% }
-% Assert that a given key is defined as a value taking key or a |NoVal| key with
-% the correct argument structure, respectively.
-% \begin{macrocode}
-\protected\def\ekvd@assert@val#1%
- {%
- \ekvifdefined\ekvd@set{#1}%
- {\expandafter\ekvd@assert@val@\csname\ekv@name\ekvd@set{#1}\endcsname}%
- {%
- \ekvifdefinedNoVal\ekvd@set{#1}%
- \ekvd@err@add@val@on@noval
- {\ekvd@err@undefined@key{#1}}%
- \@gobble
- }%
- }
-\protected\def\ekvd@assert@val@#1%
- {%
- \expandafter\ekvd@extract@args\meaning#1\ekvd@stop
- \unless\ifx\ekvd@extracted@args\ekvd@one@arg@string
- \ekvd@err@unsupported@arg
- \fi
- \@firstofone
- }%
-\protected\def\ekvd@assert@noval#1%
- {%
- \ekvifdefinedNoVal\ekvd@set{#1}%
- {\expandafter\ekvd@assert@noval@\csname\ekv@name\ekvd@set{#1}N\endcsname}%
- {%
- \ekvifdefined\ekvd@set{#1}%
- \ekvd@err@add@noval@on@val
- {\ekvd@err@undefined@key{#1}}%
- \@gobble
- }%
- }
-\protected\def\ekvd@assert@noval@#1%
- {%
- \expandafter\ekvd@extract@args\meaning#1\ekvd@stop
- \unless\ifx\ekvd@extracted@args\ekv@empty
- \ekvd@err@unsupported@arg
- \fi
- \@firstofone
- }
-\protected\def\ekvd@extract@args#1%
- {%
- \protected\def\ekvd@extract@args##1#1##2->##3\ekvd@stop
- {\def\ekvd@extracted@args{##2}}%
- }
-\expandafter\ekvd@extract@args\expandafter{\detokenize{macro:}}
-\edef\ekvd@one@arg@string{\string#1}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@assert@arg,\ekvd@assert@arg@msg,\ekvd@ifnoarg}
-% There is no need to actually define |\ekvd@ifnoarg| here, as it will be set by
-% either |\ekvd@arg| or |\ekvd@noarg|.
-% \begin{macrocode}
-\def\ekvd@assert@arg{\ekvd@ifnoarg\ekvd@err@missing@definition}
-\long\def\ekvd@assert@arg@msg#1%
- {%
- \ekvd@ifnoarg{\ekvd@err@missing@definition@msg{#1}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@assert@filledarg,\ekvd@ifnoarg@or@empty}
-% \begin{macrocode}
-\long\def\ekvd@assert@filledarg#1%
- {%
- \ekvd@ifnoarg@or@empty{#1}\ekvd@err@missing@definition
- }
-\long\def\ekvd@ifnoarg@or@empty#1%
- {%
- \ekvd@ifnoarg
- \@firstoftwo
- {\ekv@ifempty{#1}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@assert@not@long,\ekvd@assert@not@protected,\ekvd@assert@not@also
-% \ekvd@assert@not@long@also,\ekvd@assert@not@protected@also,
-% \ekvd@assert@new,\ekvd@assert@not@new
-% }
-% Some key-types don't want to be |also|, |\long| or |\protected|, so we provide
-% macros to test this and throw an error, this could be silently ignored but now
-% users will learn to not use unnecessary stuff which slows the compilation
-% down.
-% \begin{macrocode}
-\def\ekvd@assert@not@long{\ifx\ekvd@long\long\ekvd@err@no@prefix{long}\fi}
-\def\ekvd@assert@not@protected
- {\ifx\ekvd@prot\protected\ekvd@err@no@prefix{protected}\fi}
-\def\ekvd@assert@not@also{\ekvd@ifalso{\ekvd@err@no@prefix{also}}{}}
-\def\ekvd@assert@not@long@also
- {\ifx\ekvd@long\long\ekvd@err@no@prefix@also{long}\fi}
-\def\ekvd@assert@not@protected@also
- {\ifx\ekvd@prot\protected\ekvd@err@no@prefix@also{protected}\fi}
-\def\ekvd@assert@new#1#2%
- {\csname ekvifdefined#1\endcsname\ekvd@set{#2}{\ekvd@err@not@new}}
-\def\ekvd@assert@not@new
- {\ifx\ekvd@ifnew\ekvd@assert@new\ekvd@err@no@prefix{new}\fi}
-\def\ekvd@assert@new@for@name#1%
- {%
- \ifx\ekvd@ifnew\ekvd@assert@new
- \ekv@fi@firstoftwo
- \fi
- \@secondoftwo
- {\ekv@ifdefined{#1}\ekvd@err@not@new}%
- \@firstofone
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@if@not@already@choice, \ekvd@if@not@already@choice@a,
-% \ekvd@if@not@already@choice@b
-% }
-% It is bad to use |also| on a key that already contains a |choice|, as both
-% choices would share the same valid values and thus lead to each callback being
-% used twice. The following is a rudimentary test against this.
-% \begin{macrocode}
-\protected\def\ekvd@if@not@already@choice#1%
- {%
- \expandafter\ekvd@if@not@already@choice@a
- \csname\ekv@name\ekvd@set{#1}\endcsname
- {}\ekvd@h@choice\ekvd@stop
- }
-\protected\def\ekvd@if@not@already@choice@a
- {%
- \expandafter\ekvd@if@not@already@choice@b
- }
-\long\protected\def\ekvd@if@not@already@choice@b#1\ekvd@h@choice#2\ekvd@stop
- {%
- \ekv@ifempty{#2}\@firstofone\@gobble
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@ifspace,\ekvd@ifspace@}
-% Yet another test which can be reduced to an if-empty, this time by gobbling
-% everything up to the first space.
-% \begin{macrocode}
-\long\def\ekvd@ifspace#1%
- {%
- \ekvd@ifspace@#1 \ekv@ifempty@B
- \ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo
- }
-\long\def\ekvd@ifspace@#1 % keep this space
- {%
- \ekv@ifempty@\ekv@ifempty@A
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Messages}
-%
-% Most messages of \expkvd\ are not expandable, since they only appear during
-% key-definition, which is not expandable anyway.
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@errm,\ekvd@err@missing@definition,\ekvd@err@missing@definition@msg,
-% \ekvd@err@missing@type,\ekvd@err@undefined@prefix,\ekvd@err@undefined@key,
-% \ekvd@err@no@prefix,\ekvd@err@no@prefix@msg,\ekvd@err@no@prefix@also,
-% \ekvd@err@add@val@on@noval,\ekvd@err@add@noval@on@val,
-% \ekvd@err@unsupported@arg,\ekvd@err@not@new
-% }
-% The non-expandable error messages are boring, so here they are:
-% \begin{macrocode}
-\protected\def\ekvd@errm#1{\errmessage{expkv-def Error: #1}}
-\protected\def\ekvd@err@missing@definition
- {\ekvd@errm{Missing definition for key `\ekvd@cur'}}
-\protected\def\ekvd@err@missing@definition@msg#1%
- {\ekvd@errm{Missing definition for key `\ekv@unexpanded{#1}'}}
-\protected\def\ekvd@err@missing@type
- {\ekvd@errm{Missing type prefix for key `\ekvd@cur'}}
-\protected\def\ekvd@err@undefined@prefix#1%
- {%
- \ekvd@errm
- {%
- Undefined prefix `\ekv@unexpanded{#1}' found while processing
- `\ekvd@cur'%
- }%
- }
-\protected\def\ekvd@err@undefined@key#1%
- {%
- \ekvd@errm
- {Undefined key `\ekv@unexpanded{#1}' found while processing `\ekvd@cur'}%
- }
-\protected\def\ekvd@err@undefined@noval#1%
- {%
- \ekvd@errm
- {%
- Undefined noval key `\unexpanded{#1}' found while processing
- `\ekvd@cur'%
- }%
- }
-\protected\def\ekvd@err@no@prefix#1%
- {\ekvd@errm{prefix `#1' not accepted in `\ekvd@cur'}}
-\protected\def\ekvd@err@no@prefix@msg#1#2%
- {\ekvd@errm{prefix `#2' not accepted in `\ekv@unexpanded{#1}'}}
-\protected\def\ekvd@err@no@prefix@also#1%
- {\ekvd@errm{`\ekvd@cur' not allowed with a `#1' key}}
-\protected\def\ekvd@err@add@val@on@noval
- {\ekvd@errm{`\ekvd@cur' not allowed with a NoVal key}}
-\protected\def\ekvd@err@add@noval@on@val
- {\ekvd@errm{`\ekvd@cur' not allowed with a value taking key}}
-\protected\def\ekvd@err@unsupported@arg\fi\@firstofone#1%
- {%
- \fi
- \ekvd@errm
- {%
- Existing key-macro has the unsupported argument string
- `\ekvd@extracted@args' for key `\ekvd@cur'%
- }%
- }
-\protected\def\ekvd@err@not@new
- {\ekvd@errm{The key for `\ekvd@cur' is already defined}}
-\protected\long\def\ekvd@err@misused@unknown
- {\ekvd@errm{Misuse of the unknown type found while processing `\ekvd@cur'}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvd@err@choice@invalid,\ekvd@err@choice@invalid@,\ekvd@choice@name,
-% \ekvd@unknown@choice@name
-% }
-% |\ekvd@err@choice@invalid| will have to use this mechanism to throw its
-% message. Also we have to retrieve the name parts of the choice in an easy way,
-% so we use parentheses of catcode 8 here, which should suffice in most cases to
-% allow for a correct separation.
-% \begin{macrocode}
-\def\ekvd@err@choice@invalid#1%
- {%
- \ekvd@err@choice@invalid@#1%
- }
-\begingroup
-\catcode40=8
-\catcode41=8
-\@firstofone{\endgroup
-\def\ekvd@choice@name#1#2#3%
- {%
- ekvd#1(#2)\detokenize{#3}%
- }
-\def\ekvd@unknown@choice@name#1#2%
- {%
- ekvd:u:#1(#2)%
- }
-\def\ekvd@err@choice@invalid@ ekvd#1(#2)\detokenize#3%
- {%
- \ekv@ifdefined{\ekvd@unknown@choice@name{#1}{#2}}%
- {\csname\ekvd@unknown@choice@name{#1}{#2}\endcsname{#3}}%
- {\ekvd@err{invalid choice `#3' for `#2' in set `#1'}}%
- }
-}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvd@err}
-% The expandable error messages use |\ekvd@err|, which is just like |\ekv@err|
-% from \expkv. It uses a runaway argument to start the error message.
-% \begin{macrocode}
-\ekv@exparg{\long\def\ekvd@err#1}{\ekverr{expkv-def}{#1}}
-% \end{macrocode}
-% \end{macro}
-%
-% Now everything that's left is to reset the category code of |@|.
-% \begin{macrocode}
-\catcode`\@=\ekvd@tmp
-% \end{macrocode}
-%
-% \gobbledocstriptag
-%</tex>
-%^^A=<<
-%
-%^^A=<<
-%
-% \end{implementation}^^A=<<
-%
-% \clearpage
-% \PrintIndex
-%
-\endinput
-%
-^^A vim: ft=tex fdm=marker fmr=>>=,=<<
diff --git a/macros/generic/expkv-def/expkv-def.pdf b/macros/generic/expkv-def/expkv-def.pdf
deleted file mode 100644
index ea5678d280..0000000000
--- a/macros/generic/expkv-def/expkv-def.pdf
+++ /dev/null
Binary files differ
diff --git a/macros/generic/expkv-opt/README.md b/macros/generic/expkv-opt/README.md
deleted file mode 100644
index 447c4a87da..0000000000
--- a/macros/generic/expkv-opt/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
--------------------------------------------------------------------------------
-# expkv-opt -- parse class and package options with expkv
-
-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
-
-Hosted at https://github.com/Skillmon/tex_expkv-opt
-
--------------------------------------------------------------------------------
-
-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 package allows to parse key=val options for LaTeX classes and packages
-using [`expkv`](https://github.com/Skillmon/tex_expkv). It handles global and
-local options completely separately. The only required package is `expkv`.
diff --git a/macros/generic/expkv-opt/expkv-opt.dtx b/macros/generic/expkv-opt/expkv-opt.dtx
deleted file mode 100644
index 22a9a9b0c3..0000000000
--- a/macros/generic/expkv-opt/expkv-opt.dtx
+++ /dev/null
@@ -1,1012 +0,0 @@
-% \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.sty}{\from{expkv-opt.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>}{\key}{4}{<set>}{\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}}
-\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,\@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}
- \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}
-%</driver>^^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.
-%
-% 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.
-%
-% 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 processed
-% in any way) 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}
-% 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{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}\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.
-% 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.\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}
-% 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>
-%
-% 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.2}
-\newcommand*\ekvoDate{2021-04-04}
-% \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. 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}
-\protected\def\ekvo@do@unusedoptionlist#1%
- {%
- \let\ekvo@unpreparedCurrentOption\CurrentOption
- \edef\CurrentOption
- {\expandafter\ekvo@prepare@unusedoption\CurrentOption=\ekv@mark}%
- #1\@unusedoptionlist
- \let\CurrentOption\ekvo@unpreparedCurrentOption
- }
-\def\ekvo@prepare@unusedoption{\ekvo@prepare@unusedoption@a\@empty}
-\def\ekvo@prepare@unusedoption@a#1%
- {%
- \long\def\ekvo@prepare@unusedoption@a##1=##2\ekv@mark
- {%
- \ekvo@prepare@unusedoption@b##1\ekv@stop
- \ekv@mark\ekvo@prepare@unusedoption@b
- #1\ekv@mark\ekvo@prepare@unusedoption@c
- }%
- }
-\ekvo@prepare@unusedoption@a{ }
-\long\def\ekvo@prepare@unusedoption@b#1 #2\ekv@mark#3{#3#1#2\ekv@mark#3}
-\long\def\ekvo@prepare@unusedoption@c
- #1\ekv@stop
- \ekv@mark\ekvo@prepare@unusedoption@b\ekv@mark\ekvo@prepare@unusedoption@c
- {\unexpanded\expandafter{#1}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekvo@set@handlers@local,\ekvo@set@handlers@global,
-% \ekvo@set@handlers@list
-% }
-% These macros are boring. They just set up the handlers to respect the rules
-% documented earlier.
-% \begin{macrocode}
-\protected\def\ekvo@set@handlers@local
- {%
- \ekvo@if@need@handlers
- {%
- \ifx\@currext\@clsextension
- \ifx\@classoptionslist\relax
- \let\ekvo@handle@undefined@k\@gobble
- \let\ekvo@handle@undefined@kv\@gobbletwo
- \else
- \expandafter
- \ifx
- \csname @raw@opt@\@currname.\@currext\endcsname
- \@raw@classoptionslist
- \let\ekvo@handle@undefined@k\ekvo@addto@unused@one
- \let\ekvo@handle@undefined@kv\ekvo@addto@unused@two
- \else
- \let\ekvo@handle@undefined@k\@gobble
- \let\ekvo@handle@undefined@kv\@gobbletwo
- \fi
- \fi
- \else
- \let\ekvo@handle@undefined@k\ekvo@handle@undefined@k@pkg
- \let\ekvo@handle@undefined@kv\ekvo@handle@undefined@kv@pkg
- \fi
- }%
- }
-\protected\def\ekvo@set@handlers@global
- {%
- \unless\ifx\@unusedoptionlist\@empty
- \let\ekvo@handle@defined@k\ekvo@rmfrom@unused@one
- \let\ekvo@handle@defined@kv\ekvo@rmfrom@unused@two
- \fi
- \ekvo@if@need@handlers
- {%
- \let\ekvo@handle@undefined@k\@gobble
- \let\ekvo@handle@undefined@kv\@gobbletwo
- }%
- }
-\protected\def\ekvo@set@handlers@list
- {%
- \ekvo@if@need@handlers
- {%
- \let\ekvo@handle@undefined@k\@gobble
- \let\ekvo@handle@undefined@kv\@gobbletwo
- }%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvo@if@need@handlers,\ekvo@dont@need@handlers}
-% If the user specifies handlers this macro will be let to
-% |\ekvo@dont@need@handlers|, which will act like |\@gobble| and also let it
-% to |\@firstofone| afterwards.
-% \begin{macrocode}
-\let\ekvo@if@need@handlers\@firstofone
-\protected\long\def\ekvo@dont@need@handlers#1%
- {%
- \let\ekvo@if@need@handlers\@firstofone
- }%
-% \end{macrocode}
-% \end{macro}
-%
-% We have to set the default for the handlers of defined keys, because they
-% don't necessarily get defined before a list is parsed.
-% \begin{macrocode}
-\let\ekvo@handle@defined@k\@gobble
-\let\ekvo@handle@defined@kv\@gobbletwo
-% \end{macrocode}
-%
-%
-% \subsection{Processing list elements}
-%
-% \begin{macro}[internal]{\ekvo@process@common}
-% All the key processing frontend macros use the same basic structure. |#1|
-% will be a simple test, deciding whether the list will really be parsed or
-% not, |#3| will be the \set, and |#2| will be the individual code of the
-% frontend macro which should be executed if both the test in |#1| is true and
-% the \set\ is defined.
-% \begin{macrocode}
-\protected\def\ekvo@process@common#1#2#3%
- {%
- #1{\ekvo@do@with@set{#3}{#2}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvo@process@list}
-% This macro only expands the list holding macro and forwards it to the
-% loop macro.
-% \begin{macrocode}
-\protected\def\ekvo@process@list#1%
- {%
- \expandafter\ekvo@CurrentOption@loop\expandafter{#1}\ekvo@parse
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekvo@parse}
-% 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{@raw@opt@\@currname.\@currext}\@firstofone\@gobble}%
- {%
- \ekvo@set@handlers@local
- \expandafter
- \ekvo@process@list\csname @raw@opt@\@currname.\@currext\endcsname
- \AtEndOfPackage{\let\@unprocessedoptions\relax}%
- }%
- }
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}{\ekvoProcessGlobalOptions}
-% \begin{macrocode}
-\protected\def\ekvoProcessGlobalOptions
- {%
- \ekvo@process@common{\ekvo@ifx@F\@classoptionslist\relax}%
- {%
- \ekvo@set@handlers@global
- \ekvo@process@list\@raw@classoptionslist
- \let\ekvo@handle@defined@k\@gobble
- \let\ekvo@handle@defined@kv\@gobbletwo
- }%
- }
-% \end{macrocode}
-% \end{macro}
-% \begin{macro}{\ekvoProcessUnusedGlobalOptions}
-% \begin{macrocode}
-\protected\def\ekvoProcessUnusedGlobalOptions#1%
- {%
- \PackageWarning{expkv-opt}%
- {This macro no longer works because of changes in the LaTeX2e kernel.}%
- }
-% \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
- {\@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
- \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
-%</pkg>
-%
-% \end{implementation}^^A=<<
-%
-% \clearpage
-% \PrintIndex
-%
-% \Finale
-\endinput
-%
-^^A vim: ft=tex fdm=marker fmr=>>=,=<<
diff --git a/macros/generic/expkv-opt/expkv-opt.pdf b/macros/generic/expkv-opt/expkv-opt.pdf
deleted file mode 100644
index 5ecded074a..0000000000
--- a/macros/generic/expkv-opt/expkv-opt.pdf
+++ /dev/null
Binary files differ
diff --git a/macros/generic/expkv/README.md b/macros/generic/expkv/README.md
deleted file mode 100644
index ccfa3194b3..0000000000
--- a/macros/generic/expkv/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
--------------------------------------------------------------------------------
-# expkv -- an expandable key=val implementation
-
-Version 2021-09-20 v1.9a
-
-Released under the LaTeX Project Public License v1.3c or later
-See http://www.latex-project.org/lppl.txt
-
-Hosted at https://github.com/Skillmon/tex_expkv
-
--------------------------------------------------------------------------------
-
-Copyright (C) 2020-2021 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 provides an expandable key=val implementation that is somewhat fast, but
-not the fastest key=val implementation available. It is generic code and
-completely self-contained. There is a LaTeX package `expkv.sty` included to play
-nice on LaTeX's package loading system, but that package is not needed and does
-not provide more functionality than the generic code in `expkv.tex`.
-
-A key-defining interface that is not as rudimentary as the macros provided in
-this package is contained in expkv-def:
-https://github.com/Skillmon/tex_expkv-def
diff --git a/macros/generic/expkv/expkv.dtx b/macros/generic/expkv/expkv.dtx
deleted file mode 100644
index 8651ad97a3..0000000000
--- a/macros/generic/expkv/expkv.dtx
+++ /dev/null
@@ -1,2980 +0,0 @@
-% \iffalse meta-comment
-%
-% File: expkv.dtx Copyright (C) 2020-2021 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 -- an expandable key=val implementation
-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-2021 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.dtx
-and the derived files expkv.pdf
- expkv.sty
- expkv.tex
- t-expkv.tex
-
-\endpreamble
-% stop docstrip adding \endinput
-\postamble
-\endpostamble
-\generate{\file{expkv.sty}{\from{expkv.dtx}{pkg}}}
-\generate{\file{expkv.tex}{\from{expkv.dtx}{tex}}}
-\generate{\file{t-expkv.tex}{\from{expkv.dtx}{ctx}}}
-\ifx\fmtname\nameofplainTeX
- \expandafter\endbatchfile
-\else
- \expandafter\endgroup
-\fi
-%
-\IfFileExists{expkv.tex}{\input{expkv.tex}}{}
-\ProvidesFile{expkv.dtx}
- [\csname ekvDate\endcsname\ an expandable key=val implementation]
-\PassOptionsToPackage{full}{textcomp}
-\documentclass{l3doc}
-\RequirePackage[oldstylenums,nott]{kpfonts}
-\input{glyphtounicode}
-\pdfgentounicode=1
-\RequirePackage{xfp} ^^A required for an example
-\RequirePackage{listings}
-\RequirePackage{booktabs}
-\RequirePackage{array}
-\RequirePackage{collcell}
-\RequirePackage{siunitx}
-\DeclareSIUnit\ops{ops}
-\RequirePackage{xcolor}
-\RequirePackage{caption}
-\RequirePackage{microtype}
-\RequirePackage{accsupp}
-\RequirePackage{enumitem}
-\RequirePackage{tcolorbox}
-\newtcolorbox{exresult}[2][]
- {colback=expkvgrey!10!white,colframe=expkvgrey,fontupper=\small,width={#2},#1}
-\newtcbox\exres[1][]
- {
- colback=expkvgrey!10!white
- ,colframe=expkvgrey
- ,size=small
- ,nobeforeafter
- ,tcbox raise base
- ,fontupper=\small
- ,#1
- }
-\def\mylstwd{.55em}
-\lstdefinelanguage{expkv}[primitive]{TeX}
- {
- ,moretexcs=[4]^^A e-TeX
- {
- expanded,
- numexpr,
- protected,
- }
- ,moretexcs=[5]^^A plain/LaTeX/ConTeXt
- {
- approx,
- begin,
- empty,
- item,
- LaTeX,
- makeatletter,makeatother,
- newcommand,newdimen,
- RequirePackage,
- rule,
- TeX,
- textit,texttt,
- usepackage,
- usemodule,
- }
- ,moretexcs=[6]^^A used packages
- {
- ^^A xfp
- fpeval,
- ^^A keyval
- setkeys,
- ^^A yax
- defactiveparameter,storevalue,setparameterlist
- }
- ,moretexcs=[2]^^A expkv macros
- {
- ekvdef,ekvdefNoVal,^^A
- ekvlet,ekvletNoVal,ekvletkv,ekvletkvNoVal,^^A
- ekvdefunknown,ekvdefunknownNoVal,^^A
- ekvredirectunknown,ekvredirectunknownNoVal,^^A
- ekvset,ekvsetSneaked,^^A
- ekvsetdef,ekvsetSneakeddef,ekvsetdefSneaked,^^A
- ekvparse,^^A
- ekvVersion,ekvDate,^^A
- ekvifdefined,ekvifdefinedNoVal,ekvifdefinedset,^^A
- ekvbreak,ekvbreakPreSneak,ekvbreakPostSneak,^^A
- ekvsneak,ekvsneakPre,^^A
- ekvchangeset,^^A
- ekvoptarg,ekvoptargTF,^^A
- ekverr
- }
- ,moretexcs=[3]^^A expkv-pkg macros
- {
- ^^A expkv-cs
- ekvcSecondaryKeys,ekvcSplitAndForward,
- ^^A expkv-def
- ekvdefinekeys
- }
- }
-\colorlet{codeparam}{cyan!65!black}
-\lstset
- {
- ,language=expkv
- ,flexiblecolumns=false
- ,basewidth=\mylstwd
- ,gobble=2
- ,basicstyle=\fontfamily{jkp}\itshape
- ,texcsstyle=*[1]{\bfseries\color{expkvgrey}} ^^A primitives
- ,texcsstyle=*[2]{\bfseries\color{expkvred}} ^^A expkv
- ,texcsstyle=*[3]{\color{expkvred}} ^^A expkv-pkg
- ,texcsstyle=*[4]{\bfseries\color{expkvgrey}} ^^A e-TeX
- ,texcsstyle=*[5]{\bfseries\color{expkvgrey}} ^^A plain/LaTeX macros
- ,texcsstyle=*[6]{} ^^A macros of other packages
- ,commentstyle=\color[gray]{0.4}
- ,literate=
- {\{} {{\CodeUpBf\{}}{1}
- {\}} {{\CodeUpBf\}}}{1}
- {$} {{\CodeUpBf\$}}{1}
- {[} {{\CodeUp[}}{1}
- {]} {{\CodeUp]}}{1}
- {(} {{\CodeUp(}}{1}
- {)} {{\CodeUp)}}{1}
- {*} {{$*$}}{1}
- {1} {{\CodeUp{1}}}{1}
- {2} {{\CodeUp{2}}}{1}
- {3} {{\CodeUp{3}}}{1}
- {4} {{\CodeUp{4}}}{1}
- {5} {{\CodeUp{5}}}{1}
- {6} {{\CodeUp{6}}}{1}
- {7} {{\CodeUp{7}}}{1}
- {8} {{\CodeUp{8}}}{1}
- {9} {{\CodeUp{9}}}{1}
- {0} {{\CodeUp{0}}}{1}
- {##} {{\CodeColored{codeparam}{1}{\#}}}{1}
- {##1}{{\CodeColored{codeparam}{2}{\#1}}}{2}
- {##2}{{\CodeColored{codeparam}{2}{\#2}}}{2}
- {##3}{{\CodeColored{codeparam}{2}{\#3}}}{2}
- {##4}{{\CodeColored{codeparam}{2}{\#4}}}{2}
- {##5}{{\CodeColored{codeparam}{2}{\#5}}}{2}
- {##6}{{\CodeColored{codeparam}{2}{\#6}}}{2}
- {##7}{{\CodeColored{codeparam}{2}{\#7}}}{2}
- {##8}{{\CodeColored{codeparam}{2}{\#8}}}{2}
- {##9}{{\CodeColored{codeparam}{2}{\#9}}}{2}
- {<key>}{{$\langle$}key{$\rangle$}}{5}
- {<set>}{{$\langle$}set{$\rangle$}}{5}
- {<set1>}{{$\langle$}set1{$\rangle$}}{6}
- {<set2>}{{$\langle$}set2{$\rangle$}}{6}
- ^^A,literate=*{<key>}{\key}{4}{<set>}{\set}{4}
- }
-\newcommand*\CodeColored[3]{\textcolor{#1}{\makebox[\dimexpr\mylstwd*#2]{#3}}}
-\newcommand*\CodeUpBf[1]{\makebox[\mylstwd]{\textup{\textbf{#1}}}}
-\newcommand*\CodeUp[1]{\makebox[\mylstwd]{\textup{#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*\example{\par\smallskip\noindent\textit{Example:} \ignorespaces}
-\newcommand*\expFormat
- {^^A
- {^^A
- \rmfamily
- \bfseries
- {\color{expkvgrey}e\kern-.05em x\kern-.05em}^^A
- \lower.493ex\hbox{{\color{expkvgrey}P}}^^A
- }^^A
- }
-\newcommand*\kvstyle
- {^^A
- \normalfont\rmfamily\bfseries\color{expkvred}^^A
- }
-\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}}
-\ExplSyntaxOn
-\newcommand*\pkglogo[1]
- {
- \texorpdfstring
- {
- \mbox
- {
- \BeginAccSupp{ActualText=#1}
- \rmfamily
- \str_case:nn {#1}
- {
- {yax}
- {
- Y\kern-.1em
- \raise.15em\hbox{\scshape a}
- \kern-.1em \lower.15em\hbox{X}%
- }
- }
- \EndAccSupp{}
- }
- }
- {#1}
- }
-\newcommand*\yax{\pkglogo{yax}}
-\ExplSyntaxOff
-\newcommand\kv{\meta{key}=\meta{value}}
-\newcommand\key{\meta{key}}
-\newcommand\val{\meta{value}}
-\newcommand\set{\meta{set}}
-\hypersetup{linkcolor=red!80!black,urlcolor=purple!80!black}
-\DoNotIndex{\directlua}
-\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,\detokenize,\meaning}
-\DoNotIndex{\lastnamedcs,\romannumeral,\z@}
-\DoNotIndex{\noexpand,\normalexpanded,\normalunexpanded}
-\DoNotIndex{\par,\protect}
-\DoNotIndex{\unprotect}
-\DoNotIndex{\writestatus}
-\DoNotIndex{\ifcsname}
-\DoNotIndex{\ifx}
-\DoNotIndex{\iffalse}
-\DoNotIndex{\ifnum}
-\DoNotIndex{\else}
-\DoNotIndex{\fi}
-\@gobble\fi ^^A ignoring \ifx etc., but only one \fi
-\@gobble\fi ^^A ignoring \ifx etc., but only one \fi
-\@gobble\fi ^^A ignoring \ifx etc., but only one \fi
-\@ifdefinable\gobbledocstriptag{\def\gobbledocstriptag#1>{}}
-\newcommand*\pmso[1] ^^A poor man's strike out
- {^^A
- \leavevmode
- \begingroup
- \sbox0{#1}^^A
- \rlap{\vrule height .6ex depth -.5ex width \wd0\relax}^^A
- \usebox0\relax
- \endgroup
- }
-\makeatother
-\begin{document}
- \title
- {^^A
- \texorpdfstring
- {^^A
- \huge\expkv
- \\[\medskipamount]
- \Large an {\expFormat}andable
- \meta{{\kvstyle k}\kern-.05em ey}=^^A
- \meta{{\kvstyle v}\kern-.05em alue}
- implementation^^A
- }{expkv - an expandable <key>=<value> implementation}^^A
- }
- \date{\ekvDate\space v\ekvVersion}
- \author{Jonathan P. Spratte\thanks{\protect\randomize{jspratte@yahoo.de}}}
- \DocInput{expkv.dtx}
-\end{document}
-%</driver>^^A=<<
-% \fi
-%
-% \maketitle
-% \renewcommand*\thefootnote{\arabic{footnote}}
-%
-% \begin{abstract}
-% \noindent\parfillskip=0pt
-% \expkv\ provides a small interface for \kv\ parsing. The parsing macro is
-% \emph{fully expandable}, the \meta{code} of your keys might be not. \expkv\ is
-% \emph{swift}, close to the fastest \kv\ implementation. However it is the
-% fastest which copes with active commas and equal signs and doesn't strip
-% braces accidentally.
-% \end{abstract}
-%
-% \tableofcontents
-%
-% \begin{documentation}^^A>>=
-%
-% \section{Documentation}
-%
-% \expkv\ provides an expandable \kv\ parser. The \kv\ pairs should be given as
-% a comma separated list and the separator between a \key\ and the associated
-% \val\ should be an equal sign. Both, the commas and the equal signs, might be
-% of category 12 (other) or 13 (active). To support this is necessary as for
-% example \pkg{babel} turns characters active for some languages, for instance
-% the equal sign is turned active for Turkish.
-%
-% \expkv\ is usable as generic code, as a \LaTeX\ package or as a \ConTeXt\
-% module. To use it, just use one of:
-% \begin{lstlisting}
-% \input expkv % plainTeX
-% \usepackage{expkv} % LaTeX
-% \usemodule[expkv] % ConTeXt
-% \end{lstlisting}
-% Both the \LaTeX\ package and the \ConTeXt\ module don't do more than
-% \file{expkv.tex}, except calling |\ProvidesPackage| and setting things up such
-% that \file{expkv.tex} will use |\ProvidesFile|, or printing some status
-% information. The \ConTeXt\ support is not thoroughly tested, though (since I
-% don't use \ConTeXt\ myself I don't know if there are additional pitfalls I
-% wasn't aware of).
-%
-% In the \expkv\ family are other packages contained which provide additional
-% functionality. Those packages currently are:
-% \begin{description}[format=\expkvpkg]
-% \item[def]
-% a key-defining frontend for \expkv\ using a \kv\ syntax
-% \item[cs]
-% define expandable \kv\ macros using \expkv
-% \item[opt]
-% parse package and class options with \expkv
-% \end{description}
-% Note that while the package names are stylised with a vertical rule, their
-% names are all lower case with a hyphen (\emph{e.g.}, \file{expkv-def}).
-%
-% A list of concise comparisons to other \kv\ packages is contained in
-% \autoref{sec:cmp}.
-%
-% \subsection{Setting up Keys}\label{sec:define}
-% \expkv\ provides a rather simple approach to setting up keys, similar to
-% \pkg{keyval}. However there is an auxiliary package named \expkvd\ which
-% provides a more sophisticated interface, similar to well established packages
-% like \pkg{pgfkeys} or \pkg{l3keys}.
-%
-% Keys in \expkv\ (as in almost all other \kv\ implementations) belong to a
-% \emph{set} such that different sets can contain keys of the same name. Unlike
-% many other implementations \expkv\ doesn't provide means to set a default
-% value, instead we have keys that take values and keys that don't (the latter
-% are called |NoVal| keys by \expkv), but both can have the same name (on the
-% user level).
-%
-% The following macros are available to define new keys. Those macros containing
-% ``|def|'' in their name can be prefixed by anything allowed to prefix |\def|
-% (but \emph{don't} use |\outer|, keys defined with it won't ever be usable),
-% prefixes allowed for |\let| can prefix those with ``|let|'' in their name,
-% accordingly. Neither \set\ nor \key\ are allowed to be empty for new keys.
-% \set\ will be used as is inside of |\csname ...\endcsname| and \key\ will get
-% |\detokenize|d. Also \set\ should not contain an explicit |\par| token.
-%
-% \begin{function}{\ekvdef}
-% \begin{syntax}
-% \cs{ekvdef}\marg{set}\marg{key}\marg{code}
-% \end{syntax}
-% Defines a \key\ taking a value in a \set\ to expand to \meta{code}. In
-% \meta{code} you can use |#1| to refer to the given value.
-% \end{function}
-% \example Define |text| in |foo| to store the value inside |\foo@text|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \protected\long\ekvdef{foo}{text}{\def\foo@text{#1}}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvdefNoVal}
-% \begin{syntax}
-% \cs{ekvdefNoVal}\marg{set}\marg{key}\marg{code}
-% \end{syntax}
-% Defines a no value taking \key\ in a \set\ to expand to \meta{code}.
-% \end{function}
-% \example Define |bool| in |foo| to set |\iffoo@bool| to |true|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \protected\ekvdefNoVal{foo}{bool}{\foo@booltrue}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvlet}
-% \begin{syntax}
-% \cs{ekvlet}\marg{set}\marg{key}\meta{cs}
-% \end{syntax}
-% Let the value taking \key\ in \set\ to \meta{cs}, there are no checks on
-% \meta{cs} enforced, but the code should expect the value as a single braced
-% argument directly following it.
-% \end{function}
-% \example Let |cmd| in |foo| do the same as |\foo@cmd|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvlet{foo}{cmd}\foo@cmd
-% \end{lstlisting}
-%
-% \begin{function}{\ekvletNoVal}
-% \begin{syntax}
-% \cs{ekvletNoVal}\marg{set}\marg{key}\meta{cs}
-% \end{syntax}
-% Let the no value taking \key\ in \set\ to \meta{cs}, it is not checked
-% whether \meta{cs} exists or that it takes no parameter.
-% \end{function}
-% \example See above.
-%
-% \begin{function}{\ekvletkv}
-% \begin{syntax}
-% \cs{ekvletkv}\marg{set}\marg{key}\marg{set2}\marg{key2}
-% \end{syntax}
-% Let the \key\ in \set\ to \meta{key2} in \meta{set2}, it is not checked
-% whether that second key exists (but take a look at
-% \cs[no-index]{ekvifdefined}).
-% \end{function}
-% \example Let |B| in |bar| be an alias for |A| in |foo|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvletkv{bar}{B}{foo}{A}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvletkvNoVal}
-% \begin{syntax}
-% \cs{ekvletkvNoVal}\marg{set}\marg{key}\marg{set2}\marg{key2}
-% \end{syntax}
-% Let the \key\ in \set\ to \meta{key2} in \meta{set2}, it is not checked
-% whether that second key exists (but take a look at
-% \cs[no-index]{ekvifdefinedNoVal}).
-% \end{function}
-% \example See above.
-%
-% \begin{function}{\ekvdefunknown}
-% \begin{syntax}
-% \cs{ekvdefunknown}\marg{set}\marg{code}
-% \end{syntax}
-% By default an error will be thrown if an unknown \key\ is encountered. With
-% this macro you can define \meta{code} that will be executed for a given
-% \set\ when an unknown \key\ with a \val\ was encountered instead of throwing
-% an error. You can refer to the given \val\ with |#1| and to the unknown
-% \key's name with |#2| in \meta{code}.\footnotemark{}
-% |\ekvdefunknown| and |\ekvredirectunknown| are mutually exclusive,
-% you can't use both.
-% \end{function}
-% \footnotetext{That order is correct, this way the code is faster.}
-% \example Also search |bar| for undefined keys of set |foo|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \long\ekvdefunknown{foo}{\ekvset{bar}{#2={#1}}}
-% \end{lstlisting}
-% This example differs from using |\ekvredirectunknown{foo}{bar}| (see below) in
-% that also the unknown-key handler of the |bar| set will be triggered, error
-% messages for undefined keys will look different, and this is slower than using
-% |\ekvredirectunknown|.
-%
-% \begin{function}{\ekvdefunknownNoVal}
-% \begin{syntax}
-% \cs{ekvdefunknownNoVal}\marg{set}\marg{code}
-% \end{syntax}
-% As already explained for \cs[no-index]{ekvdefunknown}, \expkv\ would throw
-% an error when encountering an unknown \key. With this you can instead let it
-% execute \meta{code} if an unknown |NoVal| \key\ was encountered. You can
-% refer to the given \key\ with |#1| in \meta{code}.
-% |\ekvdefunknownNoVal| and |\ekvredirectunknownNoVal| are mutually exclusive,
-% you can't use both.
-% \end{function}
-% \example Also search |bar| for undefined keys of set |foo|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvdefunknownNoVal{foo}{\ekvset{bar}{#1}}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvredirectunknown}
-% \begin{syntax}
-% \cs{ekvredirectunknown}\marg{set}\marg{set-list}
-% \end{syntax}
-% This is a short cut to set up a special |\ekvdefunknown| for \set\ that will
-% check each set in the comma separated \meta{set-list} for the unknown \key.
-% You can't use prefixes (so no |\long| or |\protected|) with this macro, the
-% resulting unknown-key handler will always be |\long|. The first set in the
-% \meta{set-list} has highest priority. Once the \key\ is found the remaining
-% sets are discarded, if the \key\ isn't found in any set an error will be
-% thrown eventually. Note that the error messages are affected by the use of
-% this macro, in particular, it isn't checked whether a |NoVal| key of the
-% same name is defined in order to throw an |unwanted value| error.
-% |\ekvdefunknown| and |\ekvredirectunknown| are mutually exclusive,
-% you can't use both.
-% \end{function}
-% \example For every key not defined in the set |foo| also search the sets |bar|
-% and |baz|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvredirectunknown{foo}{bar, baz}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvredirectunknownNoVal}
-% \begin{syntax}
-% \cs{ekvredirectunknownNoVal}\marg{set}\marg{set-list}
-% \end{syntax}
-% This behaves just like |\ekvredirectunknown| and does the same but for the
-% |NoVal| keys. Again no prefixes are supported. Note that the error messages
-% are affected by the use of this macro, in particular, it isn't checked
-% whether a normal key of the same name is defined in order to throw a
-% |missing value| error.
-% |\ekvdefunknownNoVal| and |\ekvredirectunknownNoVal| are mutually exclusive,
-% you can't use both.
-% \end{function}
-% \example See above.
-%
-% \subsection{Parsing Keys}
-%
-% \begin{function}{\ekvset}
-% \begin{syntax}
-% \cs{ekvset}\marg{set}\{\kv,\ldots\}
-% \end{syntax}
-% Splits \kv\ pairs on commas. From both \key\ and \val\ up to one space is
-% stripped from both ends, if then only a braced group remains the braces are
-% stripped as well. So |\ekvset{foo}{bar=baz}| and
-% |\ekvset{foo}{ {bar}= {baz} }| will both do
-% \texttt{\cs[no-index]{\meta{foobarcode}}\{baz\}}, so you can hide commas,
-% equal signs and spaces at the ends of either \key\ or \val\ by putting
-% braces around them. If you omit the equal sign the code of the key created
-% with the |NoVal| variants described in \autoref{sec:define} will be
-% executed. If \kv\ contains more than a single unhidden equal sign, it will
-% be split at the first one and the others are considered part of the value.
-% |\ekvset| should be nestable.
-%
-% |\ekvset| is currently \emph{not} alignment safe.\footnotemark\ As a result,
-% key names and values that contain an |&| must be wrapped in braces when
-% |\ekvset| is used inside an alignment (like \LaTeXe's |tabular| environment)
-% or you have to create a wrapper that ensures an alignment safe context.
-% \end{function}
-% \footnotetext{This might change in the future, I've not decided yet.}
-% \example Parse |key=arg, key| in the set |foo|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvset{foo}{key=arg, key}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvsetSneaked}
-% \begin{syntax}
-% \cs{ekvsetSneaked}\marg{set}\marg{sneak}\{\kv,\ldots\}
-% \end{syntax}
-% Just like \cs[no-index]{ekvset}, this macro parses the \kv\ pairs within the
-% given \set. But \cs[no-index]{ekvsetSneaked} will behave as if
-% \cs[no-index]{ekvsneak} has been called with \meta{sneak} as its argument as
-% the first action.
-% \end{function}
-% \example Parse |key=arg, key| in the set |foo| with |\afterwards| sneaked out:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvsetSneaked{foo}{\afterwards}{key=arg, key}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvsetdef}
-% \begin{syntax}
-% \cs{ekvsetdef}\meta{cs}\marg{set}
-% \end{syntax}
-% With this function you can define a shorthand macro \meta{cs} to parse keys
-% of a specified \set. It is always defined |\long|, but if you need to you
-% can also prefix it with |\global|. The resulting macro is faster than but
-% else equivalent to the idiomatic definition:\par
-% \texttt
-% {\string\long\string\def\meta{cs}\#1\{\string\ekvset\marg{set}\{\#1\}\}}
-% \end{function}
-% \example Define the macro |\foosetup| to parse keys in the set |foo| and use
-% it to parse |key=arg, key|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvsetdef\foosetup{foo}
-% \foosetup{key=arg, key}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvsetSneakeddef}
-% \begin{syntax}
-% \cs{ekvsetSneakeddef}\meta{cs}\marg{set}
-% \end{syntax}
-% Just like \cs[no-index]{ekvsetdef} this defines a shorthand macro \meta{cs},
-% but this macro will make it a shorthand for \cs[no-index]{ekvsetSneaked},
-% meaning that \meta{cs} will take two arguments, the first being stuff that
-% should be given to \cs[no-index]{ekvsneak} and the second the \kv\ list. The
-% resulting macro is faster than but else equivalent to the idiomatic
-% definition:\par
-% \texttt
-% {%
-% \string\long\string\def\meta{cs}\#1\#2\{^^A
-% \string\ekvsetSneaked\marg{set}\{\#1\}\{\#2\}\}^^A
-% }
-% \end{function}
-% \example Define the macro |\foothings| to parse keys in the set |foo| and
-% accept a sneaked argument, then use it to parse |key=arg, key| and sneak
-% |\afterwards|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvsetSneakeddef\foothings{foo}
-% \foothings{\afterwards}{key=arg, key}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvsetdefSneaked}
-% \begin{syntax}
-% \cs{ekvsetdefSneaked}\meta{cs}\marg{set}\marg{sneaked}
-% \end{syntax}
-% And this one behaves like \cs[no-index]{ekvsetSneakeddef} but with a fixed
-% \meta{sneaked} argument. So the resulting macro is faster than but else
-% equivalent to the idiomatic definition:\par
-% \texttt
-% {%
-% \string\long\string\def\meta{cs}\#1\{^^A
-% \string\ekvsetSneaked\marg{set}\marg{sneaked}\{\#1\}\}^^A
-% }
-% \end{function}
-% \example Define the macro |\barthing| to parse keys in the set |bar| and
-% always execute |\afterwards| afterwards, then use it to parse |key=arg, key|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvsetdefSneaked\barthing{bar}{\afterwards}
-% \barthing{key=arg, key}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvparse}
-% \begin{syntax}
-% \cs{ekvparse}\marg{code1}\marg{code2}\{\kv,\ldots\}
-% \end{syntax}
-% This macro parses the \kv\ pairs and provides those list elements which are
-% only keys as an argument to \meta{code1}, and those which are a \kv\ pair
-% to \meta{code2} as two arguments. It is fully expandable as well and returns
-% each element of the parsed list in |\unexpanded|, which has no effect
-% outside of an |\expanded| or |\edef| context.
-% Also |\ekvparse| expands in exactly two steps of expansion.
-% You can use multiple tokens in \meta{code1} and \meta{code2} or just a
-% single control sequence name. In both cases the found \key\ and \val\ are
-% provided as a brace group following them.
-%
-% |\ekvparse| is alignment safe, meaning that you don't have to take any
-% precautions if it is used inside an alignment context (like \LaTeXe's
-% |tabular| environment) and any key or value can contain an |&|.
-%
-% |\ekvbreak|, |\ekvsneak|, and |\ekvchangeset| and their relatives don't work
-% in |\ekvparse|. It is analogue to \pkg{expl3}'s |\keyval_parse:NNn|, but
-% not with the same parsing rules -- |\keyval_parse:NNn| throws an error on
-% multiple equal signs per \kv\ pair and on empty \key\ names in a \kv\ pair,
-% both of which |\ekvparse| doesn't deal with.
-% \end{function}
-% \example
-% \begin{lstlisting}
-% \ekvparse{\handlekey{S}}{\handlekeyval{S}}{foo = bar, key, baz={zzz}}
-% \end{lstlisting}
-% would be equivalent to
-% \begin{lstlisting}
-% \handlekeyval{S}{foo}{bar}\handlekey{S}{key}\handlekeyval{S}{baz}{zzz}
-% \end{lstlisting}
-% and afterwards |\handlekey| and |\handlekeyval| would have to further handle
-% the \key. There are no macros like these two contained in \expkv, you have
-% to set them up yourself if you want to use |\ekvparse| (of course the names
-% might differ). If you need the results of |\ekvparse| as the argument for
-% another macro, you should use |\expanded|, or expand |\ekvparse| twice, as
-% only then the input stream will contain the output above:
-% \begin{lstlisting}
-% \expandafter\parse\expanded{\ekvparse\k\kv{foo = bar, key, baz={zzz}}}
-% \end{lstlisting}
-% or
-% \begin{lstlisting}
-% \expandafter\expandafter\expandafter
-% \parse\ekvparse\k\kv{foo = bar, key, baz={zzz}}
-% \end{lstlisting}
-% would both expand to
-% \begin{lstlisting}
-% \parse\kv{foo}{bar}\k{key}\kv{baz}{zzz}
-% \end{lstlisting}
-%
-% \subsection{Other Macros}
-%
-% \expkv\ provides some other macros which might be of interest.
-%
-% \begin{function}{\ekvVersion,\ekvDate}
-% These two macros store the version and date of the package.
-% \end{function}
-%
-% \begin{function}{\ekvifdefined,\ekvifdefinedNoVal}
-% \begin{syntax}
-% \cs{ekvifdefined}\marg{set}\marg{key}\marg{true}\marg{false}
-% \cs{ekvifdefinedNoVal}\marg{set}\marg{key}\marg{true}\marg{false}
-% \end{syntax}
-% These two macros test whether there is a \key\ in \set. It is false if
-% either a hash table entry doesn't exist for that key or its meaning is
-% |\relax|.
-% \end{function}
-% \example Check whether the key |special| is already defined in set |foo|, if
-% it isn't input a file that contains more key definitions:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvifdefined{foo}{special}{}{\input{foo.morekeys.tex}}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvifdefinedset}
-% \begin{syntax}
-% \cs{ekvifdefinedset}\marg{set}\marg{true}\marg{false}
-% \end{syntax}
-% This macro tests whether \set\ is defined (which it is if at least one key
-% was defined for it). If it is \meta{true} will be run, else \meta{false}.
-% \end{function}
-% \example Check whether the set |VeRyUnLiKeLy| is already defined, if so throw
-% an error, else do nothing:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvifdefinedset{VeRyUnLiKeLy}
-% {\errmessage{VeRyUnLiKeLy already defined}}{}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak}
-% \begin{syntax}
-% \cs{ekvbreak}\marg{after}
-% \end{syntax}
-% Gobbles the remainder of the current |\ekvset| macro and its argument list
-% and reinserts \meta{after}. So this can be used to break out of |\ekvset|.
-% The first variant will also gobble anything that has been sneaked out using
-% |\ekvsneak| or |\ekvsneakPre|, while |\ekvbreakPreSneak| will put
-% \meta{after} before anything that has been smuggled and |\ekvbreakPostSneak|
-% will put \meta{after} after the stuff that has been sneaked out.
-% \end{function}
-% \example Define a key |abort| that will stop key parsing inside the set |foo|
-% and execute |\foo@aborted|, or if it got a value |\foo@aborted@with|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvdefNoVal{foo}{abort}{\ekvbreak{\foo@aborted}}
-% \ekvdef{foo}{abort}{\ekvbreak{\foo@aborted@with{#1}}}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvsneak,\ekvsneakPre}
-% \begin{syntax}
-% \cs{ekvsneak}\marg{after}
-% \end{syntax}
-% Puts \meta{after} after the effects of |\ekvset|. The first variant will put
-% \meta{after} after any other tokens which might have been sneaked before,
-% while |\ekvsneakPre| will put \meta{after} before other smuggled stuff.
-% This reads and reinserts the remainder of the current |\ekvset| macro and
-% its argument list to do its job. After |\ekvset| has parsed the entire \kv\
-% list everything that has been |\ekvsneak|ed will be left in the input
-% stream. A small usage example is shown in \autoref{sec:sneakex}.
-% \end{function}
-% \example Define a key |secret| in the set |foo| that will sneak out
-% |\foo@secretly@sneaked|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvdefNoVal{foo}{secret}{\ekvsneak{\foo@secretly@sneaked}}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvchangeset}
-% \begin{syntax}
-% \cs{ekvchangeset}\marg{new-set}
-% \end{syntax}
-% Replaces the current set with \meta{new-set}, so for the rest of the current
-% |\ekvset| call, that call behaves as if it was called with
-% \texttt{\cs[no-index]{ekvset}\marg{new-set}}. It is comparable to using
-% \texttt{\meta{key}/.cd} in \pkg{pgfkeys}.
-% \end{function}
-% \example Define a key |cd| in set |foo| that will change to another set as
-% specified in the value, if the set is undefined it'll stop the parsing and
-% throw an error as defined in the macro |\foo@cd@error|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \ekvdef{foo}{cd}
-% {\ekvifdefinedset{#1}{\ekvchangeset{#1}}{\ekvbreak{\foo@cd@error}}}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvoptarg}
-% \begin{syntax}
-% \cs{ekvoptarg}\marg{next}\marg{default}
-% \end{syntax}
-% This macro will check for a following optional argument in brackets (|[]|)
-% expandably. After the optional argument there has to be a mandatory one. The
-% code in \meta{next} should expect two arguments (the processed optional
-% argument and the mandatory one). If there was an optional argument the
-% result will be \meta{next}\marg{optional}\meta{mandatory} (so the optional
-% argument will be wrapped in braces, the mandatory argument will be
-% untouched). If there was no optional argument the result will be
-% \meta{next}\marg{default}\marg{mandatory} (so the default will be used and
-% the mandatory argument will be wrapped in braces after being read once -- if
-% it was already wrapped it is effectively unchanged).
-% \end{function}
-% |\ekvoptarg| expands in exactly two steps, grabs all the arguments only at the
-% second expansion step, and is alignment safe. It has its limitations however.
-% It can't tell the difference between |[| and |{[}|, so it doesn't work if the
-% mandatory argument is a single bracket. Also if the optional argument should
-% contain a nested closing bracket, the optional argument has to use nested
-% braces like so: |[{arg]ument}]|.
-% \example Say we have a macro that should take an optional argument defaulting
-% to 1:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \newcommand\foo{\ekvoptarg\@foo{1}}
-% \newcommand\@foo[2]{Mandatory: #2\par Optional: #1}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvoptargTF}
-% \begin{syntax}
-% \cs{ekvoptargTF}\marg{true}\marg{false}
-% \end{syntax}
-% This macro is similar to |\ekvoptarg|, but will result in
-% \meta{true}\marg{optional}\meta{mandatory} or \meta{false}\marg{mandatory}
-% instead of placing a default value.
-% \end{function}
-% |\ekvoptargTF| expands in exactly two steps, grabs all the arguments only at
-% the second expansion step, and is alignment safe. It has the same limitations
-% as |\ekvoptarg|.
-% \example Say we have a macro that should behave differently depending on
-% whether there was an optional argument or not. This could be done with:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \newcommand\foo{\ekvoptargTF\foo@a\foo@b}
-% \newcommand\foo@a[2]{Mandatory: #2\par Optional: #1}
-% \newcommand\foo@b[1]{Mandatory: #1\par No optional.}
-% \end{lstlisting}
-%
-% \begin{function}{\ekvcsvloop}
-% \begin{syntax}
-% \cs{ekvcsvloop}\marg{code}\marg{csv-list}
-% \end{syntax}
-% This loops over the comma separated items in \meta{csv-list} and, after
-% stripping spaces from either end of \meta{item} and removing at most one set
-% of outer braces, leaves
-% \texttt
-% {^^A
-% \cs[no-index]{unexpanded}\hskip0pt
-% \{\hskip0pt
-% \meta{code}\hskip0pt
-% \marg{item}\hskip0pt
-% \}^^A
-% }
-% for each list item in the input stream. Blank elements are ignored (if you
-% need a blank element it should be given as |{}|). It supports both active
-% commas and commas of category other. You could consider it as a watered down
-% version of |\ekvparse|. However it is not alignment safe, which you could
-% achieve by nesting it in |\expanded| (since the braces around the argument
-% of |\expanded| will hide |&|s from \TeX's alignment parsing).
-% \end{function}
-% \example The following splits a comma separated list and prints it in a
-% typewriter font with parentheses around each element.\\
-% \begin{minipage}{.75\linewidth}
-% \begin{lstlisting}
-% \newcommand*\myprocessor[1]{\texttt{(#1)}}
-% \ekvcsvloop\myprocessor{abc,def,ghi}\par
-% \ekvcsvloop\myprocessor{1,,2,,3,,4}\par
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \newcommand*\myprocessor[1]{\texttt{(#1)}}
-% \ekvcsvloop\myprocessor{abc,def,ghi}\par
-% \ekvcsvloop\myprocessor{1,,2,,3,,4}\par
-% \end{exresult}
-%
-% \begin{function}{\ekverr}
-% \begin{syntax}
-% \cs{ekverr}\marg{package}\marg{message}
-% \end{syntax}
-% This macro will throw an error fully expandably.\footnotemark\ The error
-% length is limited to a total length of 69~characters, and since ten
-% characters will be added for the formatting (\verb*|! | and
-% \verb*| Error: |) that leaves us with a total length for \meta{package} plus
-% \meta{message} of 59~characters. If the message gets longer \TeX\ will only
-% display the first 69~characters and append |\ETC.| to the end.
-%
-% Neither \meta{package} nor \meta{message} expand any further. Also
-% \meta{package} must not contain an explicit |\par| token or the token
-% |\thanks@jfbu|. No such restriction applies to \meta{message}.
-%
-% If |^^J| is set up as the |\newlinechar| (which is the case in \LaTeXe\ but
-% not in plain \TeX\ by default) you can use that to introduce line breaks in
-% your error message. However that doesn't change the message length limit.
-% \end{function}
-% \footnotetext{The used mechanism was to the best of my knowledge first
-% implemented by Jean-François Burnol.}
-% After your own error message some further text will be placed. The
-% formatting of that text will look good if |^^J| is the |\newlinechar|, else
-% not so much. That text will read:
-% \begin{verbatim}
-% ! Paragraph ended before \<an-expandable-macro>
-% completed due to above exception. If the error
-% summary is not comprehensible see the package
-% documentation.
-% I will try to recover now. If you're in inter-
-% active mode hit <return> at the ? prompt and I
-% continue hoping recovery was complete.
-% \end{verbatim}
-% Any clean up has to be done by you, |\ekverr| will expand to nothing after
-% throwing the error message.
-%
-% In \ConTeXt\ this macro works differently. While still being fully expandable,
-% it doesn't have the character count limitation and doesn't impose restrictions
-% on \meta{package}. It will not display the additional text and adding line
-% breaks is not possible.
-% \example Say we set up a small calculation which works with user input. In our
-% calculation we need a division, so have to watch out for division by zero. If
-% we detect such a case we throw an error and do the recovery by using the
-% biggest integer allowed in \TeX\ as the result.
-% \begin{lstlisting}
-% \newcommand*\mydivision[2]
-% {%
-% \the\numexpr
-% \ifnum\numexpr#2=0 % space here on purpose
-% \ekverr{my}{division by 0. Setting result to 2147483647.}%
-% 2147483647%
-% \else
-% (#1)/(#2)%
-% \fi
-% \relax
-% }
-% $(10+5)/(3-3)\approx\mydivision{10+5}{3-3}$
-% \end{lstlisting}
-% If that code gets executed the following will be the terminal output
-% \begin{verbatim}
-% Runaway argument?
-% ! my Error: division by 0. Setting result to 2147483647.
-% ! Paragraph ended before \<an-expandable-macro>
-% completed due to above exception. If the error
-% summary is not comprehensible see the package
-% documentation.
-% I will try to recover now. If you're in inter-
-% active mode hit <return> at the ? prompt and I
-% continue hoping recovery was complete.
-% <to be read again>
-% \par
-% l.15 $(10+5)/(3-3)\approx\mydivision{10+5}{3-3}
-% $
-% ?
-% \end{verbatim}
-% and the output would contain
-% \exres{$(10+5)/(3-3)\approx2147483647$}
-% if we continued the \TeX\ run at the prompt.
-%
-% \bigskip
-%
-% \begin{function}{\ekv@name,\ekv@name@set,\ekv@name@key}
-% \begin{syntax}
-% \cs{ekv@name}\marg{set}\marg{key}
-% \cs{ekv@name@set}\marg{set}
-% \cs{ekv@name@key}\marg{key}
-% \end{syntax}
-% The names of the macros that correspond to a key in a set are build with
-% these macros. The name is built from two blocks, one that is formatting the
-% \set\ name (|\ekv@name@set|) and one for formatting the \key\ name
-% (|\ekv@name@key|). To get the actual name the argument to |\ekv@name@key|
-% must be |\detokenize|d. Both blocks are put together (with the necessary
-% |\detokenize|) by |\ekv@name|.
-% For |NoVal| keys an additional |N| gets appended irrespective of these
-% macros' definition, so their name is
-% \texttt{\cs[no-index]{ekv@name}\marg{set}\marg{key}N}.\par
-% You can use these macros to implement additional functionality or access key
-% macros outside of \expkv, but \emph{don't} change them! \expkv\ relies on
-% their exact definitions internally.
-% \end{function}
-% \example Execute the callback of the |NoVal| key |key| in set |foo|:
-% \begin{lstlisting}[aboveskip=0pt,belowskip=0pt]
-% \csname\ekv@name{foo}{key}N\endcsname
-% \end{lstlisting}
-%
-% \subsection{Examples}
-%
-% \subsubsection{Standard Use-Case}
-%
-% Say we have a macro for which we want to create a \kv\ interface. The macro
-% has a parameter, which is stored in the dimension |\ourdim| having a default
-% value from its initialisation. Now we want to be able to change that dimension
-% with the |width| key to some specified value. For that we'd do
-% \begin{lstlisting}
-% \newdimen\ourdim
-% \ourdim=150pt
-% \protected\ekvdef{our}{width}{\ourdim=#1\relax}
-% \end{lstlisting}
-% as you can see, we use the set |our| here. We want the key to behave different
-% if no value is specified. In that case the key should not use its initial
-% value, but be smart and determine the available space from
-% \cs[no-index]{hsize}, so we also define
-% \begin{lstlisting}
-% \protected\ekvdefNoVal{our}{width}{\ourdim=.9\hsize}
-% \end{lstlisting}
-% Now we set up our macro to use this \kv\ interface
-% \begin{lstlisting}
-% \protected\def\ourmacro#1%
-% {\begingroup\ekvset{our}{#1}\the\ourdim\endgroup}
-% \end{lstlisting}
-% Finally we can use our macro like in the following\\
-% \begin{minipage}{.5\linewidth}
-% \begin{lstlisting}
-% \ourmacro{}\par
-% \ourmacro{width}\par
-% \ourmacro{width=5pt}\par
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.5\linewidth}
-% \newdimen\ourdim\ourdim=150pt
-% \protected\ekvdef{our}{width}{\ourdim=#1\relax}^^A
-% \protected\ekvdefNoVal{our}{width}{\ourdim=.9\hsize}^^A
-% \protected\def\ourmacro#1^^A
-% {\begingroup\ekvset{our}{#1}\the\ourdim\endgroup}^^A
-% \ourmacro{}\par
-% \ourmacro{width}\par
-% \ourmacro{width=5pt}\par
-% \end{exresult}
-%
-% \paragraph{The same keys using \protect\expkvd}
-% Using \expkvd\ we can set up the equivalent key using a \kv\ interface, after
-% the following we could use |\ourmacro| in the same way as above. \expkvd\ will
-% allocate and initialise |\ourdim| and define the |width| key |\protected| for
-% us, so the result will be exactly the same -- with the exception that the
-% default will use |\ourdim=.9\hsize\relax| instead.
-% \begin{lstlisting}
-% \input expkv-def % or \usepackage{expkv-def}
-% \ekvdefinekeys{our}
-% {
-% dimen width = \ourdim,
-% qdefault width = .9\hsize,
-% initial width = 150pt
-% }
-% \end{lstlisting}
-%
-% \subsubsection{A Macro to Draw Rules}
-%
-% Another small example could be a \kv\ driven |\rule| alternative, because I
-% keep forgetting the correct order of its arguments. First we define the keys
-% (and initialize the macros used to store the keys):
-% \begin{lstlisting}
-% \makeatletter
-% \newcommand*\myrule@ht{1ex}
-% \newcommand*\myrule@wd{0.1em}
-% \newcommand*\myrule@raise{\z@}
-% \protected\ekvdef{myrule}{ht}{\def\myrule@ht{#1}}
-% \protected\ekvdef{myrule}{wd}{\def\myrule@wd{#1}}
-% \protected\ekvdef{myrule}{raise}{\def\myrule@raise{#1}}
-% \protected\ekvdef{myrule}{lower}{\def\myrule@raise{-#1}}
-% \end{lstlisting}
-% Then we define a macro to change the defaults outside of |\myrule| and
-% |\myrule| itself:
-% \begin{lstlisting}
-% \ekvsetdef\myruleset{myrule}
-% \newcommand*\myrule[1][]
-% {\begingroup\myruleset{#1}\myrule@out\endgroup}
-% \end{lstlisting}
-% And finally the output:
-% \begin{lstlisting}
-% \newcommand*\myrule@out{\rule[\myrule@raise]\myrule@wd\myrule@ht}
-% \makeatother
-% \end{lstlisting}
-% And we can use it:\\
-% \begin{minipage}{.5\linewidth}
-% \begin{lstlisting}
-% a\myrule\par
-% a\myrule[ht=2ex,lower=.5ex]\par
-% \myruleset{wd=5pt}
-% a\myrule
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.5\linewidth}
-% \makeatletter
-% \newcommand*\myrule@ht{1ex}
-% \newcommand*\myrule@wd{0.1em}
-% \newcommand*\myrule@raise{\z@}
-% \protected\ekvdef{myrule}{ht}{\def\myrule@ht{#1}}
-% \protected\ekvdef{myrule}{wd}{\def\myrule@wd{#1}}
-% \protected\ekvdef{myrule}{raise}{\def\myrule@raise{#1}}
-% \protected\ekvdef{myrule}{lower}{\def\myrule@raise{-#1}}
-% \ekvsetdef\myruleset{myrule}
-% \newcommand*\myrule[1][]{\begingroup\myruleset{#1}\myrule@out\endgroup}
-% \newcommand*\myrule@out{\rule[\myrule@raise]\myrule@wd\myrule@ht}
-% \makeatother
-% a\myrule\par
-% a\myrule[ht=2ex,lower=.5ex]\par
-% \myruleset{wd=5pt}
-% a\myrule
-% \end{exresult}
-%
-%
-% \subsubsection{An Expandable \kv\ Macro Using \cs[no-index]{ekvsneak}}
-% \label{sec:sneakex}
-%
-% Let's set up an expandable macro, that uses a \kv\ interface. The problems
-% we'll face for this are:
-% \begin{enumerate}
-% \item ignoring duplicate keys
-% \item default values for keys which weren't used
-% \item providing the values as the correct argument to a macro (ordered)
-% \end{enumerate}
-%
-% First we need to decide which \kv\ parsing macro we want to do this with,
-% |\ekvset| or |\ekvparse|. For this example we also want to show the
-% usage of |\ekvsneak|, hence we'll choose |\ekvset|. And we'll have to use
-% |\ekvset| such that it builds a parsable list for our macro internals. To
-% gain back control after |\ekvset| is done we have to put an internal of our
-% macro at the start of that list, so we use an internal key that uses
-% |\ekvsneakPre| after any user input.
-%
-% To ignore duplicates will be easy if the value of the key used last will be
-% put first in the list, so the following will use |\ekvsneakPre| for the
-% user-level keys. If we wanted some key for which the first usage should be the
-% binding one we would use |\ekvsneak| instead for that key.
-%
-% Providing default values can be done in different ways, we'll use a simple
-% approach in which we'll just put the outcome of our keys if they were used
-% with default values before the parsing list terminator.
-%
-% Ordering the keys can be done simply by searching for a specific token for
-% each argument which acts like a flag, so our sneaked out values will include
-% specific tokens acting as markers.
-%
-% Now that we have answers for our technical problems, we have to decide what
-% our example macro should do. How about we define a macro that calculates the
-% sine of a number and rounds that to a specified precision? As a small extra
-% this macro should understand input in radian and degree and the used
-% trigonometric function should be selectable as well. For the hard part of this
-% task (expandably evaluating trigonometric functions) we'll use the \pkg{xfp}
-% package.
-%
-% First we set up our keys according to our earlier considerations and set up
-% the user facing macro |\sine|. The end marker of the parsing list will be a
-% |\sine@stop| token, which we don't need to define and we put our defaults
-% right before it. The user macro |\sine| uses |\ekvoptargTF| to check for the
-% optional argument short cutting to the final step if no optional argument was
-% found. This way we safe some time in this case, though we have to specify the
-% default values twice.
-%
-% \begin{lstlisting}
-% \RequirePackage{xfp}
-% \makeatletter
-% \ekvdef{expex}{f}{\ekvsneakPre{\f{#1}}}
-% \ekvdef{expex}{round}{\ekvsneakPre{\rnd{#1}}}
-% \ekvdefNoVal{expex}{degree}{\ekvsneakPre{\deg{d}}}
-% \ekvdefNoVal{expex}{radian}{\ekvsneakPre{\deg{}}}
-% \ekvdefNoVal{expex}{internal}{\ekvsneakPre{\sine@rnd}}
-% \newcommand*\sine{\ekvoptargTF\sine@args{\sine@final{sin}{d}{3}}}
-% \newcommand*\sine@args[2]
-% {\ekvset{expex}{#1,internal}\rnd{3}\deg{d}\f{sin}\sine@stop{#2}}
-% \end{lstlisting}
-%
-% Now we need to define some internal macros to extract the value of each key's
-% last usage (remember that this will be the group after the first special
-% flag-token). For that we use one delimited macro per key.
-% \begin{lstlisting}
-% \def\sine@rnd#1\rnd#2#3\sine@stop{\sine@deg#1#3\sine@stop{#2}}
-% \def\sine@deg#1\deg#2#3\sine@stop{\sine@f#1#3\sine@stop{#2}}
-% \def\sine@f#1\f#2#3\sine@stop{\sine@final{#2}}
-% \end{lstlisting}
-% After the macros |\sine@rnd|, |\sine@deg|, and |\sine@f| the macro
-% |\sine@final| will see
-% \texttt
-% {^^A
-% \cs[no-index]{sine@final}^^A
-% \marg{f}\marg{degree/radian}\marg{round}\marg{num}^^A
-% }.
-% Now |\sine@final| has to expandably deal with those arguments such that the
-% |\fpeval| macro of \pkg{xfp} gets the correct input. Luckily this is pretty
-% straight forward in this example. In |\fpeval| the trigonometric functions
-% have names such as |sin| or |cos| and the degree taking variants |sind| or
-% |cosd|. And since the |degree| key puts a |d| in |#2| and the |radian| key
-% leaves |#2| empty all we have to do to get the correct function name is stick
-% the two together.
-% \begin{lstlisting}
-% \newcommand*\sine@final[4]{\fpeval{round(#1#2(#4),#3)}}
-% \makeatother
-% \end{lstlisting}
-% Let's test our macro:\\
-% \begin{minipage}{.75\linewidth}
-% \begin{lstlisting}[gobble=4]
-% \sine{60}\par
-% \sine[round=10]{60}\par
-% \sine[f=cos,radian]{pi}\par
-% \edef\myval{\sine[f=tan]{1}}\texttt{\meaning\myval}
-% \end{lstlisting}
-% \end{minipage}^^A
-% \begin{exresult}[nobeforeafter,box align=center]{.25\linewidth}
-% \makeatletter
-% \ekvdef{expex}{f}{\ekvsneakPre{\f{#1}}}^^A
-% \ekvdef{expex}{round}{\ekvsneakPre{\rnd{#1}}}^^A
-% \ekvdefNoVal{expex}{degree}{\ekvsneakPre{\deg{d}}}^^A
-% \ekvdefNoVal{expex}{radian}{\ekvsneakPre{\deg{}}}^^A
-% \ekvdefNoVal{expex}{internal}{\ekvsneakPre{\sine@rnd}}^^A
-% \newcommand*\sine{\ekvoptargTF\sine@args{\sine@final{sin}{d}{3}}}
-% \newcommand*\sine@args[2]
-% {\ekvset{expex}{#1,internal}\rnd{3}\deg{d}\f{sin}\sine@stop{#2}}
-% \def\sine@rnd#1\rnd#2#3\sine@stop{\sine@deg#1#3\sine@stop{#2}}^^A
-% \def\sine@deg#1\deg#2#3\sine@stop{\sine@f#1#3\sine@stop{#2}}^^A
-% \def\sine@f#1\f#2#3\sine@stop{\sine@final{#2}}^^A
-% \newcommand*\sine@final[4]{\fpeval{round(#1#2(#4),#3)}}^^A
-% \makeatother
-% \sine{60}\par
-% \sine[round=10]{60}\par
-% \sine[f=cos,radian]{pi}\par
-% \edef\myval{\sine[f=tan]{1}}\texttt{\meaning\myval}
-% \end{exresult}
-%
-% \paragraph{The same macro using \protect\expkvc}
-% Using \expkvc\ we can set up something equivalent with a bit less code. The
-% implementation chosen in \expkvc\ is more efficient than the example above and
-% way easier to code for the user.
-% \begin{lstlisting}
-% \makeatletter
-% \newcommand*\sine{\ekvoptargTF\sine@a{\sine@b{sin}{d}{3}}}
-% \ekvcSplitAndForward\sine@a\sine@b
-% {
-% f=sin,
-% unit=d,
-% round=3,
-% }
-% \ekvcSecondaryKeys\sine@a
-% {
-% nmeta degree={unit=d},
-% nmeta radian={unit={}},
-% }
-% \newcommand*\sine@b[4]{\fpeval{round(#1#2(#4),#3)}}
-% \makeatother
-% \end{lstlisting}
-% The resulting macro will behave just like the one previously defined, but will
-% have an additional |unit| key, since in \expkvc\ every argument must have a
-% value taking key which defines it.
-%
-%
-% \subsection{Error Messages}
-%
-% \expkv\ should only send messages in case of errors, there are no warnings and
-% no info messages. In this subsection those errors are listed.
-%
-% \subsubsection{Load Time}
-%
-% \file{expkv.tex} checks whether \eTeX\ and the |\expanded| primitive are
-% available. If it isn't, an error will be thrown using |\errmessage|:
-% \begin{lstlisting}
-% ! expkv Error: e-TeX and \expanded required.
-% \end{lstlisting}
-%
-% \subsubsection{Defining Keys}
-%
-% If you get any error from \expkv\ while you're trying to define a key, the
-% definition will be aborted and gobbled.
-%
-% If you try to define a key with an empty set name you'll get:
-% \begin{lstlisting}
-% ! expkv Error: empty set name not allowed.
-% \end{lstlisting}
-%
-% Similarly, if you try to define a key with an empty key name:
-% \begin{lstlisting}
-% ! expkv Error: empty key name not allowed.
-% \end{lstlisting}
-%
-% Both of these messages are done in a way that doesn't throw additional errors
-% due to |\global|, |\long|, etc., not being used correctly if you prefixed one
-% of the defining macros.
-%
-% \subsubsection{Using Keys}
-%
-% This subsubsection contains the errors thrown during |\ekvset|. The errors are
-% thrown in an expandable manner using |\ekverr|. In the following messages
-% \lstinline|<key>| gets replaced with the problematic key's name, and
-% \lstinline|<set>| with the corresponding set. If any errors during \kv\
-% handling are encountered, the entry in the comma separated list will be
-% omitted after the error is thrown and the next \kv\ pair will be parsed.
-%
-% If you're using an undefined key you'll get:
-% \begin{lstlisting}
-% Runaway argument?
-% ! expkv Error: unknown key `<key>' in set `<set>'
-% \end{lstlisting}
-%
-% If you're using a key for which only a normal version and no |NoVal| version
-% is defined, but don't provide a value, you'll get:
-% \begin{lstlisting}
-% Runaway argument?
-% ! expkv Error: missing value for `<key>' in set `<set>'
-% \end{lstlisting}
-%
-% If you're using a key for which only a |NoVal| version and no normal version
-% is defined, but provide a value, you'll get:
-% \begin{lstlisting}
-% Runaway argument?
-% ! expkv Error: unwanted value for `<key>' in set `<set>'
-% \end{lstlisting}
-%
-% If you're using an undefined key in a set for which |\ekvredirectunknown| was
-% used, and the key isn't found in any of the other sets as well, you'll get:
-% \begin{lstlisting}
-% Runaway argument?
-% ! expkv Error: no key `<key>' in sets {<set1>}{<set2>}...
-% \end{lstlisting}
-%
-% If you're using an undefined |NoVal| key in a set for which
-% |\ekvredirectunknownNoVal| was used, and the key isn't found in any of the
-% other sets as well, you'll get:
-% \begin{lstlisting}
-% Runaway argument?
-% ! expkv Error: no NoVal key `<key>' in sets {<set1>}{<set2>}...
-% \end{lstlisting}
-%
-% If you're using a set for which you never executed one of the defining macros
-% from \autoref{sec:define} you'll get a low level \TeX\ error, as that isn't
-% actively tested by the parser (and hence will lead to undefined behaviour and
-% not be gracefully ignored). The error will look like
-% \begin{lstlisting}[language={}]
-% ! Missing \endcsname inserted.
-% <to be read again>
-% \! expkv Error: Set `<set>' undefined.
-% \end{lstlisting}
-%
-% \subsection{Bugs}
-%
-% Just like \pkg{keyval}, \expkv\ is bug free. But if you find \pmso{bugs}hidden
-% features\footnote{Thanks, David!} you can tell me about them either via mail
-% (see the first page) or directly on GitHub if you have an account there:
-% \url{https://github.com/Skillmon/tex_expkv}
-%
-% \subsection{Comparisons}\label{sec:cmp}
-%
-% This subsection makes some basic comparison between \expkv\ and other \kv\
-% packages. The comparisons are really concise, regarding speed, feature range
-% (without listing the features of each package), and bugs and misfeatures.
-%
-% Comparisons of speed are done with a very simple test key and the help of the
-% \pkg{l3benchmark} package. The key and its usage should be equivalent to
-% \begin{lstlisting}
-% \protected\ekvdef{test}{height}{\def\myheight{#1}}
-% \ekvsetdef\expkvtest{test}
-% \expkvtest{ height = 6 }
-% \end{lstlisting}
-% and only the usage of the key, not its definition, is benchmarked. For the
-% impatient, the essence of these comparisons regarding speed and buggy
-% behaviour is contained in \autoref{tab:comp}.
-%
-% As far as I know \expkv\ is the only fully expandable \kv\ parser. I tried to
-% compare \expkv\ to every \kv\ package listed on
-% \href{https://ctan.org/topic/keyval}{CTAN}, however, one might notice that
-% some of those are missing from this list. That's because I didn't get the
-% others to work due to bugs, or because they just provide wrappers around other
-% packages in this list.
-%
-% In this subsection is no benchmark of |\ekvparse| and |\keyval_parse:NNn|
-% contained, as most other packages don't provide equivalent features to my
-% knowledge. |\ekvparse| is slightly faster than |\ekvset|, but keep in mind
-% that it does less. The same is true for |\keyval_parse:NNn| compared to
-% |\keys_set:nn| of \pkg{expl3} (where the difference is much bigger). Comparing
-% just the two, |\ekvparse| is a tad faster than |\keyval_parse:NNn| because of
-% the two tests (for empty key names and only a single equal sign) which are
-% omitted.
-%
-% \paragraph{\pkg{keyval}} is about \SIrange{30}{40}{\percent} faster and has a
-% comparable feature set (actually a bit smaller since \expkv\ supports
-% unknown-key handlers and redirection to other sets) just a slightly different
-% way how it handles keys without values. That might be considered a drawback,
-% as it limits the versatility, but also as an advantage, as it might reduce
-% doubled code. Keep in mind that as soon as someone loads \pkg{xkeyval} the
-% performance of \pkg{keyval} gets replaced by \pkg{xkeyval}'s.
-%
-% Also \pkg{keyval} has a bug, which unfortunately can't really be resolved
-% without breaking backwards compatibility for \emph{many} documents, namely it
-% strips braces from the argument before stripping spaces if the argument isn't
-% surrounded by spaces, also it might strip more than one set of braces. Hence
-% all of the following are equivalent in their outcome, though the last two
-% lines should result in something different than the first two:
-% \begin{lstlisting}[belowskip=0pt]
-% \setkeys{foo}{bar=baz}
-% \setkeys{foo}{bar= {baz}}
-% \setkeys{foo}{bar={ baz}} % should be ` baz'
-% \setkeys{foo}{bar={{baz}}} % should be `{baz}'
-% \end{lstlisting}
-%
-% \paragraph{\pkg{xkeyval}} is roughly twenty times slower, but it provides more
-% functionality, e.g., it has choice keys, boolean keys, and so on. It contains
-% the same bug as \pkg{keyval} as it has to be compatible with it by design (it
-% replaces \pkg{keyval}'s frontend), but also adds even more cases in which
-% braces are stripped that shouldn't be stripped, worsening the situation.
-%
-% \paragraph{\pkg{ltxkeys}} is no longer compatible with the \LaTeX\ kernel
-% starting with the release 2020-10-01. It is over 380 times slower -- which is
-% funny, because it aims to be ``[\ldots] faster [\ldots] than these earlier
-% packages [referring to \pkg{keyval} and \pkg{xkeyval}].'' It needs more time
-% to parse zero~keys than five of the packages in this comparison need to parse
-% 100~keys. Since it aims to have a bigger feature set than \pkg{xkeyval}, it
-% most definitely also has a bigger feature set than \expkv. Also, it can't
-% parse |\long| input, so as soon as your values contain a |\par|, it'll throw
-% errors. Furthermore, \pkg{ltxkeys} doesn't strip outer braces at all by
-% design, which, imho, is a weird design choice. In addition \pkg{ltxkeys} loads
-% \pkg{catoptions} which is known to introduce bugs (e.g., see
-% \url{https://tex.stackexchange.com/questions/461783}). Because it is no longer
-% compatible with the kernel, I stop benchmarking it (so the numbers listed here
-% and in \autoref{tab:comp} regarding \pkg{ltxkeys} were last updated on
-% 2020-10-05).
-%
-% \paragraph{\pkg{l3keys}} is around four and a half times slower, but has an,
-% imho, great interface to define keys. It strips \emph{all} outer spaces, even
-% if somehow multiple spaces ended up on either end. It offers more features,
-% but is pretty much bound to \pkg{expl3} code. Whether that's a drawback is up
-% to you.
-%
-% \paragraph{\pkg{pgfkeys}} is around \num{2.7} times slower for one key if one
-% uses the |/|\meta{path}|/.cd| syntax and almost \SI{20}{\percent} slower if
-% one uses |\pgfqkeys|, but has an \emph{enormous} feature set.
-% To get the best performance |\pgfqkeys| was used in the benchmark. This
-% reduces the overhead for setting the base directory of the benchmark keys by
-% about \SI{43}{\ops} (so both $p_0$ and $T_0$ would be about \SI{43}{\ops}
-% bigger if |\pgfkeys{|\meta{path}|/.cd,|\meta{keys}|}| was used instead).
-% It has the same or a very similar bug \pkg{keyval} has. The brace bug (and
-% also the category fragility) can be fixed by \pkg{pgfkeyx}, but this package
-% was last updated in 2012 and it slows down |\pgfkeys| by factor~\num{8}. Also
-% \pkg{pgfkeyx} is no longer compatible with versions of \pkg{pgfkeys} newer
-% than 2020-05-25.
-%
-% \paragraph{\pkg{kvsetkeys} with \pkg{kvdefinekeys}} is about \num{4.4} times
-% slower, but it works even if commas and equals have category codes different
-% from 12 (just as some other packages in this list). Else the features of the
-% keys are equal to those of \pkg{keyval}, the parser has more features, though.
-%
-% \paragraph{\pkg{options}} is \num{1.7} times slower for only a single value.
-% It has a much bigger feature set. Unfortunately it also suffers from the
-% premature unbracing bug \pkg{keyval} has.
-%
-% \paragraph{\pkg{simplekv}} is hard to compare because I don't speak French (so
-% I don't understand the documentation). There was an update released on
-% 2020-04-27 which greatly improved the package's performance and adds
-% functionality so that it can be used more like most of the other \kv\
-% packages. It has problems with stripping braces and spaces in a hard to
-% predict manner just like \pkg{keyval}. Also, while it tries to be robust
-% against category code changes of commas and equal signs, the used mechanism
-% fails if the \kv\ list already got tokenised. Regarding unknown keys it got a
-% very interesting behaviour. It doesn't throw an error, but stores the \val\ in
-% a new entry accessible with \cs[no-index]{useKV}. Also if you omit \val\ it
-% stores |true| for that \key. For up to three keys, \expkv\ is a bit faster,
-% for more keys \pkg{simplekv} takes the lead.
-%
-% \paragraph{\protect\yax} is over twenty times slower. It has a pretty
-% strange syntax for the \TeX-world, imho, and again a direct equivalent is hard
-% to define (don't understand me wrong, I don't say I don't like the syntax,
-% it's just atypical). It has the premature unbracing bug, too. Also somehow
-% loading \yax\ broke \pkg{options} for me. The tested definition was:
-% \begin{lstlisting}[belowskip=0pt]
-% \usepackage{yax}
-% \defactiveparameter yax {\storevalue\myheight yax:height } % setup
-% \setparameterlist{yax}{ height = 6 } % benchmark
-% \end{lstlisting}
-%
-% \begin{table}
-% \def\fnsym{\textcolor{red!80!black}{*}}%
-% \sisetup{round-precision=1, round-mode=places}%
-% \begingroup
-% \centering
-% \newcommand*\yes{\textcolor{red!80!black} {yes}}^^A
-% \newcommand*\no {\textcolor{green!80!black}{no}}^^A
-% \caption[Comparison of \kv\ packages]
-% {^^A
-% Comparison of \kv\ packages. The packages are ordered from
-% fastest to slowest for one \kv\ pair. Benchmarking was done using
-% \pkg{l3benchmark} and the scripts in the \file{Benchmarks} folder
-% of the \href{https://github.com/Skillmon/tex_expkv}{git repository}.
-% The columns $p_i$ are the polynomial coefficients of a linear fit to the
-% run-time, $p_0$ can be interpreted as the overhead for initialisation
-% and $p_1$ the cost per key. The $T_0$ column is the actual mean ops
-% needed for an empty list argument, as the linear fit doesn't match that
-% point well in general. The column ``BB'' lists whether the
-% parsing is affected by some sort of brace bug, ``CF'' stands for
-% category code fragile and lists whether the parsing breaks with active
-% commas or equal signs.^^A
-% \label{tab:comp}^^A
-% }
-% \begin{tabular}
-% {>{\collectcell\pkg}l<{\endcollectcell}*3{S[table-format=4.1]}ccc}
-% \toprule
-% \rmfamily Package & {$p_1$} & {$p_0$} & {$T_0$}& BB & CF & Date \\
-% \midrule
-% keyval & 13.742 & 1.486 & 7.254 & \yes & \yes & 2014-10-28 \\
-% \expkv & 19.701 & 2.169 & 6.592 & \no & \no & 2020-10-10 \\
-% simplekv & 18.334 & 6.971 & 17.710 & \yes & \yes & 2020-04-27 \\
-% pgfkeys & 24.274 & 1.725 & 10.650 & \yes & \yes & 2020-09-05 \\
-% options & 23.600 & 15.638 & 20.830 & \yes & \yes & 2015-03-01 \\
-% kvsetkeys & {\fnsym} & {\fnsym} & 40.290 & \no & \no & 2019-12-15 \\
-% l3keys & 71.309 & 33.131 & 31.590 & \no & \no & 2020-09-24 \\
-% xkeyval & 253.563 & 202.246 & 168.300 & \yes & \yes & 2014-12-03 \\
-% \yax & 421.853 & 157.003 & 114.700 & \yes & \yes & 2010-01-22 \\
-% ltxkeys & 3400.142 & 4737.958 & 5368.000 & \no & \no & 2012-11-17 \\
-% \bottomrule
-% \end{tabular}
-% \par
-% \endgroup
-% \medskip
-% \fnsym For \pkg{kvsetkeys} the linear model used for the other
-% packages is a poor fit, \pkg{kvsetkeys} seems to have approximately
-% quadratic run-time, the coefficients of the second degree polynomial fit are
-% $p_2=\num{8.240}$, $p_1=\num{44.862}$, and $p_0=\num{60.793}$. Of course the
-% other packages might not really have linear run-time, but at least from 1~to
-% 20~keys the fits don't seem too bad. If one extrapolates the fits for 100
-% \kv\ pairs one finds that most of them match pretty well, the exception
-% being \pkg{ltxkeys}, which behaves quadratic as well with
-% $p_2=\num{23.500}$, $p_1=\num{2906.634}$, and $p_0=\num{6547.489}$.
-% \end{table}
-%
-% \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}^^A>>=
-%^^A the LaTeX package >>=
-% \subsection{The \LaTeX\ Package}
-% First we set up the \LaTeX\ package. That one doesn't really do much except
-% |\input|ting the generic code and identifying itself as a package.
-% \gobbledocstriptag
-%<*pkg>
-% \begin{macrocode}
-\def\ekv@tmp
- {%
- \ProvidesFile{expkv.tex}%
- [\ekvDate\space v\ekvVersion\space an expandable key=val implementation]%
- }
-\input{expkv.tex}
-\ProvidesPackage{expkv}%
- [\ekvDate\space v\ekvVersion\space an expandable key=val implementation]
-% \end{macrocode}
-% \gobbledocstriptag
-%</pkg>
-%^^A=<<
-%^^A the ConTeXt module >>=
-% \subsection{The \ConTeXt\ module}
-% This is pretty straight forward, we just have to change the error throwing
-% mechanism for \ConTeXt\ (the approach taken for plain and \LaTeX\ breaks in
-% \ConTeXt, effectively breaking \ConTeXt, dropping you in an interactive \TeX\
-% session with almost no means of escape).
-% \gobbledocstriptag
-%<*ctx>
-% \begin{macrocode}
-\writestatus{loading}{ConTeXt User Module / expkv}
-\unprotect
-\input expkv.tex
-\long\def\ekv@err@collect#1\par#2%
- {\directlua{tex.error[[\detokenize{#2} Error: #1]]}}
-\writestatus{loading}
- {ConTeXt User Module / expkv / Version \ekvVersion\space loaded}
-\protect\endinput
-% \end{macrocode}
-% \gobbledocstriptag
-%</ctx>
-%^^A=<<
-%^^A main file >>=
-% \subsection{The Generic Code}
-% The rest of this implementation will be the generic code.
-% \gobbledocstriptag
-%<*tex>
-%
-% We make sure that it's only input once:
-% \begin{macrocode}
-\expandafter\ifx\csname ekvVersion\endcsname\relax
-\else
- \expandafter\endinput
-\fi
-% \end{macrocode}
-%
-% Check whether \eTeX\ and |\expanded| are available -- \expkv\ requires \eTeX.
-% \begin{macrocode}
-\begingroup
- \edef\ekvtmpa{\string\expanded}
- \edef\ekvtmpb{\meaning\expanded}
- \expandafter
-\endgroup
-\ifx\ekvtmpa\ekvtmpb
- \expandafter\let\csname ekv@expanded\endcsname\expanded
- \expandafter\let\csname ekv@unexpanded\endcsname\unexpanded
-\else
- \begingroup
- \edef\ekvtmpa{\string\expanded}
- \edef\ekvtmpb{\meaning\normalexpanded}
- \expandafter
- \endgroup
- \ifx\ekvtmpa\ekvtmpb
- \expandafter\let\csname ekv@expanded\endcsname\normalexpanded
- \expandafter\let\csname ekv@unexpanded\endcsname\normalunexpanded
- \else
- \errmessage
- {expkv Error: e-TeX and the \noexpand\expanded primitive required}%
- \expandafter\endinput
- \fi
-\fi
-% \end{macrocode}
-%
-% \begin{macro}{\ekvVersion,\ekvDate}
-% We're on our first input, so lets store the version and date in a macro.
-% \begin{macrocode}
-\def\ekvVersion{1.9a}
-\def\ekvDate{2021-09-20}
-% \end{macrocode}
-% \end{macro}
-%
-% If the \LaTeX\ format is loaded we want to be a good file and report back who
-% we are, for this the package will have defined |\ekv@tmp| to use
-% |\ProvidesFile|, else this will expand to a |\relax| and do no harm.
-% \begin{macrocode}
-\csname ekv@tmp\endcsname
-% \end{macrocode}
-%
-% Store the category code of |@| to later be able to reset it and change it to
-% 11 for now.
-% \begin{macrocode}
-\expandafter\chardef\csname ekv@tmp\endcsname=\catcode`\@
-\catcode`\@=11
-% \end{macrocode}
-% |\ekv@tmp| might later be reused to gobble any prefixes which might be
-% provided to |\ekvdef| and similar in case the names are invalid, we just
-% temporarily use it here as means to store the current category code of |@| to
-% restore it at the end of the file, we never care for the actual definition of
-% it.
-%
-% \begin{macro}[internal]{\ekv@if@lastnamedcs}
-% If the primitive |\lastnamedcs| is available, we can be a bit faster than
-% without it. So we test for this and save the test's result in this macro.
-% \begin{macrocode}
-\begingroup
- \edef\ekv@tmpa{\string \lastnamedcs}
- \edef\ekv@tmpb{\meaning\lastnamedcs}
- \ifx\ekv@tmpa\ekv@tmpb
- \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##1}}
- \else
- \def\ekv@if@lastnamedcs{\long\def\ekv@if@lastnamedcs##1##2{##2}}
- \fi
- \expandafter
-\endgroup
-\ekv@if@lastnamedcs
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@empty}
-% Sometimes we have to introduce a token to prevent accidental brace stripping.
-% This token would then need to be removed by |\@gobble| or similar. Instead we
-% can use |\ekv@empty| which will just expand to nothing, that is faster than
-% gobbling an argument.
-% \begin{macrocode}
-\def\ekv@empty{}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \@gobble,\@firstofone,\@firstoftwo,\@secondoftwo,
-% \ekv@fi@gobble,\ekv@fi@firstofone,\ekv@fi@firstoftwo,\ekv@fi@secondoftwo,
-% \ekv@gobble@mark,\ekv@gobbleto@stop,\ekv@gobble@from@mark@to@stop
-% }
-% Since branching tests are often more versatile than |\if...\else...\fi|
-% constructs, we define helpers that are branching pretty fast. Also here are
-% some other utility functions that just grab some tokens. The ones that are
-% also contained in \LaTeX\ don't use the |ekv| prefix. Not all of the ones
-% defined here are really needed by \expkv\ but are provided because packages
-% like \expkvd\ or \expkvo\ need them (and I don't want to define them in each
-% package which might need them).
-% \begin{macrocode}
-\long\def\@gobble#1{}
-\long\def\@firstofone#1{#1}
-\long\def\@firstoftwo#1#2{#1}
-\long\def\@secondoftwo#1#2{#2}
-\long\def\ekv@fi@gobble\fi\@firstofone#1{\fi}
-\long\def\ekv@fi@firstofone\fi\@gobble#1{\fi#1}
-\long\def\ekv@fi@firstoftwo\fi\@secondoftwo#1#2{\fi#1}
-\long\def\ekv@fi@secondoftwo\fi\@firstoftwo#1#2{\fi#2}
-\def\ekv@gobble@mark\ekv@mark{}
-\long\def\ekv@gobbleto@stop#1\ekv@stop{}
-\long\def\ekv@gobble@from@mark@to@stop\ekv@mark#1\ekv@stop{}
-% \end{macrocode}
-% \end{macro}
-% As you can see |\ekv@gobbleto@stop| uses a special marker |\ekv@stop|. The
-% package will use three such markers, the one you've seen already, |\ekv@mark|
-% and |\ekv@nil|. Contrarily to how for instance \pkg{expl3} does things, we
-% don't define them, as we don't need them to have an actual meaning. This has
-% the advantage that if they somehow get expanded -- which should never happen
-% if things work out -- they'll throw an error directly.
-%
-% \begin{macro}[internal]
-% {
-% \ekv@ifempty,\ekv@ifempty@,\ekv@ifempty@true,\ekv@ifempty@false,
-% \ekv@ifempty@true@F,\ekv@ifempty@true@F@gobble,
-% \ekv@ifempty@true@F@gobbletwo
-% }
-% We can test for a lot of things building on an if-empty test, so lets define a
-% really fast one. Since some tests might have reversed logic (true if something
-% is not empty) we also set up macros for the reversed branches.
-% \begin{macrocode}
-\long\def\ekv@ifempty#1%
- {%
- \ekv@ifempty@\ekv@ifempty@A#1\ekv@ifempty@B\ekv@ifempty@true
- \ekv@ifempty@A\ekv@ifempty@B\@secondoftwo
- }
-\long\def\ekv@ifempty@#1\ekv@ifempty@A\ekv@ifempty@B{}
-\long\def\ekv@ifempty@true\ekv@ifempty@A\ekv@ifempty@B\@secondoftwo#1#2{#1}
-\long\def\ekv@ifempty@false\ekv@ifempty@A\ekv@ifempty@B\@firstoftwo#1#2{#2}
-\long\def\ekv@ifempty@true@F\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1{}
-\long\def\ekv@ifempty@true@F@gobble\ekv@ifempty@A\ekv@ifempty@B\@firstofone#1#2%
- {}
-\long\def\ekv@ifempty@true@F@gobbletwo
- \ekv@ifempty@A\ekv@ifempty@B\@firstofone#1#2#3%
- {}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@ifblank,\ekv@ifblank@}
-% The obvious test that can be based on an if-empty is if-blank, meaning a test
-% checking whether the argument is empty or consists only of spaces. Our version
-% here will be tweaked a bit, as we want to check this, but with one leading
-% |\ekv@mark| token that is to be ignored. The wrapper |\ekv@ifblank| will not
-% be used by \expkv\ for speed reasons but \expkvo\ uses it.
-% \begin{macrocode}
-\long\def\ekv@ifblank#1%
- {%
- \ekv@ifblank@#1\ekv@nil\ekv@ifempty@B\ekv@ifempty@true
- \ekv@ifempty@A\ekv@ifempty@B\@secondoftwo
- }
-\long\def\ekv@ifblank@\ekv@mark#1{\ekv@ifempty@\ekv@ifempty@A}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@ifdefined}
-% We'll need to check whether something is defined quite frequently, so why not
-% define a macro that does this. The following test is expandable and pretty
-% fast. The version with |\lastnamedcs| is the fastest version to test for an
-% undefined macro I know of (that considers both undefined macros and those with
-% the meaning |\relax|).
-% \begin{macrocode}
-\ekv@if@lastnamedcs
- {%
- \long\def\ekv@ifdefined#1{\ifcsname#1\endcsname\ekv@ifdef@\fi\@secondoftwo}
- \def\ekv@ifdef@\fi\@secondoftwo
- {%
- \fi
- \expandafter\ifx\lastnamedcs\relax
- \ekv@fi@secondoftwo
- \fi
- \@firstoftwo
- }
- }
- {%
- \long\def\ekv@ifdefined#1%
- {%
- \ifcsname#1\endcsname\ekv@ifdef@\fi\ekv@ifdef@false#1\endcsname\relax
- \ekv@fi@secondoftwo
- \fi
- \@firstoftwo
- }
- \def\ekv@ifdef@\fi\ekv@ifdef@false{\fi\expandafter\ifx\csname}
- \long\def\ekv@ifdef@false
- #1\endcsname\relax\ekv@fi@secondoftwo\fi\@firstoftwo#2#3%
- {#3}
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@strip,\ekv@strip@a,\ekv@strip@b,\ekv@strip@c}
-% We borrow some ideas of \pkg{expl3}'s \pkg{l3tl} to strip spaces
-% from keys and values. This |\ekv@strip| also strips one level of outer braces
-% \emph{after} stripping spaces, so an input of | {abc} | becomes |abc| after
-% stripping. It should be used with |#1| prefixed by |\ekv@mark|. Also this
-% implementation at most strips \emph{one} space from both sides (which should
-% be fine most of the time, since \TeX\ reads consecutive spaces as a single one
-% during tokenisation).
-% \begin{macrocode}
-\def\ekv@strip#1%
- {%
- \long\def\ekv@strip##1%
- {%
- \ekv@strip@a
- ##1\ekv@nil
- \ekv@mark#1%
- #1\ekv@nil
- }%
- \long\def\ekv@strip@a##1\ekv@mark#1{\ekv@strip@b##1\ekv@mark}%
- }
-\ekv@strip{ }
-\long\def\ekv@strip@b#1 \ekv@nil{\ekv@strip@c#1\ekv@nil}
-\long\def\ekv@strip@c\ekv@mark#1\ekv@nil\ekv@mark#2\ekv@nil#3{#3{#1}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekv@exparg,\ekv@exparg@,\ekv@expargtwice,\ekv@expargtwice@,\ekv@zero}
-% To reduce some code doublets while gaining some speed (and also as convenience
-% for other packages in the family), it is often useful to expand the first
-% token in a definition once. Let's define a wrapper for this.
-%
-% Also, to end a |\romannumeral| expansion, we want to use |\z@|, which is
-% contained in both plain \TeX\ and \LaTeX, but we use a private name for it to
-% make it easier to spot and hence easier to manage.
-% \begin{macrocode}
-\let\ekv@zero\z@
-\long\def\ekv@exparg#1#2{\expandafter\ekv@exparg@\expandafter{#2}{#1}}
-\long\def\ekv@exparg@#1#2{#2{#1}}%
-\long\def\ekv@expargtwice#1#2{\expandafter\ekv@expargtwice@\expandafter{#2}{#1}}
-\def\ekv@expargtwice@{\expandafter\ekv@exparg@\expandafter}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvcsvloop}
-% \begin{macro}[internal]{\ekv@csv@loop@active,\ekv@csv@loop@active@end}
-% An |\ekvcsvloop| will just loop over a csv list in a simple manner. First we
-% split at active commas (gives better performance this way), next we have to
-% check whether we're at the end of the list (checking for |\ekv@stop|). If
-% not we go on splitting at commas of category other.
-% \begin{macrocode}
-\begingroup
-\def\ekvcsvloop#1{%
-\endgroup
-\long\def\ekvcsvloop##1##2%
- {\ekv@csv@loop@active{##1}\ekv@mark##2#1\ekv@stop#1}
-% \end{macrocode}
-% This does the same as |\ekv@csv@loop| but for active commas.
-% \begin{macrocode}
-\long\def\ekv@csv@loop@active##1##2#1%
- {%
- \ekv@gobble@from@mark@to@stop##2\ekv@csv@loop@active@end\ekv@stop
- \ekv@csv@loop{##1}##2,\ekv@stop,%
- }%
-\long\def\ekv@csv@loop@active@end
- \ekv@stop
- \ekv@csv@loop##1\ekv@mark\ekv@stop,\ekv@stop,%
- {}%
-}
-% \end{macrocode}
-% Do the definitions with the weird catcode.
-% \begin{macrocode}
-\catcode`\,=13
-\ekvcsvloop,
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@csv@loop,\ekv@csv@loop@do,\ekv@csv@loop@end}
-% We use temporary macros and an |\expandafter| chain to preexpand
-% |\ekv@strip| here. After splitting at other commas we check again for end
-% the end of the sublist, check for blank elements which should be ignored,
-% and else strip spaces and execute the user code (protecting it from further
-% expanding with |\unexpanded|).
-% \begin{macrocode}
-\def\ekv@csv@loop#1%
- {%
- \long\def\ekv@csv@loop##1##2,%
- {%
- \ekv@gobble@from@mark@to@stop##2\ekv@csv@loop@end\ekv@stop
- \ekv@ifblank@##2\ekv@nil\ekv@ifempty@B\ekv@csv@loop@blank
- \ekv@ifempty@A\ekv@ifempty@B
- #1\ekv@csv@loop@do{##1}%
- }%
- }
-\expandafter\ekv@csv@loop\expandafter{\ekv@strip{#2}}
-\long\def\ekv@csv@loop@do#1#2{\ekv@unexpanded{#2{#1}}\ekv@csv@loop{#2}\ekv@mark}
-\def\ekv@csv@loop@end#1%
- {%
- \long\def\ekv@csv@loop@end
- \ekv@stop
- \ekv@ifblank@\ekv@mark\ekv@stop\ekv@nil\ekv@ifempty@B\ekv@csv@loop@blank
- \ekv@ifempty@A\ekv@ifempty@B
- #1\ekv@csv@loop@do##1%
- {\ekv@csv@loop@active{##1}\ekv@mark}%
- }
-\expandafter\ekv@csv@loop@end\expandafter{\ekv@strip{\ekv@mark\ekv@stop}}
-\long\expandafter\def\expandafter\ekv@csv@loop@blank
- \expandafter\ekv@ifempty@A\expandafter\ekv@ifempty@B
- \ekv@strip{\ekv@mark#1}\ekv@csv@loop@do#2%
- {\ekv@csv@loop{#2}\ekv@mark}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekv@name,\ekv@name@set,\ekv@name@key}
-% The keys will all follow the same naming scheme, so we define it here.
-% \begin{macrocode}
-\def\ekv@name@set#1{ekv#1(}
-\long\def\ekv@name@key#1{#1)}
-\edef\ekv@name
- {%
- \ekv@unexpanded\expandafter{\ekv@name@set{#1}}%
- \ekv@unexpanded\expandafter{\ekv@name@key{\detokenize{#2}}}%
- }
-\long\ekv@exparg{\def\ekv@name#1#2}{\ekv@name}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@undefined@set}
-% We can misuse the macro name we use to expandably store the set-name in a
-% single token -- since this increases performance drastically, especially for
-% long set-names -- to throw a more meaningful error message in case a set isn't
-% defined. The name of |\ekv@undefined@set| is a little bit misleading, as it is
-% called in either case inside of |\csname|, but the result will be a control
-% sequence with meaning |\relax| if the set is undefined, hence will break the
-% |\csname| building the key-macro which will throw the error message.
-% \begin{macrocode}
-\def\ekv@undefined@set#1{! expkv Error: Set `#1' undefined.}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@checkvalid}
-% We place some restrictions on the allowed names, though, namely sets and
-% keys are not allowed to be empty -- blanks are fine (meaning \mbox{set-
-% or} key-names consisting of spaces). The |\def\ekv@tmp| gobbles any \TeX\
-% prefixes which would otherwise throw errors. This will, however, break the
-% package if an |\outer| has been gobbled this way. I consider that good,
-% because keys shouldn't be defined |\outer| anyways.
-% \begin{macrocode}
-\edef\ekv@checkvalid
- {%
- \ekv@unexpanded\expandafter{\ekv@ifempty{#1}}%
- \ekv@unexpanded
- {{%
- \def\ekv@tmp{}%
- \errmessage{expkv Error: empty set name not allowed}%
- }}%
- {%
- \ekv@unexpanded\expandafter{\ekv@ifempty{#2}}%
- \ekv@unexpanded
- {%
- {%
- \def\ekv@tmp{}%
- \errmessage{expkv Error: empty key name not allowed}%
- }%
- \@secondoftwo
- }%
- }%
- \ekv@unexpanded{\@gobble}%
- }
-\ekv@exparg{\protected\def\ekv@checkvalid#1#2}{\ekv@checkvalid}%
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvifdefined,\ekvifdefinedNoVal}
-% And provide user-level macros to test whether a key is defined.
-% \begin{macrocode}
-\ekv@expargtwice{\long\def\ekvifdefined#1#2}%
- {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}}}
-\ekv@expargtwice{\long\def\ekvifdefinedNoVal#1#2}%
- {\expandafter\ekv@ifdefined\expandafter{\ekv@name{#1}{#2}N}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% \ekvdef,\ekvdefNoVal,\ekvlet,\ekvletNoVal,\ekvletkv,\ekvletkvNoVal,
-% \ekvdefunknown,\ekvdefunknownNoVal
-% }
-% Set up the key defining macros |\ekvdef| etc. We use temporary macros to set
-% these up with a few expansions already done.
-% \begin{macrocode}
-\def\ekvdef#1#2#3#4%
- {%
- \protected\long\def\ekvdef##1##2##3%
- {#1{\expandafter\def\csname#2\endcsname####1{##3}#3}}%
- \protected\long\def\ekvdefNoVal##1##2##3%
- {#1{\expandafter\def\csname#2N\endcsname{##3}#3}}%
- \protected\long\def\ekvlet##1##2##3%
- {#1{\expandafter\let\csname#2\endcsname##3#3}}%
- \protected\long\def\ekvletNoVal##1##2##3%
- {#1{\expandafter\let\csname#2N\endcsname##3#3}}%
- \ekv@expargtwice{\protected\long\def\ekvdefunknown##1##2}%
- {%
- \romannumeral
- \expandafter\ekv@exparg@\expandafter
- {%
- \expandafter\expandafter\expandafter
- \def\expandafter\csname\ekv@name{##1}{}u\endcsname####1####2{##2}%
- #3%
- }%
- {\ekv@zero\ekv@checkvalid{##1}.}%
- }%
- \ekv@expargtwice{\protected\long\def\ekvdefunknownNoVal##1##2}%
- {%
- \romannumeral
- \expandafter\ekv@exparg@\expandafter
- {%
- \expandafter\expandafter\expandafter
- \def\expandafter\csname\ekv@name{##1}{}uN\endcsname####1{##2}%
- #3%
- }%
- {\ekv@zero\ekv@checkvalid{##1}.}%
- }%
- \protected\long\def\ekvletkv##1##2##3##4%
- {%
- #1%
- {%
- \expandafter\let\csname#2\expandafter\endcsname
- \csname#4\endcsname
- #3%
- }%
- }%
- \protected\long\def\ekvletkvNoVal##1##2##3##4%
- {%
- #1%
- {%
- \expandafter\let\csname#2N\expandafter\endcsname
- \csname#4N\endcsname
- #3%
- }%
- }%
- }
-\edef\ekvdefNoVal
- {%
- {\ekv@unexpanded\expandafter{\ekv@checkvalid{#1}{#2}}}%
- {\ekv@unexpanded\expandafter{\ekv@name{#1}{#2}}}%
- {%
- \ekv@unexpanded{\expandafter\ekv@defsetmacro\csname}%
- \ekv@unexpanded\expandafter{\ekv@undefined@set{#1}\endcsname{#1}}%
- }%
- {\ekv@unexpanded\expandafter{\ekv@name{#3}{#4}}}%
- }
-\expandafter\ekvdef\ekvdefNoVal
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvredirectunknown,\ekvredirectunknownNoVal}
-% \begin{macro}[internal]
-% {
-% \ekv@defredirectunknown,\ekv@redirectunknown@aux,
-% \ekv@redirectunknownNoVal@aux
-% }
-% The redirection macros prepare the unknown function by looping over the
-% provided list of sets and leaving a |\ekv@redirect@kv| or |\ekv@redirect@k|
-% for each set. Only the first of these internals will receive the \key\ and
-% \val\ as arguments.
-% \begin{macrocode}
-\protected\def\ekvredirectunknown
- {%
- \ekv@defredirectunknown
- \ekv@redirect@kv
- \ekv@err@redirect@kv@notfound
- {\long\ekvdefunknown}%
- \ekv@redirectunknown@aux
- }
-\protected\def\ekvredirectunknownNoVal
- {%
- \ekv@defredirectunknown
- \ekv@redirect@k
- \ekv@err@redirect@k@notfound
- \ekvdefunknownNoVal
- \ekv@redirectunknownNoVal@aux
- }
-\protected\def\ekv@defredirectunknown#1#2#3#4#5#6%
- {%
- \begingroup
- \edef\ekv@tmp
- {%
- \ekvcsvloop#1{#6}%
- \ekv@unexpanded{#2}%
- {\ekvcsvloop{}{#5,#6}}%
- }%
- \ekv@expargtwice
- {\endgroup#3{#5}}%
- {\expandafter#4\ekv@tmp\ekv@stop}%
- }
-\def\ekv@redirectunknown@aux#1{#1{##1}{##2}}
-\def\ekv@redirectunknownNoVal@aux#1{#1{##1}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekv@redirect@k,\ekv@redirect@k@a,\ekv@redirect@k@a@,
-% \ekv@redirect@k@b,\ekv@redirect@k@c,\ekv@redirect@k@d,
-% \ekv@redirect@kv,\ekv@redirect@kv@a,\ekv@redirect@kv@a@,
-% \ekv@redirect@kv@b,\ekv@redirect@kv@c,\ekv@redirect@kv@d
-% }
-% The redirect code works by some simple loop over all the sets, which we
-% already preprocessed in |\ekv@defredirectunknown|. For some optimisation we
-% blow this up a bit code wise, essentially, all this does is |\ekvifdefined|
-% or |\ekvifdefinedNoVal| in each set, if there is a match gobble the
-% remainder of the specified sets and execute the key macro, else go on with
-% the next set (to which the \key\ and \val\ are forwarded).
-%
-% First we set up some code which is different depending on |\lastnamedcs|
-% being available or not. All this is stored in a temporary macro to have
-% pre-expanded |\ekv@name| constellations ready.
-% \begin{macrocode}
-\def\ekv@redirect@k#1#2#3#4%
- {%
- \ekv@if@lastnamedcs
- {%
- \def\ekv@redirect@k##1##2##3%
- {%
- \ifcsname#1\endcsname\ekv@redirect@k@a\fi
- ##3{##1}%
- }%
- \def\ekv@redirect@k@a\fi{\fi\expandafter\ekv@redirect@k@b\lastnamedcs}%
- \long\def\ekv@redirect@kv##1##2##3##4%
- {%
- \ifcsname#2\endcsname\ekv@redirect@kv@a\fi\@gobble{##1}%
- ##4{##1}{##2}%
- }%
- \def\ekv@redirect@kv@a\fi\@gobble
- {\fi\expandafter\ekv@redirect@kv@b\lastnamedcs}%
- }
- {%
- \def\ekv@redirect@k##1##2##3%
- {%
- \ifcsname#1\endcsname\ekv@redirect@k@a\fi\ekv@redirect@k@a@
- #1\endcsname
- ##3{##1}%
- }%
- \def\ekv@redirect@k@a@#3\endcsname{}%
- \def\ekv@redirect@k@a\fi\ekv@redirect@k@a@
- {\fi\expandafter\ekv@redirect@k@b\csname}%
- \long\def\ekv@redirect@kv##1##2##3##4%
- {%
- \ifcsname#2\endcsname\ekv@redirect@kv@a\fi\ekv@redirect@kv@a@
- #2\endcsname{##1}%
- ##4{##1}{##2}%
- }%
- \long\def\ekv@redirect@kv@a@#4\endcsname##3{}%
- \def\ekv@redirect@kv@a\fi\ekv@redirect@kv@a@
- {\fi\expandafter\ekv@redirect@kv@b\csname}%
- }%
- }
-% \end{macrocode}
-% The key name given to this loop will already be |\detokenize|d by |\ekvset|,
-% so we can safely remove the |\detokenize| here for some performance gain.
-% \begin{macrocode}
-\def\ekv@redirect@kv#1\detokenize#2#3\ekv@stop{\ekv@unexpanded{#1#2#3}}
-\edef\ekv@redirect@kv
- {%
- {\expandafter\ekv@redirect@kv\ekv@name{#2}{#1}N\ekv@stop}%
- {\expandafter\ekv@redirect@kv\ekv@name{#3}{#2}\ekv@stop}%
- {\expandafter\ekv@redirect@kv\ekv@name{#1}{#2}N\ekv@stop}%
- {\expandafter\ekv@redirect@kv\ekv@name{#1}{#2}\ekv@stop}%
- }
-% \end{macrocode}
-% Everything is ready to make the real definitions.
-% \begin{macrocode}
-\expandafter\ekv@redirect@k\ekv@redirect@kv
-% \end{macrocode}
-% The remaining macros here are independent on |\lastnamedcs|, starting from
-% the |@b| we know that there is a hash table entry, and get the macro as a
-% parameter. We still have to test whether the macro is |\relax|, depending on
-% the result of that test we have to either remove the remainder of the
-% current test, or the remainder of the set list and invoke the macro.
-% \begin{macrocode}
-\def\ekv@redirect@k@b#1%
- {\ifx\relax#1\ekv@redirect@k@c\fi\ekv@redirect@k@d#1}
-\def\ekv@redirect@k@c\fi\ekv@redirect@k@d#1{\fi}
-\def\ekv@redirect@k@d#1#2\ekv@stop{#1}
-\def\ekv@redirect@kv@b#1%
- {\ifx\relax#1\ekv@redirect@kv@c\fi\ekv@redirect@kv@d#1}
-\long\def\ekv@redirect@kv@c\fi\ekv@redirect@kv@d#1#2{\fi}
-\long\def\ekv@redirect@kv@d#1#2#3\ekv@stop{#1{#2}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@defsetmacro}
-% In order to enhance the speed the set name given to |\ekvset| will be turned
-% into a control sequence pretty early, so we have to define that control
-% sequence.
-% \begin{macrocode}
-\edef\ekv@defsetmacro
- {%
- \ekv@unexpanded{\ifx#1\relax\edef#1##1}%
- {%
- \ekv@unexpanded\expandafter{\ekv@name@set{#2}}%
- \ekv@unexpanded\expandafter{\ekv@name@key{##1}}%
- }%
- \ekv@unexpanded{\fi}%
- }
-\ekv@exparg{\protected\def\ekv@defsetmacro#1#2}{\ekv@defsetmacro}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvifdefinedset}
-% \begin{macrocode}
-\ekv@expargtwice{\def\ekvifdefinedset#1}%
- {\expandafter\ekv@ifdefined\expandafter{\ekv@undefined@set{#1}}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvset}
-% Set up |\ekvset|, which should not be affected by active commas and equal
-% signs. The equal signs are a bit harder to cope with and we'll do that later,
-% but the active commas can be handled by just doing two comma-splitting loops
-% one at actives one at others. That's why we define |\ekvset| here with a
-% temporary meaning just to set up the things with two different category codes.
-% |#1| will be a \texttt{,\textsubscript{13}} and |#2| will be a
-% \texttt{=\textsubscript{13}}.
-% \begin{macrocode}
-\begingroup
-\def\ekvset#1#2{%
-\endgroup
-\ekv@exparg{\long\def\ekvset##1##2}%
- {%
- \expandafter\expandafter\expandafter
- \ekv@set\expandafter\csname\ekv@undefined@set{##1}\endcsname
- \ekv@mark##2#1\ekv@stop#1{}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@set}
-% |\ekv@set| will split the \kv\ list at active commas. Then it has to check
-% whether there were unprotected other commas and resplit there.
-% \begin{macrocode}
-\long\def\ekv@set##1##2#1%
- {%
-% \end{macrocode}
-% Test whether we're at the end, if so invoke |\ekv@endset|,
-% \begin{macrocode}
- \ekv@gobble@from@mark@to@stop##2\ekv@endset\ekv@stop
-% \end{macrocode}
-% else go on with other commas.
-% \begin{macrocode}
- \ekv@set@other##1##2,\ekv@stop,%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@endset}
-% |\ekv@endset| is a hungry little macro. It will eat everything that remains
-% of |\ekv@set| and unbrace the sneaked stuff.
-% \begin{macrocode}
-\long\def\ekv@endset
- \ekv@stop\ekv@set@other##1\ekv@mark\ekv@stop,\ekv@stop,##2%
- {##2}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@eq@other,\ekv@eq@active}
-% Splitting at equal signs will be done in a way that checks whether there is
-% an equal sign and splits at the same time. This gets quite messy and the
-% code might look complicated, but this is pretty fast (faster than first
-% checking for an equal sign and splitting if one is found). The splitting
-% code will be adapted for |\ekvset| and |\ekvparse| to get the most speed,
-% but some of these macros don't require such adaptions. |\ekv@eq@other| and
-% |\ekv@eq@active| will split the argument at the first equal sign and insert
-% the macro which comes after the first following |\ekv@mark|. This allows for
-% fast branching based on \TeX's argument grabbing rules and we don't have to
-% split after the branching if the equal sign was there.
-% \begin{macrocode}
-\long\def\ekv@eq@other##1=##2\ekv@mark##3{##3##1\ekv@stop\ekv@mark##2}
-\long\def\ekv@eq@active##1#2##2\ekv@mark##3{##3##1\ekv@stop\ekv@mark##2}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@set@other}
-% The macro |\ekv@set@other| is guaranteed to get only single \kv\ pairs.
-% \begin{macrocode}
-\long\def\ekv@set@other##1##2,%
- {%
-% \end{macrocode}
-% First we test whether we're done.
-% \begin{macrocode}
- \ekv@gobble@from@mark@to@stop##2\ekv@endset@other\ekv@stop
-% \end{macrocode}
-% If not we split at the equal sign of category other.
-% \begin{macrocode}
- \ekv@eq@other##2\ekv@nil\ekv@mark\ekv@set@eq@other@a
- =\ekv@mark\ekv@set@eq@active
-% \end{macrocode}
-% And insert the set name for the next recursion step of |\ekv@set@other|.
-% \begin{macrocode}
- ##1%
- \ekv@mark
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@set@eq@other@a, \ekv@set@eq@other@b}
-% The first of these two macros runs the split-test for equal signs of
-% category active. It will only be inserted if the \kv\ pair contained at
-% least one equal sign of category other and |##1| will contain everything up
-% to that equal sign.
-% \begin{macrocode}
-\long\def\ekv@set@eq@other@a##1\ekv@stop
- {%
- \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@set@eq@other@active
- #2\ekv@mark\ekv@set@eq@other@b
- }
-% \end{macrocode}
-% The second macro will have been called by |\ekv@eq@active| if no active
-% equal sign was found. All it does is remove the excess tokens of that
-% test and forward the \kv\ pair to |\ekv@set@pair|. Normally we would have to
-% also gobble an additional |\ekv@mark| after |\ekv@stop|, but this mark is
-% needed to delimit |\ekv@set@pair|'s argument anyway, so we just leave it
-% there.
-% \begin{macrocode}
-\ekv@exparg
- {%
- \long\def\ekv@set@eq@other@b
- ##1\ekv@nil\ekv@mark\ekv@set@eq@other@active\ekv@stop\ekv@mark
- ##2\ekv@nil=\ekv@mark\ekv@set@eq@active
- }%
- {\ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2\ekv@nil}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@set@eq@other@active}
-% |\ekv@set@eq@other@active| will be called if the \kv\ pair was wrongly
-% split on an equal sign of category other but has an earlier equal sign of
-% category active. |##1| will be the contents up to the active equal sign and
-% |##2| everything that remains until the first found other equal sign. It has
-% to reinsert the equal sign and forward things to |\ekv@set@pair|.
-% \begin{macrocode}
-\ekv@exparg
- {%
- \long\def\ekv@set@eq@other@active
- ##1\ekv@stop##2\ekv@nil#2\ekv@mark
- \ekv@set@eq@other@b\ekv@mark##3=\ekv@mark\ekv@set@eq@active
- }%
- {\ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2=##3}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@set@eq@active, \ekv@set@eq@active@}
-% |\ekv@set@eq@active| will be called when there was no equal sign of category
-% other in the \kv\ pair. It removes the excess tokens of the prior test and
-% split-checks for an active equal sign.
-% \begin{macrocode}
-\long\def\ekv@set@eq@active
- ##1\ekv@nil\ekv@mark\ekv@set@eq@other@a\ekv@stop\ekv@mark
- {%
- \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@set@eq@active@
- #2\ekv@mark\ekv@set@noeq
- }
-% \end{macrocode}
-% If an active equal sign was found in |\ekv@set@eq@active| we'll have to pass
-% the now split \kv\ pair on to |\ekv@set@pair|.
-% \begin{macrocode}
-\ekv@exparg
- {\long\def\ekv@set@eq@active@##1\ekv@stop##2\ekv@nil#2\ekv@mark\ekv@set@noeq}%
- {\ekv@strip{##1}{\expandafter\ekv@set@pair\detokenize}\ekv@mark##2\ekv@nil}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@set@noeq}
-% If no active equal sign was found by |\ekv@set@eq@active| there is no equal
-% sign contained in the parsed list entry. In that case we have to check
-% whether the entry is blank in order to ignore it (in which case we'll have
-% to gobble the set-name which was put after these tests by |\ekv@set@other|).
-% Else this is a |NoVal| key and the entry is passed on to |\ekv@set@key|.
-% \begin{macrocode}
-\edef\ekv@set@noeq
- {%
- \ekv@unexpanded
- {%
- \ekv@ifblank@##1\ekv@nil\ekv@ifempty@B\ekv@set@was@blank
- \ekv@ifempty@A\ekv@ifempty@B
- }%
- \ekv@unexpanded\expandafter
- {\ekv@strip{##1}{\expandafter\ekv@set@key\detokenize}\ekv@mark}%
- }
-\ekv@exparg
- {%
- \long\def\ekv@set@noeq
- ##1\ekv@nil\ekv@mark\ekv@set@eq@active@\ekv@stop\ekv@mark
- }%
- {\ekv@set@noeq}
-\expandafter\def\expandafter\ekv@set@was@blank
- \expandafter\ekv@ifempty@A\expandafter\ekv@ifempty@B
- \ekv@strip{\ekv@mark##1}##2\ekv@mark
- {\ekv@set@other}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@endset@other}
-% All that's left for |\ekv@set@other| is the macro which breaks the recursion
-% loop at the end. This is done by gobbling all the remaining tokens.
-% \begin{macrocode}
-\long\def\ekv@endset@other
- \ekv@stop
- \ekv@eq@other\ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@set@eq@other@a
- =\ekv@mark\ekv@set@eq@active
- {\ekv@set}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvbreak,\ekvbreakPreSneak,\ekvbreakPostSneak}
-% Provide macros that can completely stop the parsing of |\ekvset|, who knows
-% what it'll be useful for.
-% \begin{macrocode}
-\long\def\ekvbreak##1##2\ekv@stop#1##3{##1}
-\long\def\ekvbreakPreSneak ##1##2\ekv@stop#1##3{##1##3}
-\long\def\ekvbreakPostSneak##1##2\ekv@stop#1##3{##3##1}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvsneak,\ekvsneakPre}
-% One last thing we want to do for |\ekvset| is to provide macros that just
-% smuggle stuff after |\ekvset|'s effects.
-% \begin{macrocode}
-\long\def\ekvsneak##1##2\ekv@stop#1##3{##2\ekv@stop#1{##3##1}}
-\long\def\ekvsneakPre##1##2\ekv@stop#1##3{##2\ekv@stop#1{##1##3}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvparse}
-% Additionally to the |\ekvset| macro we also want to provide an |\ekvparse|
-% macro, that has the same scope as |\keyval_parse:NNn| from \pkg{expl3}.
-% This is pretty analogue to the |\ekvset| implementation, we just put an
-% |\unexpanded| here and there instead of other macros to stop the |\expanded|
-% on our output. The |\unexpanded\expanded{{...}}| ensures that the material
-% is in an alignment safe group at all time, and that it doesn't expand any
-% further in an |\edef| or |\expanded| context.
-% \begin{macrocode}
-\long\def\ekvparse##1##2##3%
- {%
- \ekv@unexpanded\ekv@expanded
- {{\ekv@parse{##1}{##2}\ekv@mark##3#1\ekv@stop#1}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@parse}
-% \begin{macrocode}
-\long\def\ekv@parse##1##2##3#1%
- {%
- \ekv@gobble@from@mark@to@stop##3\ekv@endparse\ekv@stop
- \ekv@parse@other{##1}{##2}##3,\ekv@stop,%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@endparse}
-% \begin{macrocode}
-\long\def\ekv@endparse
- \ekv@stop\ekv@parse@other##1\ekv@mark\ekv@stop,\ekv@stop,%
- {}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@parse@other}
-% \begin{macrocode}
-\long\def\ekv@parse@other##1##2##3,%
- {%
- \ekv@gobble@from@mark@to@stop##3\ekv@endparse@other\ekv@stop
- \ekv@eq@other##3\ekv@nil\ekv@mark\ekv@parse@eq@other@a
- =\ekv@mark\ekv@parse@eq@active
- {##1}{##2}%
- \ekv@mark
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@parse@eq@other@a,\ekv@parse@eq@other@b}
-% \begin{macrocode}
-\long\def\ekv@parse@eq@other@a##1\ekv@stop
- {%
- \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active
- #2\ekv@mark\ekv@parse@eq@other@b
- }
-\ekv@exparg
- {%
- \long\def\ekv@parse@eq@other@b
- ##1\ekv@nil\ekv@mark\ekv@parse@eq@other@active\ekv@stop\ekv@mark
- ##2\ekv@nil=\ekv@mark\ekv@parse@eq@active
- }%
- {\ekv@strip{##1}\ekv@parse@pair##2\ekv@nil}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@parse@eq@other@active}
-% \begin{macrocode}
-\ekv@exparg
- {%
- \long\def\ekv@parse@eq@other@active
- ##1\ekv@stop##2\ekv@nil#2\ekv@mark
- \ekv@parse@eq@other@b\ekv@mark##3=\ekv@mark\ekv@parse@eq@active
- }%
- {\ekv@strip{##1}\ekv@parse@pair##2=##3}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@parse@eq@active,\ekv@parse@eq@active@}
-% \begin{macrocode}
-\long\def\ekv@parse@eq@active
- ##1\ekv@nil\ekv@mark\ekv@parse@eq@other@a\ekv@stop\ekv@mark
- {%
- \ekv@eq@active##1\ekv@nil\ekv@mark\ekv@parse@eq@active@
- #2\ekv@mark\ekv@parse@noeq
- }
-\ekv@exparg
- {\long\def\ekv@parse@eq@active@##1\ekv@stop##2#2\ekv@mark\ekv@parse@noeq}%
- {\ekv@strip{##1}\ekv@parse@pair##2}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@parse@noeq}
-% \begin{macrocode}
-\edef\ekv@parse@noeq
- {%
- \ekv@unexpanded
- {%
- \ekv@ifblank@##1\ekv@nil\ekv@ifempty@B\ekv@parse@was@blank
- \ekv@ifempty@A\ekv@ifempty@B
- }%
- \ekv@unexpanded\expandafter{\ekv@strip{##1}\ekv@parse@key}%
- }
-\ekv@exparg
- {%
- \long\def\ekv@parse@noeq
- ##1\ekv@nil\ekv@mark\ekv@parse@eq@active@\ekv@stop\ekv@mark
- }%
- {\ekv@parse@noeq}
-\expandafter\def\expandafter\ekv@parse@was@blank
- \expandafter\ekv@ifempty@A\expandafter\ekv@ifempty@B
- \ekv@strip{\ekv@mark##1}\ekv@parse@key
- {\ekv@parse@other}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@endparse@other}
-% \begin{macrocode}
-\long\def\ekv@endparse@other
- \ekv@stop
- \ekv@eq@other\ekv@mark\ekv@stop\ekv@nil\ekv@mark\ekv@parse@eq@other@a
- =\ekv@mark\ekv@parse@eq@active
- {\ekv@parse}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@parse@pair,\ekv@parse@pair@}
-% \begin{macrocode}
-\ekv@exparg{\long\def\ekv@parse@pair##1##2\ekv@nil}%
- {\ekv@strip{##2}\ekv@parse@pair@{##1}}
-\long\def\ekv@parse@pair@##1##2##3##4%
- {%
- \ekv@unexpanded{##4{##2}{##1}}%
- \ekv@parse@other{##3}{##4}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@parse@key}
-% \begin{macrocode}
-\long\def\ekv@parse@key##1##2%
- {%
- \ekv@unexpanded{##2{##1}}%
- \ekv@parse@other{##2}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% Finally really setting things up with |\ekvset|'s temporary meaning:
-% \begin{macrocode}
-}
-\catcode`\,=13
-\catcode`\==13
-\ekvset,=
-% \end{macrocode}
-%
-% \begin{macro}{\ekvsetSneaked}
-% This macro can be defined just by expanding |\ekvsneak| once after expanding
-% |\ekvset|. To expand everything as much as possible early on we use a
-% temporary definition.
-% \begin{macrocode}
-\edef\ekvsetSneaked
- {%
- \ekv@unexpanded{\ekvsneak{#2}}%
- \ekv@unexpanded\expandafter{\ekvset{#1}{#3}}%
- }
-\ekv@expargtwice{\long\def\ekvsetSneaked#1#2#3}{\ekvsetSneaked}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvchangeset}
-% Provide a macro that is able to switch out the current \set\ in |\ekvset|.
-% This operation allows something similar to \pkg{pgfkeys}'s
-% \texttt{\meta{key}/.cd} mechanism. However this operation can be more
-% expensive than |/.cd| as we can't just redefine some token to reflect this,
-% but have to switch out the set expandably, so this works similar to the
-% |\ekvsneak| macros reading and reinserting things, but it only has to read and
-% reinsert the remainder of the current key's replacement code.
-% \begin{macrocode}
-\ekv@exparg{\def\ekvchangeset#1}%
- {%
- \expandafter\expandafter\expandafter
- \ekv@changeset\expandafter\csname\ekv@undefined@set{#1}\endcsname\ekv@empty
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@changeset}
-% This macro does the real change-out of |\ekvchangeset|. |#2| will have a
-% leading |\ekv@empty| so that braces aren't stripped accidentally, but that
-% will not hurt and just expand to nothing in one step.
-% \begin{macrocode}
-\long\def\ekv@changeset#1#2\ekv@set@other#3{#2\ekv@set@other#1}
-% \end{macrocode}
-% \end{macro}
-%
-%
-% \begin{macro}[internal]
-% {
-% \ekv@set@pair,\ekv@set@pair@a,\ekv@set@pair@b,\ekv@set@pair@c,
-% \ekv@set@pair@d,\ekv@set@pair@e
-% }
-% |\ekv@set@pair| gets invoked with the space and brace stripped and
-% |\detokenize|d key-name as its first, the value as the second, and the set
-% name as the third argument. It provides tests for the key-macros and
-% everything to be able to throw meaningful error messages if it isn't
-% defined. We have two routes here, one if |\lastnamedcs| is defined and one
-% if it isn't. The big difference is that if it is we can omit a |\csname| and
-% instead just expand |\lastnamedcs| once to get the control sequence.
-% If the macro is defined the value will be space and brace stripped and the
-% key-macro called. Else branch into the error handling provided by
-% |\ekv@set@pair|.
-% \begin{macrocode}
-\ekv@if@lastnamedcs
- {%
- \long\def\ekv@set@pair#1\ekv@mark#2\ekv@nil#3%
- {%
- \ifcsname #3{#1}\endcsname\ekv@set@pair@a\fi\@secondoftwo
- {#2}%
- {%
- \ifcsname #3{}u\endcsname\ekv@set@pair@a\fi\@secondoftwo
- {#2}%
- {%
- \ekv@ifdefined{#3{#1}N}%
- \ekv@err@noarg
- \ekv@err@unknown
- #3%
- }%
- {#1}%
- }%
- \ekv@set@other#3%
- }
- \def\ekv@set@pair@a\fi\@secondoftwo
- {\fi\expandafter\ekv@set@pair@b\lastnamedcs}
- }
- {%
- \long\def\ekv@set@pair#1\ekv@mark#2\ekv@nil#3%
- {%
- \ifcsname #3{#1}\endcsname
- \ekv@set@pair@a\fi\ekv@set@pair@c#3{#1}\endcsname
- {#2}%
- {%
- \ifcsname #3{}u\endcsname
- \ekv@set@pair@a\fi\ekv@set@pair@c#3{}u\endcsname
- {#2}%
- {%
- \ekv@ifdefined{#3{#1}N}%
- \ekv@err@noarg
- \ekv@err@unknown
- #3%
- }%
- {#1}%
- }%
- \ekv@set@other#3%
- }
- \def\ekv@set@pair@a\fi\ekv@set@pair@c{\fi\expandafter\ekv@set@pair@b\csname}
- \long\def\ekv@set@pair@c#1\endcsname#2#3{#3}
- }
-\long\def\ekv@set@pair@b#1%
- {%
- \ifx#1\relax
- \ekv@set@pair@e
- \fi
- \ekv@set@pair@d#1%
- }
-\ekv@exparg{\long\def\ekv@set@pair@d#1#2#3}{\ekv@strip{#2}#1}
-\long\def\ekv@set@pair@e\fi\ekv@set@pair@d#1#2#3{\fi#3}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {\ekv@set@key,\ekv@set@key@a,\ekv@set@key@b,\ekv@set@key@c}
-% Analogous to |\ekv@set@pair|, |\ekv@set@key| builds the |NoVal| key-macro and
-% provides an error-branch. |\ekv@set@key@| will test whether the key-macro is
-% defined and if so call it, else the errors are thrown.
-% \begin{macrocode}
-\ekv@if@lastnamedcs
- {%
- \long\def\ekv@set@key#1\ekv@mark#2%
- {%
- \ifcsname #2{#1}N\endcsname\ekv@set@key@a\fi\@firstofone
- {%
- \ifcsname #2{}uN\endcsname\ekv@set@key@a\fi\@firstofone
- {%
- \ekv@ifdefined{#2{#1}}%
- \ekv@err@reqval
- \ekv@err@unknown
- #2%
- }%
- {#1}%
- }%
- \ekv@set@other#2%
- }
- \def\ekv@set@key@a\fi\@firstofone{\fi\expandafter\ekv@set@key@b\lastnamedcs}
- }
- {%
- \long\def\ekv@set@key#1\ekv@mark#2%
- {%
- \ifcsname #2{#1}N\endcsname
- \ekv@set@key@a\fi\ekv@set@key@c#2{#1}N\endcsname
- {%
- \ifcsname #2{}uN\endcsname
- \ekv@set@key@a\fi\ekv@set@key@c#2{}uN\endcsname
- {%
- \ekv@ifdefined{#2{#1}}%
- \ekv@err@reqval
- \ekv@err@unknown
- #2%
- }%
- {#1}%
- }%
- \ekv@set@other#2%
- }
- \def\ekv@set@key@a\fi\ekv@set@key@c{\fi\expandafter\ekv@set@key@b\csname}
- \long\def\ekv@set@key@c#1N\endcsname#2{#2}
- }
-\long\def\ekv@set@key@b#1%
- {%
- \ifx#1\relax
- \ekv@fi@secondoftwo
- \fi
- \@firstoftwo#1%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvsetdef}
-% Provide a macro to define a shorthand to use |\ekvset| on a specified \set.
-% To gain the maximum speed |\ekvset| is expanded twice by
-% |\ekv@exparg| so that during runtime the macro storing the set name
-% is already built and one |\expandafter| doesn't have to be used.
-% \begin{macrocode}
-\ekv@expargtwice{\protected\def\ekvsetdef#1#2}%
- {%
- \romannumeral
- \ekv@exparg{\ekv@zero\ekv@exparg{\long\def#1##1}}%
- {\ekvset{#2}{##1}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvsetSneakeddef,\ekvsetdefSneaked}
-% And do the same for |\ekvsetSneaked| in the two possible ways, with a fixed
-% sneaked argument and with a flexible one.
-% \begin{macrocode}
-\ekv@expargtwice{\protected\def\ekvsetSneakeddef#1#2}%
- {%
- \romannumeral
- \ekv@exparg{\ekv@zero\ekv@exparg{\long\def#1##1##2}}%
- {\ekvsetSneaked{#2}{##1}{##2}}%
- }
-\ekv@expargtwice{\protected\def\ekvsetdefSneaked#1#2#3}%
- {%
- \romannumeral
- \ekv@exparg{\ekv@zero\ekv@exparg{\long\def#1##1}}%
- {\ekvsetSneaked{#2}{#3}{##1}}%
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@alignsafe,\ekv@endalignsafe}
-% These macros protect the usage of ampersands inside of alignment contexts.
-% \begin{macrocode}
-\begingroup
-\catcode`\^^@=2
-\@firstofone{\endgroup
- \def\ekv@alignsafe{\romannumeral\iffalse{\fi`^^@ }
-}
-\def\ekv@endalignsafe{\ifnum`{=\ekv@zero}\fi}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekvoptarg,\ekvoptargTF}
-% Provide macros to expandably collect an optional argument in brackets. The
-% macros here are pretty simple in nature compared to \pkg{xparse}'s
-% possibilities (they don't care for nested bracket levels).
-%
-% We start with a temporary definition to pre-expand |\ekv@alignsafe| (will be
-% |#1|) and |\ekv@endalignsafe| (will be |#2|). As |\ekv@alignsafe| starts with
-% a |\romannumeral| we use that to also control the number of steps needed
-% instead of adding another |\romannumeral|. For this we have to remove the
-% space token from the end of |\ekv@alignsafe|'s definition.
-% \begin{macrocode}
-\begingroup
-\def\ekvoptarg#1#2{%
-\endgroup
-% \end{macrocode}
-% The real definition starts an expansion context and afterwards grabs the
-% arguments. |#1| will be the next step, |#2| the default value, and |#3| might
-% be an opening bracket, or the mandatory argument. We check for the opening
-% bracket, if it is found grab the optional argument, else leave |#1{#2}| in the
-% input stream after ending the expansion context.
-% \begin{macrocode}
-\def\ekvoptarg{#1\ekv@optarg@a}
-\long\def\ekv@optarg@a##1##2##3%
- {%
- \ekv@optarg@if\ekv@mark##3\ekv@mark\ekv@optarg@b\ekv@mark[\ekv@mark
- #2%
- \@firstofone{ ##1}{##2}{##3}%
- }%
-% \end{macrocode}
-% The other variant of this will do roughly the same. Here, |#1| will be the
-% next step if an optional argument is found, |#2| the next step else, and |#3|
-% might be the opening bracket or mandatory argument.
-% \begin{macrocode}
-\def\ekvoptargTF{#1\ekv@optargTF@a}
-\long\def\ekv@optargTF@a##1##2##3%
- {%
- \ekv@optarg@if\ekv@mark##3\ekv@mark\ekv@optargTF@b{##1}\ekv@mark[\ekv@mark
- #2%
- \@firstofone{ ##2}{##3}%
- }
-% \end{macrocode}
-% The two macros to grab the optional argument have to remove the remainder of
-% the test and the wrong next step as well as grabbing the argument.
-% \begin{macrocode}
-\long\def\ekv@optarg@b\ekv@mark[\ekv@mark\ifnum`##1\fi\@firstofone##2##3##4##5]%
- {#2##2{##5}}
-\long\def\ekv@optargTF@b
- ##1\ekv@mark[\ekv@mark\ifnum`##2\fi\@firstofone##3##4##5]%
- {#2 ##1{##5}}
-}
-% \end{macrocode}
-% Do the definitions and add the test macro. We use |\ekv@strip| to remove the
-% trailing space from the definition of |\ekv@alignsafe|.
-% \begin{macrocode}
-\ekv@exparg
- {%
- \expandafter\ekv@strip\expandafter
- {\expandafter\ekv@mark\ekv@alignsafe}%
- \ekvoptarg
- }%
- \ekv@endalignsafe
-\long\def\ekv@optarg@if#1\ekv@mark[\ekv@mark{}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\ekverr}
-% \begin{macro}[internal]{\ekv@err@collect,\ekv@err@cleanup}
-% Since |\ekvset| is fully expandable as long as the code of the keys is (which
-% is unlikely) we want to somehow throw expandable errors, in our case via
-% a runaway argument (to my knowledge the first version of this method was
-% implemented by Jean-François Burnol, many thanks to him). The first step is to
-% ensure that the second argument (which might contain user input) doesn't
-% contain tokens we use as delimiters (in this case |\par|), this will be done
-% by the front facing macro |\ekverr|. But first we set some other things up.
-%
-% We use a temporary definition for |\ekverr| to get multiple consecutive
-% spaces. Then we set up the macro that will collect the error and the macro
-% that will throw the error. The latter will have an unreasonable long name.
-% This way we can convey more information. Though the information in the macro
-% name is static and has to be somewhat general to fit every occurence. The
-% important bit is that the long named macro has a delimited argument and is
-% short which will throw the error at the |\par| at the end of
-% |\ekv@err@collect|. This macro has the drawback that it will only print nicely
-% if the |\newlinechar| is |^^J|.
-% \begin{macrocode}
-\def\ekv@err@cleanup\par{}
-\def\ekv@err@collect#1%
- {%
- \def\ekv@err@collect##1\par##2%
- {%
- \expandafter
- \ekv@err@cleanup
- #1! ##2 Error: ##1\par
- }%
- \def#1##1\thanks@jfbu{}%
- }
-\def\ekverr{ }
-\expandafter\ekv@err@collect\csname <an-expandable-macro>^^J%
- completed due to above exception. \ekverr If the error^^J%
- summary is \ekverr not comprehensible \ekverr see the package^^J%
- documentation.^^J%
- I will try to recover now. \ekverr If you're in inter-^^J%
- active mode hit <return> \ekverr at the ? prompt and I^^J%
- continue hoping recovery\endcsname
-% \end{macrocode}
-% \begin{macrocode}
-\long\def\ekverr#1#2{\expandafter\ekv@err@collect\detokenize{#2}\par{#1}}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[internal]{\ekv@err}
-% We define a shorthand to throw errors in \expkv.
-% \begin{macrocode}
-\ekv@exparg{\long\def\ekv@err#1}{\ekverr{expkv}{#1}}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[internal]
-% {
-% \ekv@err@common,\ekv@err@common@,
-% \ekv@err@unknown,\ekv@err@noarg,\ekv@err@reqval
-% }
-% Now we can use |\ekv@err| to set up some error messages so that we can later
-% use those instead of the full strings.
-% \begin{macrocode}
-\long\def\ekv@err@common #1#2{\expandafter\ekv@err@common@\string#2{#1}}
-\ekv@exparg{\long\def\ekv@err@common@#1`#2' #3.#4#5}%
- {\ekv@err{#4 `#5' in set `#2'}}
-\ekv@exparg{\long\def\ekv@err@unknown#1}{\ekv@err@common{unknown key}{#1}}
-\ekv@exparg{\long\def\ekv@err@noarg #1}
- {\ekv@err@common{unwanted value for}{#1}}
-\ekv@exparg{\long\def\ekv@err@reqval #1}{\ekv@err@common{missing value for}{#1}}
-\ekv@exparg{\long\def\ekv@err@redirect@kv@notfound#1#2#3\ekv@stop}%
- {\ekv@err{no key `#2' in sets #3}}
-\ekv@exparg{\def\ekv@err@redirect@k@notfound#1#2\ekv@stop}%
- {\ekv@err{no NoVal key `#1' in sets #2}}
-% \end{macrocode}
-% \end{macro}
-%
-% Now everything that's left is to reset the category code of |@|.
-% \begin{macrocode}
-\catcode`\@=\ekv@tmp
-% \end{macrocode}
-%
-% \gobbledocstriptag
-%</tex>
-%^^A=<<
-%
-%^^A=<<
-%
-% \end{implementation}^^A=<<
-%
-% \clearpage
-% \PrintIndex
-%
-\endinput
-%
-^^A vim: ft=tex fdm=marker fmr=>>=,=<<
diff --git a/macros/generic/expkv/expkv.pdf b/macros/generic/expkv/expkv.pdf
deleted file mode 100644
index 2da6f6dada..0000000000
--- a/macros/generic/expkv/expkv.pdf
+++ /dev/null
Binary files differ