From a00717063b7dce37451cdcfc2e4f45517467a484 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Tue, 17 Dec 2019 23:22:24 +0000 Subject: kvsetkeys split from oberdiek (18dec19) git-svn-id: svn://tug.org/texlive/trunk@53166 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/doc/latex/kvsetkeys/README.md | 11 + .../doc/latex/kvsetkeys/kvsetkeys-example.tex | 93 ++ .../texmf-dist/doc/latex/kvsetkeys/kvsetkeys.pdf | Bin 0 -> 374946 bytes .../source/latex/kvsetkeys/kvsetkeys.dtx | 1676 ++++++++++++++++++++ .../texmf-dist/tex/generic/kvsetkeys/kvsetkeys.sty | 573 +++++++ Master/tlpkg/bin/tlpkg-ctan-check | 2 +- Master/tlpkg/tlpsrc/collection-latex.tlpsrc | 1 + Master/tlpkg/tlpsrc/kvsetkeys.tlpsrc | 0 8 files changed, 2355 insertions(+), 1 deletion(-) create mode 100644 Master/texmf-dist/doc/latex/kvsetkeys/README.md create mode 100644 Master/texmf-dist/doc/latex/kvsetkeys/kvsetkeys-example.tex create mode 100644 Master/texmf-dist/doc/latex/kvsetkeys/kvsetkeys.pdf create mode 100644 Master/texmf-dist/source/latex/kvsetkeys/kvsetkeys.dtx create mode 100644 Master/texmf-dist/tex/generic/kvsetkeys/kvsetkeys.sty create mode 100644 Master/tlpkg/tlpsrc/kvsetkeys.tlpsrc diff --git a/Master/texmf-dist/doc/latex/kvsetkeys/README.md b/Master/texmf-dist/doc/latex/kvsetkeys/README.md new file mode 100644 index 00000000000..a7e822fa0fa --- /dev/null +++ b/Master/texmf-dist/doc/latex/kvsetkeys/README.md @@ -0,0 +1,11 @@ +# kvsetkeys + +kvsetkeys package for LaTeX + + +Package kvsetkeys provides kvsetkeys, a variant +of package keyval's \cs{setkeys}. It allows to specify +a handler that deals with unknown options. Active commas and equal +signs may be used (e.g. see babel's shorthands) and +only one level of curly braces is removed from the values. + diff --git a/Master/texmf-dist/doc/latex/kvsetkeys/kvsetkeys-example.tex b/Master/texmf-dist/doc/latex/kvsetkeys/kvsetkeys-example.tex new file mode 100644 index 00000000000..ad6033d04bd --- /dev/null +++ b/Master/texmf-dist/doc/latex/kvsetkeys/kvsetkeys-example.tex @@ -0,0 +1,93 @@ +%% +%% This is file `kvsetkeys-example.tex', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% kvsetkeys.dtx (with options: `example') +%% +%% This is a generated file. +%% +%% Project: kvsetkeys +%% Version: 2019/12/15 v1.18 +%% +%% Copyright (C) +%% 2006, 2007, 2009-2012 Heiko Oberdiek +%% 2016-2019 Oberdiek Package Support Group +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either +%% version 1.3c of this license or (at your option) any later +%% version. This version of this license is in +%% https://www.latex-project.org/lppl/lppl-1-3c.txt +%% and the latest version of this license is in +%% https://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of +%% LaTeX version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status "maintained". +%% +%% The Current Maintainers of this work are +%% Heiko Oberdiek and the Oberdiek Package Support Group +%% https://github.com/ho-tex/kvsetkeys/issues +%% +%% +%% The Base Interpreter refers to any `TeX-Format', +%% because some files are installed in TDS:tex/generic//. +%% +%% This work consists of the main source file kvsetkeys.dtx +%% and the derived files +%% kvsetkeys.sty, kvsetkeys.pdf, kvsetkeys.ins, kvsetkeys.drv, +%% kvsetkeys-example.tex, kvsetkeys-test1.tex, +%% kvsetkeys-test2.tex, kvsetkeys-test3.tex, +%% kvsetkeys-test4.tex. +%% +\documentclass{article} +\usepackage[T1]{fontenc} +\usepackage{kvsetkeys} +\usepackage{keyval} + +\makeatletter +\newcommand*{\tag}[2][]{% + % #1: attributes + % #2: tag name + \begingroup + \toks@={}% + \let\@endslash\@empty + \kvsetkeys{tag}{#1}% + \texttt{% + \textless #2\the\toks@\@endslash\textgreater + }% + \endgroup +} +\kv@set@family@handler{tag}{% + % #1: key + % #2: value + \toks@\expandafter{% + \the\toks@ + \space + #1=\string"#2\string"% + }% +} +\define@key{tag}{/}[]{% + \def\@endslash{/}% +} +\makeatother + +\begin{document} +\begin{tabbing} + \mbox{}\qquad\=\qquad\=\kill + \tag{html}\\ + \>\dots\\ + \>\tag[border=1]{table}\\ + \>\>\tag[width=200, span=3, /]{colgroup}\\ + \>\>\dots\\ + \>\tag{/table}\\ + \>\dots\\ + \tag{/html}\\ +\end{tabbing} +\end{document} +%% \section{Installation} +\endinput +%% +%% End of file `kvsetkeys-example.tex'. diff --git a/Master/texmf-dist/doc/latex/kvsetkeys/kvsetkeys.pdf b/Master/texmf-dist/doc/latex/kvsetkeys/kvsetkeys.pdf new file mode 100644 index 00000000000..7d4a72c04ff Binary files /dev/null and b/Master/texmf-dist/doc/latex/kvsetkeys/kvsetkeys.pdf differ diff --git a/Master/texmf-dist/source/latex/kvsetkeys/kvsetkeys.dtx b/Master/texmf-dist/source/latex/kvsetkeys/kvsetkeys.dtx new file mode 100644 index 00000000000..c04507c2973 --- /dev/null +++ b/Master/texmf-dist/source/latex/kvsetkeys/kvsetkeys.dtx @@ -0,0 +1,1676 @@ +% \iffalse meta-comment +% +% File: kvsetkeys.dtx +% Version: 2019/12/15 v1.18 +% Info: Key value parser +% +% Copyright (C) +% 2006, 2007, 2009-2012 Heiko Oberdiek +% 2016-2019 Oberdiek Package Support Group +% https://github.com/ho-tex/kvsetkeys/issues +% +% This work may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either +% version 1.3c of this license or (at your option) any later +% version. This version of this license is in +% https://www.latex-project.org/lppl/lppl-1-3c.txt +% and the latest version of this license is in +% https://www.latex-project.org/lppl.txt +% and version 1.3 or later is part of all distributions of +% LaTeX version 2005/12/01 or later. +% +% This work has the LPPL maintenance status "maintained". +% +% The Current Maintainers of this work are +% Heiko Oberdiek and the Oberdiek Package Support Group +% https://github.com/ho-tex/kvsetkeys/issues +% +% The Base Interpreter refers to any `TeX-Format', +% because some files are installed in TDS:tex/generic//. +% +% This work consists of the main source file kvsetkeys.dtx +% and the derived files +% kvsetkeys.sty, kvsetkeys.pdf, kvsetkeys.ins, kvsetkeys.drv, +% kvsetkeys-example.tex, kvsetkeys-test1.tex, +% kvsetkeys-test2.tex, kvsetkeys-test3.tex, +% kvsetkeys-test4.tex. +% +% Distribution: +% CTAN:macros/latex/contrib/kvsetkeys/kvsetkeys.dtx +% CTAN:macros/latex/contrib/kvsetkeys/kvsetkeys.pdf +% +% Unpacking: +% (a) If kvsetkeys.ins is present: +% tex kvsetkeys.ins +% (b) Without kvsetkeys.ins: +% tex kvsetkeys.dtx +% (c) If you insist on using LaTeX +% latex \let\install=y\input{kvsetkeys.dtx} +% (quote the arguments according to the demands of your shell) +% +% Documentation: +% (a) If kvsetkeys.drv is present: +% latex kvsetkeys.drv +% (b) Without kvsetkeys.drv: +% latex kvsetkeys.dtx; ... +% The class ltxdoc loads the configuration file ltxdoc.cfg +% if available. Here you can specify further options, e.g. +% use A4 as paper format: +% \PassOptionsToClass{a4paper}{article} +% +% Programm calls to get the documentation (example): +% pdflatex kvsetkeys.dtx +% makeindex -s gind.ist kvsetkeys.idx +% pdflatex kvsetkeys.dtx +% makeindex -s gind.ist kvsetkeys.idx +% pdflatex kvsetkeys.dtx +% +% Installation: +% TDS:tex/generic/kvsetkeys/kvsetkeys.sty +% TDS:doc/latex/kvsetkeys/kvsetkeys.pdf +% TDS:doc/latex/kvsetkeys/kvsetkeys-example.tex +% TDS:source/latex/kvsetkeys/kvsetkeys.dtx +% +%<*ignore> +\begingroup + \catcode123=1 % + \catcode125=2 % + \def\x{LaTeX2e}% +\expandafter\endgroup +\ifcase 0\ifx\install y1\fi\expandafter + \ifx\csname processbatchFile\endcsname\relax\else1\fi + \ifx\fmtname\x\else 1\fi\relax +\else\csname fi\endcsname +% +%<*install> +\input docstrip.tex +\Msg{************************************************************************} +\Msg{* Installation} +\Msg{* Package: kvsetkeys 2019/12/15 v1.18 Key value parser (HO)} +\Msg{************************************************************************} + +\keepsilent +\askforoverwritefalse + +\let\MetaPrefix\relax +\preamble + +This is a generated file. + +Project: kvsetkeys +Version: 2019/12/15 v1.18 + +Copyright (C) + 2006, 2007, 2009-2012 Heiko Oberdiek + 2016-2019 Oberdiek Package Support Group + +This work may be distributed and/or modified under the +conditions of the LaTeX Project Public License, either +version 1.3c of this license or (at your option) any later +version. This version of this license is in + https://www.latex-project.org/lppl/lppl-1-3c.txt +and the latest version of this license is in + https://www.latex-project.org/lppl.txt +and version 1.3 or later is part of all distributions of +LaTeX version 2005/12/01 or later. + +This work has the LPPL maintenance status "maintained". + +The Current Maintainers of this work are +Heiko Oberdiek and the Oberdiek Package Support Group +https://github.com/ho-tex/kvsetkeys/issues + + +The Base Interpreter refers to any `TeX-Format', +because some files are installed in TDS:tex/generic//. + +This work consists of the main source file kvsetkeys.dtx +and the derived files + kvsetkeys.sty, kvsetkeys.pdf, kvsetkeys.ins, kvsetkeys.drv, + kvsetkeys-example.tex, kvsetkeys-test1.tex, + kvsetkeys-test2.tex, kvsetkeys-test3.tex, + kvsetkeys-test4.tex. + +\endpreamble +\let\MetaPrefix\DoubleperCent + +\generate{% + \file{kvsetkeys.ins}{\from{kvsetkeys.dtx}{install}}% + \file{kvsetkeys.drv}{\from{kvsetkeys.dtx}{driver}}% + \usedir{tex/generic/kvsetkeys}% + \file{kvsetkeys.sty}{\from{kvsetkeys.dtx}{package}}% + \usedir{doc/latex/kvsetkeys}% + \file{kvsetkeys-example.tex}{\from{kvsetkeys.dtx}{example}}% +} + +\catcode32=13\relax% active space +\let =\space% +\Msg{************************************************************************} +\Msg{*} +\Msg{* To finish the installation you have to move the following} +\Msg{* file into a directory searched by TeX:} +\Msg{*} +\Msg{* kvsetkeys.sty} +\Msg{*} +\Msg{* To produce the documentation run the file `kvsetkeys.drv'} +\Msg{* through LaTeX.} +\Msg{*} +\Msg{* Happy TeXing!} +\Msg{*} +\Msg{************************************************************************} + +\endbatchfile +% +%<*ignore> +\fi +% +%<*driver> +\NeedsTeXFormat{LaTeX2e} +\ProvidesFile{kvsetkeys.drv}% + [2019/12/15 v1.18 Key value parser (HO)]% +\documentclass{ltxdoc} +\usepackage{holtxdoc}[2011/11/22] +\begin{document} + \DocInput{kvsetkeys.dtx}% +\end{document} +% +% \fi +% +% +% +% \GetFileInfo{kvsetkeys.drv} +% +% \title{The \xpackage{kvsetkeys} package} +% \date{2019/12/15 v1.18} +% \author{Heiko Oberdiek\thanks +% {Please report any issues at \url{https://github.com/ho-tex/kvsetkeys/issues}}} +% +% \maketitle +% +% \begin{abstract} +% Package \xpackage{kvsetkeys} provides \cs{kvsetkeys}, a variant +% of package \xpackage{keyval}'s \cs{setkeys}. It allows to specify +% a handler that deals with unknown options. Active commas and equal +% signs may be used (e.g. see \xpackage{babel}'s shorthands) and +% only one level of curly braces is removed from the values. +% \end{abstract} +% +% \tableofcontents +% +% \def\M#1{\texttt{\{}\meta{#1}\texttt{\}}} +% +% \section{Documentation} +% +% First I want to recommend the very good review article +% ``A guide to key-value methods'' by Joseph Wright \cite{tb94wright}. +% It introduces the different key-value packages and compares them. +% +% \subsection{Motivation} +% +% \cs{kvsetkeys} serves as replacement for \xpackage{keyval}'s +% \cs{setkeys}. It basically uses the same syntax. But the +% implementation is more robust and predictable: +% \begin{description} +% \item[Active syntax characters:] +% Comma `|,|' and the equals sign `|=|' are used inside +% key value lists as syntax characters. Package \xpackage{keyval} +% uses the catcode of the characters that is active during +% package loading, usually this is catcode 12 (other). +% But it can happen that the catcode setting of the syntax characters +% changes. Especially active characters are of interest, because +% some language adaptations uses them. For example, option \xoption{turkish} +% of package \xpackage{babel} uses the equals sign as active shorthand +% character. Therefore package \xpackage{kvsetkeys} deals with +% both catcode settings 12 (other) and 13 (active). +% \item[Brace removal:] +% Package \xpackage{keyval}'s \cs{setkeys} removes up to two +% levels of curly braces around the value in some unpredictable way: +%\begin{quote} +%|\setkeys{fam}{key={{value}}} || || | $\rightarrow$ |value|\\ +%|\setkeys{fam}{key={{{value}}}} | $\rightarrow$ |{value}|\\ +%|\setkeys{fam}{key= {{{value}}}}| $\rightarrow$ |{{value}}| +%\end{quote} +% This package \xpackage{kvsetkeys} follows a much stronger rule: +% Exactly one level of braces are removed from an item, if the +% item is surrounded by curly braces. An item can be a +% the key value pair, the key or the value. +%\begin{quote} +%|\kvsetkeys{fam}{key={value}} || | $\rightarrow$ |value|\\ +%|\kvsetkeys{fam}{key={{value}} | $\rightarrow$ |{value}|\\ +%|\kvsetkeys{fam}{key= {{value}}| $\rightarrow$ |{value}| +%\end{quote} +% \item[Arbitrary values:] Unmatched conditionals are supported. +% \end{description} +% +% Before I describe +% \cs{kvsetkeys} in more detail, first I want to explain, how +% this package deals with key value lists. For the package also +% provides low level interfaces that can be used by package authors. +% +% \subsection{Normalizing key value lists} +% +% \begin{declcs}{kv@normalize}\,\M{key value list} +% \end{declcs} +% If the user specifies key value lists, he usually prefers +% nice formatted source code, e.g.: +% \begin{quote} +%\begin{verbatim} +%\hypersetup{ +% pdftitle = {...}, +% pdfsubject = {...}, +% pdfauthor = {...}, +% pdfkeywords = {...}, +% ... +%} +%\end{verbatim} +% \end{quote} +% Thus there can be spaces around keys, around |=| or around the value. +% Also empty entries are possible by too many commas. Therefore these +% spaces and empty entries are silently removed by package \xpackage{keyval} +% and this package. Whereas the contents of the value can be protected +% by curly braces, especially if spaces or commas are used inside, +% a key name must not use spaces or other syntax characters. +% +% \cs{kv@normalize} takes a key value list and performs the cleanup: +% \begin{itemize} +% \item Spaces are removed. +% \item Syntax characters (comma and equal sign) that are active +% are replaced by the same characters with standard catcode. +% (Example: \xpackage{babel}'s language option \xoption{turkish} +% uses the equal sign as active shorthand character.) +% \end{itemize} +% The result is stored in \cs{kv@list}, e.g.: +% \begin{quote} +% |\kv@list| $\rightarrow$ |,pdftitle={...},pdfsubject={...},...,| +% \end{quote} +% Curly braces around values (or keys) remain untouched. +% \begin{description} +% \item[v1.3+:] +% One comma is added in front of the list and each pair ends with +% a comma. Thus an empty list consists of one comma, otherwise +% two commas encloses the list. Empty entries other than the first +% are removed. +% \item[v1.0 -- v1.2:] +% Empty entries are removed later. In fact it adds a comma at the begin +% and end to protect the last value and an easier implementation. +% \end{description} +% +% \subsection{Parsing key value lists} +% +% \begin{declcs}{kv@parse}\,\M{key value list}\,\M{processor} +% \end{declcs} +% It is easier to parse a normalized list, thus \cs{kv@parse} +% normalizes the list and calls \cs{kv@parse@normalized}. +% +% \begin{declcs}{kv@parse@normalized}\,\M{key value list}% +% \,\M{processor} +% \end{declcs} +% Now the key value list is split into single key value pairs. +% For further processing the key and value are given as arguments +% for the \meta{processor}: +% \begin{quote} +% \meta{processor}\,\M{key}\,\M{value} +% \end{quote} +% Also key and value are stored in macro names: +% \begin{itemize} +% \item \cs{kv@key} stores the key. +% \item \cs{kv@value} stores the value or if the value was not +% specified it has the meaning \cs{relax}. +% \end{itemize} +% The behaviour in pseudo code: +% \begin{quote} +% foreach (\meta{key}, \meta{value}) in (\meta{key value list})\\ +% \hspace*{1.5em}\cs{kv@key} := \meta{key}\\ +% \hspace*{1.5em}\cs{kv@value} := \meta{value}\\ +% \hspace*{1.5em}\meta{processor}\,\M{key}\,\M{value} +% \end{quote} +% +% \begin{declcs}{kv@break} +% \end{declcs} +% Since version 2011/03/03 v1.11 \cs{kv@break} can be +% called inside the \meta{processor} +% of \cs{kv@parse} or \cs{kv@parse@normalized}, then +% the processing is stopped and the following entries discarded. +% +% \subsection{Processing key value pairs} +% +% Key value pairs can be processed in many different ways. +% For example, the processor for \cs{kvsetkeys} works similar +% to \cs{setkeys} of package \xpackage{keyval}. There unknown +% keys raise an error. +% +% Package \xpackage{xkeyval} also knows a star form of \cs{setkeys} +% that stores unknown keys in an internal macro for further processing +% with \cs{setrmkeys} and similar macros. This feature is covered +% by processor \cs{kv@processor@known}. +% +% \subsubsection{Processing similar to \xpackage{keyval}} +% +% \begin{declcs}{kv@processor@default}\,\M{family}\,\M{key}\,\M{value} +% \end{declcs} +% There are many possiblities to process key value pairs. +% \cs{kv@processor@default} is the processor used in \cs{kvsetkeys}. +% It reimplements and extends the behaviour of +% \xpackage{keyval}'s \cs{setkeys}. +% In case of unknown keys \cs{setkeys} raise an error. +% This processer, however, calls a handler instead, if it +% is provided by the family. Both \meta{family} and \meta{key} +% may contain package \xpackage{babel}'s shorthands +% (since 2011/04/07 v1.13). +% +% Since 2011/10/18 v1.15 the family handler can reject the +% successful handling of a key by calling \cs{kv@handled@false}. +% +% Since 2019/12/15 v1.18 \cs{kv@processor@default} also defines +% macro \cs{kv@fam} with meaning \meta{family} for convenience. +% +% \subsubsection{Processing similar to \cs{setkeys*} of package \xpackage{xkeyval}} +% +% \begin{declcs}{kv@processor@known}\,\M{family}\,^^A +% \M{cmd}\,\M{key}\,\M{value} +% \end{declcs} +% The key value processor \cs{kv@processor@known} behaves similar +% to \cs{kv@processor@default}. If the \meta{key} exists in the +% \meta{family} its code is called, otherwise the family handler +% is tried. If the family handler is not set or cannot handle the +% key, the unknown key value pair is added to the macro \meta{cmd}. +% Since 2011/10/18 v1.15. +% +% The behaviour in pseudo code: +% \begin{quote} +% if \meta{key} exists\\ +% \hspace*{1.5em}call the keyval code of \meta{key}\\ +% else\\ +% \hspace*{1.5em}if \meta{handler} for \meta{family} exists\\ +% \hspace*{3em}handled = true\\ +% \hspace*{3em}\meta{handler}\,\M{key}\,\M{value}\\ +% \hspace*{3em}if handled\\ +% \hspace*{3em}else\\ +% \hspace*{4.5em}add \texttt{"}\M{key}\texttt{=}\M{value}\texttt{"} +% to \M{cmd}\\ +% \hspace*{3em}fi\\ +% \hspace*{1.5em}else\\ +% \hspace*{3em}add \texttt{"}\M{key}\texttt{=}\M{value}\texttt{"} +% to \M{cmd}\\ +% \hspace*{3em}raise unknown key error\\ +% \hspace*{1.5em}fi\\ +% fi +% \end{quote} +% +% Since 2019/12/15 v1.18 \cs{kv@processor@known} also defines +% macro \cs{kv@fam} with meaning \meta{family} for convenience. +% +% \subsection{Default family handler} +% +% \cs{kv@processor@default} calls \meta{handler}, the default +% handler for the family, if the key does not exist in the family. +% The handler is called with two arguments, the key and the value. +% It can be defined with \cs{kv@set@family@hander}: +% +% \begin{declcs}{kv@set@family@handler}\,\M{family}\,\M{handler definition} +% \end{declcs} +% This sets the default family handler for the keyval family +% \meta{family}. Inside \meta{handler definition} |#1| stands for +% the key and |#2| is the value. Also \cs{kv@key} and \cs{kv@value} +% can be used for the key and the value. If the value is not given, +% \cs{kv@value} has the meaning \cs{relax}. +% +% \begin{declcs}{kv@unset@family@handler}\,\M{family} +% \end{declcs} +% It removes the family handler for \meta{family}. +% Since 2011/10/18 v1.15. +% +% \subsection{Put it all together} +% +% \begin{declcs}{kvsetkeys}\,\M{family}\,\M{key value list} +% \end{declcs} +% Macro \cs{kvsetkeys} processes the \meta{key value list} with +% the standard processor \cs{kv@processor@default}: +% \begin{quote} +% \cs{kv@parse}\,\M{key value list}^^A +% \texttt{\{}\cs{kv@processor@default}\,\M{family}\texttt{\}} +% \end{quote} +% +% \begin{declcs}{kvsetknownkeys}\,\M{family}\,\M{cmd}\,\M{key value list} +% \end{declcs} +% Macro \cs{kvsetknownkeys} processes the \meta{key value list} +% with processor \cs{kv@processor@known}. All key value pairs +% with keys that are not known in \meta{family} are stored +% in macro \meta{cmd}. A previous contents of macro \meta{cmd} +% will be overwritten. If all keys can be handled, \meta{cmd} +% will be empty, otherwise it contains a key value list of +% unhandled key value pairs. +% Since 2011/10/18 v1.15. +% +% Pseudo code: +% \begin{quote} +% create macro \meta{cmdaux} with unique name (inside the current group)\\ +% \cs{def}\meta{cmdaux}\{\}\\ +% \cs{kv@parse}\,\M{key value list}^^A +% \texttt{\{}\cs{kv@processor@known}\,\M{family}\,\M{cmdaux}\texttt{\}}\\ +% \cs{let}\meta{cmd}=\meta{cmdaux} +% \end{quote} +% +% \begin{declcs}{kvsetkeys@expandafter}\,\M{family}\,\M{list cmd}\\ +% \cs{kvsetknownkeys@expandafter}\,\M{family}\,% +% \M{cmd}\,\M{list cmd} +% \end{declcs} +% Both macros behave like the counterparts without suffix +% |@expandafter|. The difference is that the key value list is +% given as macro that is expanded once. +% Since 2011/10/18 v1.15. +% +% Thus you can replace \cs{setkeys} of package \xpackage{keyval} +% by the key value parser of this package: +% \begin{quote} +% |\renewcommand*{\setkeys}{\kvsetkeys}|\\ +% or\\ +% |\let\setkeys\kvsetkeys| +% \end{quote} +% +% \subsection{Comma separated lists} +% +% Since version 2007/09/29 v1.3 this package also supports the normalizing +% and parsing of general comma separated lists. +% +% \begin{declcs}{comma@normalize}\,\M{comma list} +% \end{declcs} +% Macro \cs{comma@normalize} normalizes the comma separated list, +% removes spaces around commas. The result is put in macro \cs{comma@list}. +% +% \begin{declcs}{comma@parse}\,\M{comma list}\,\M{processor} +% \end{declcs} +% Macro \cs{comma@parse} first normalizes the comma separated list +% and then parses the list by calling \cs{comma@parse@normalized}. +% +% \begin{declcs}{comma@parse@normalized}\,\M{normalized comma list}^^A +% \,\M{processor} +% \end{declcs} +% The list is parsed. Empty entries are ignored. \meta{processor} +% is called for each non-empty entry with the entry as argument: +% \begin{quote} +% \meta{processor}|{|\meta{entry}|}| +% \end{quote} +% Also the entry is stored in the macro \cs{comma@entry}. +% +% \begin{declcs}{comma@break} +% \end{declcs} +% Since version 2011/03/03 v1.11 \cs{comma@break} can be +% called inside the \meta{processor} +% of \cs{comma@parse} or \cs{comma@parse@normalized}, then +% the processing is stopped and the following entries discarded. +% +% \section{Example} +% +% The following example prints a short piece of HTML code using +% the tabbing environment for indenting purpose and a key value +% syntax for specifying the attributes of an HTML tag. +% The example illustrates the use of a default family handler. +% \begin{macrocode} +%<*example> +\documentclass{article} +\usepackage[T1]{fontenc} +\usepackage{kvsetkeys} +\usepackage{keyval} + +\makeatletter +\newcommand*{\tag}[2][]{% + % #1: attributes + % #2: tag name + \begingroup + \toks@={}% + \let\@endslash\@empty + \kvsetkeys{tag}{#1}% + \texttt{% + \textless #2\the\toks@\@endslash\textgreater + }% + \endgroup +} +\kv@set@family@handler{tag}{% + % #1: key + % #2: value + \toks@\expandafter{% + \the\toks@ + \space + #1=\string"#2\string"% + }% +} +\define@key{tag}{/}[]{% + \def\@endslash{/}% +} +\makeatother + +\begin{document} +\begin{tabbing} + \mbox{}\qquad\=\qquad\=\kill + \tag{html}\\ + \>\dots\\ + \>\tag[border=1]{table}\\ + \>\>\tag[width=200, span=3, /]{colgroup}\\ + \>\>\dots\\ + \>\tag{/table}\\ + \>\dots\\ + \tag{/html}\\ +\end{tabbing} +\end{document} +% +% \end{macrocode} +% +% \StopEventually{ +% } +% +% \section{Implementation} +% +% \subsection{Identification} +% +% \begin{macrocode} +%<*package> +% \end{macrocode} +% Reload check, especially if the package is not used with \LaTeX. +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode35=6 % # + \catcode39=12 % ' + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \catcode64=11 % @ + \catcode123=1 % { + \catcode125=2 % } + \expandafter\let\expandafter\x\csname ver@kvsetkeys.sty\endcsname + \ifx\x\relax % plain-TeX, first loading + \else + \def\empty{}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \else + \expandafter\ifx\csname PackageInfo\endcsname\relax + \def\x#1#2{% + \immediate\write-1{Package #1 Info: #2.}% + }% + \else + \def\x#1#2{\PackageInfo{#1}{#2, stopped}}% + \fi + \x{kvsetkeys}{The package is already loaded}% + \aftergroup\endinput + \fi + \fi +\endgroup% +% \end{macrocode} +% Package identification: +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode35=6 % # + \catcode39=12 % ' + \catcode40=12 % ( + \catcode41=12 % ) + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode47=12 % / + \catcode58=12 % : + \catcode64=11 % @ + \catcode91=12 % [ + \catcode93=12 % ] + \catcode123=1 % { + \catcode125=2 % } + \expandafter\ifx\csname ProvidesPackage\endcsname\relax + \def\x#1#2#3[#4]{\endgroup + \immediate\write-1{Package: #3 #4}% + \xdef#1{#4}% + }% + \else + \def\x#1#2[#3]{\endgroup + #2[{#3}]% + \ifx#1\@undefined + \xdef#1{#3}% + \fi + \ifx#1\relax + \xdef#1{#3}% + \fi + }% + \fi +\expandafter\x\csname ver@kvsetkeys.sty\endcsname +\ProvidesPackage{kvsetkeys}% + [2019/12/15 v1.18 Key value parser (HO)]% +% \end{macrocode} +% +% \begin{macrocode} +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \def\x{\endgroup + \expandafter\edef\csname KVS@AtEnd\endcsname{% + \endlinechar=\the\endlinechar\relax + \catcode13=\the\catcode13\relax + \catcode32=\the\catcode32\relax + \catcode35=\the\catcode35\relax + \catcode61=\the\catcode61\relax + \catcode64=\the\catcode64\relax + \catcode123=\the\catcode123\relax + \catcode125=\the\catcode125\relax + }% + }% +\x\catcode61\catcode48\catcode32=10\relax% +\catcode13=5 % ^^M +\endlinechar=13 % +\catcode35=6 % # +\catcode64=11 % @ +\catcode123=1 % { +\catcode125=2 % } +\def\TMP@EnsureCode#1#2{% + \edef\KVS@AtEnd{% + \KVS@AtEnd + \catcode#1=\the\catcode#1\relax + }% + \catcode#1=#2\relax +} +\TMP@EnsureCode{36}{3}% $ +\TMP@EnsureCode{38}{4}% & +\TMP@EnsureCode{39}{12}% ' +\TMP@EnsureCode{43}{12}% + +\TMP@EnsureCode{44}{12}% , +\TMP@EnsureCode{45}{12}% - +\TMP@EnsureCode{46}{12}% . +\TMP@EnsureCode{47}{12}% / +\TMP@EnsureCode{91}{12}% [ +\TMP@EnsureCode{93}{12}% ] +\TMP@EnsureCode{94}{7}% ^ (superscript) +\TMP@EnsureCode{96}{12}% ` +\TMP@EnsureCode{126}{13}% ~ (active) +\edef\KVS@AtEnd{\KVS@AtEnd\noexpand\endinput} +% \end{macrocode} +% +% \subsection{Package loading} +% +% \begin{macrocode} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \def\TMP@RequirePackage#1[#2]{% + \begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname ver@#1.sty\endcsname\relax + \input #1.sty\relax + \fi + }% + \TMP@RequirePackage{infwarerr}[2007/09/09]% + \let\PackageError\@PackageError +\else +\fi +% \end{macrocode} +% +% \begin{macrocode} +\expandafter\ifx\csname toks@\endcsname\relax + \toksdef\toks@=0 % +\fi +% \end{macrocode} +% +% \subsection{Check for \eTeX} +% +% \cs{unexpanded}, \cs{ifcsname}, and \cs{unless} are used if found. +% \begin{macrocode} +\ifx\numexpr\@undefined + \catcode`\$=9 % ignore + \catcode`\&=14 % comment +\else % e-TeX + \catcode`\$=14 % comment + \catcode`\&=9 % ignore +\fi +% \end{macrocode} +% +% \subsection{Generic help macros} +% +% \begin{macro}{\KVS@Empty} +% \begin{macrocode} +\def\KVS@Empty{} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@FirstOfTwo} +% \begin{macrocode} +\long\def\KVS@FirstOfTwo#1#2{#1} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@SecondOfTwo} +% \begin{macrocode} +\long\def\KVS@SecondOfTwo#1#2{#2} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KVS@IfEmpty} +% \begin{macrocode} +\long\def\KVS@IfEmpty#1{% +& \edef\KVS@Temp{\unexpanded{#1}}% +$ \begingroup +$ \toks@{#1}% +$ \edef\KVS@Temp{\the\toks@}% +$ \expandafter\endgroup + \ifx\KVS@Temp\KVS@Empty + \expandafter\KVS@FirstOfTwo + \else + \expandafter\KVS@SecondOfTwo + \fi +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Normalizing} +% +% \begin{macro}{\kv@normalize} +% \begin{macrocode} +\long\def\kv@normalize#1{% + \begingroup + \toks@{,#1,}% + \KVS@Comma + \KVS@SpaceComma + \KVS@CommaSpace + \KVS@CommaComma + \KVS@Equals + \KVS@SpaceEquals + \KVS@EqualsSpace + \xdef\KVS@Global{\the\toks@}% + \endgroup + \let\kv@list\KVS@Global +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\comma@normalize} +% \begin{macrocode} +\def\comma@normalize#1{% + \begingroup + \toks@{,#1,}% + \KVS@Comma + \KVS@SpaceComma + \KVS@CommaSpace + \KVS@CommaComma + \xdef\KVS@Global{\the\toks@}% + \endgroup + \let\comma@list\KVS@Global +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@Comma} +% Converts active commas into comma with catcode other. +% Also adds a comma at the end to protect the last value +% for next cleanup steps. +% \begin{macrocode} +\begingroup + \lccode`\,=`\,% + \lccode`\~=`\,% +\lowercase{\endgroup + \def\KVS@Comma{% + \toks@\expandafter{\expandafter}\expandafter + \KVS@@Comma\the\toks@~\KVS@Nil + }% + \long\def\KVS@@Comma#1~#2\KVS@Nil{% + \toks@\expandafter{\the\toks@#1}% + \KVS@IfEmpty{#2}{% + }{% + \KVS@@Comma,#2\KVS@Nil + }% + }% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@SpaceComma} +% Removes spaces before the comma, may add commas at the end. +% \begin{macrocode} +\def\KVS@SpaceComma#1{% + \def\KVS@SpaceComma{% + \expandafter\KVS@@SpaceComma\the\toks@#1,\KVS@Nil + }% +} +\KVS@SpaceComma{ } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@@SpaceComma} +% \begin{macrocode} +\long\def\KVS@@SpaceComma#1 ,#2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1}% + }{% + \KVS@@SpaceComma#1,#2\KVS@Nil + }% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@CommaSpace} +% Removes spaces after the comma, may add commas at the end. +% \begin{macrocode} +\def\KVS@CommaSpace{% + \expandafter\KVS@@CommaSpace\the\toks@, \KVS@Nil +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@@CommaSpace} +% \begin{macrocode} +\long\def\KVS@@CommaSpace#1, #2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1}% + }{% + \KVS@@CommaSpace#1,#2\KVS@Nil + }% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@CommaComma} +% Replaces multiple commas by one comma. +% \begin{macrocode} +\def\KVS@CommaComma{% + \expandafter\KVS@@CommaComma\the\toks@,\KVS@Nil +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@@CommaComma} +% \begin{macrocode} +\long\def\KVS@@CommaComma#1,,#2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1,}% (!) + }{% + \KVS@@CommaComma#1,#2\KVS@Nil + }% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KVS@Equals} +% Converts active equals signs into catcode other characters. +% \begin{macrocode} +\begingroup + \lccode`\==`\=% + \lccode`\~=`\=% +\lowercase{\endgroup + \def\KVS@Equals{% + \toks@\expandafter{\expandafter}\expandafter + \KVS@@Equals\the\toks@~\KVS@Nil + }% + \long\def\KVS@@Equals#1~#2\KVS@Nil{% + \edef\KVS@Temp{\the\toks@}% + \ifx\KVS@Temp\KVS@Empty + \expandafter\KVS@FirstOfTwo + \else + \expandafter\KVS@SecondOfTwo + \fi + {% + \toks@{#1}% + }{% + \toks@\expandafter{\the\toks@=#1}% + }% + \KVS@IfEmpty{#2}{% + }{% + \KVS@@Equals#2\KVS@Nil + }% + }% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@SpaceEquals} +% Removes spaces before the equals sign. +% \begin{macrocode} +\def\KVS@SpaceEquals#1{% + \def\KVS@SpaceEquals{% + \expandafter\KVS@@SpaceEquals\the\toks@#1=\KVS@Nil + }% +} +\KVS@SpaceEquals{ } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@@SpaceEquals} +% \begin{macrocode} +\long\def\KVS@@SpaceEquals#1 =#2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1}% + }{% + \KVS@@SpaceEquals#1=#2\KVS@Nil + }% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@EqualsSpace} +% Removes spaces after the equals sign. +% \begin{macrocode} +\def\KVS@EqualsSpace{% + \expandafter\KVS@@EqualsSpace\the\toks@= \KVS@Nil +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@@EqualsSpace} +% \begin{macrocode} +\long\def\KVS@@EqualsSpace#1= #2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1}% + }{% + \KVS@@EqualsSpace#1=#2\KVS@Nil + }% +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Parsing key value lists} +% +% \begin{macro}{\kv@parse} +% Normalizes and parses the key value list. Also sets \cs{kv@list}. +% \begin{macrocode} +\long\def\kv@parse#1{% + \kv@normalize{#1}% + \expandafter\kv@parse@normalized\expandafter{\kv@list}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\kv@parse@normalized} +% |#1|: key value list\\ +% |#2|: processor +% \begin{macrocode} +\long\def\kv@parse@normalized#1#2{% + \KVS@Parse#1,\KVS@Nil{#2}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@Parse} +% |#1,#2|: key value list\\ +% |#3|: processor +% \begin{macrocode} +\long\def\KVS@Parse#1,#2\KVS@Nil#3{% + \KVS@IfEmpty{#1}{% + }{% + \KVS@Process#1=\KVS@Nil{#3}% + }% + \KVS@MaybeBreak + \KVS@IfEmpty{#2}{% + }{% + \KVS@Parse#2\KVS@Nil{#3}% + }% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@Process} +% |#1|: key\\ +% |#2|: value, |=|\\ +% |#3|: processor +% \begin{macrocode} +\long\def\KVS@Process#1=#2\KVS@Nil#3{% + \let\KVS@MaybeBreak\relax + \def\kv@key{#1}% + \KVS@IfEmpty{#2}{% + \let\kv@value\relax + #3{#1}{}% + }{% + \KVS@@Process{#1}#2\KVS@Nil{#3}% + }% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@@Process} +% |#1|: key\\ +% |#2|: value\\ +% |#3|: processor +% \begin{macrocode} +\long\def\KVS@@Process#1#2=\KVS@Nil#3{% +& \edef\kv@value{\unexpanded{#2}}% +$ \begingroup +$ \toks@{#2}% +$ \xdef\KVS@Global{\the\toks@}% +$ \endgroup +$ \let\kv@value\KVS@Global + #3{#1}{#2}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@MaybeBreak} +% \begin{macrocode} +\let\KVS@MaybeBreak\relax +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@break} +% \begin{macrocode} +\def\KVS@break#1#2#3#4{% + \let\KVS@MaybeBreak\relax +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\kv@break} +% \begin{macrocode} +\def\kv@break{% + \let\KVS@MaybeBreak\KVS@break +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Parsing comma lists} +% +% \begin{macro}{\comma@parse} +% Normalizes and parses the key value list. Also sets \cs{comma@list}. +% \begin{macrocode} +\def\comma@parse#1{% + \comma@normalize{#1}% + \expandafter\comma@parse@normalized\expandafter{\comma@list}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\comma@parse@normalized} +% |#1|: comma list\\ +% |#2|: processor +% \begin{macrocode} +\def\comma@parse@normalized#1#2{% + \KVS@CommaParse#1,\KVS@Nil{#2}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@CommaParse} +% |#1,#2|: comma list\\ +% |#3|: processor +% \begin{macrocode} +\def\KVS@CommaParse#1,#2\KVS@Nil#3{% + \KVS@IfEmpty{#1}{% + }{% + \def\comma@entry{#1}% + #3{#1}% + }% + \KVS@MaybeBreak + \KVS@IfEmpty{#2}{% + }{% + \KVS@CommaParse#2\KVS@Nil{#3}% + }% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\comma@break} +% \begin{macrocode} +\def\comma@break{% + \let\KVS@MaybeBreak\KVS@break +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Processing key value pairs} +% +% \begin{macro}{\kv@handled@false} +% The handler can call \cs{kv@handled@false} or +% \cs{kv@handled@true} so report failure or success. +% The default is success (compatibility for versions +% before 2011/10/18 v1.15). +% \begin{macrocode} +\def\kv@handled@false{% + \let\ifkv@handled@\iffalse +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\kv@handled@true} +% \begin{macrocode} +\def\kv@handled@true{% + \let\ifkv@handled@\iftrue +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\ifkv@handled@} +% \begin{macrocode} +\kv@handled@true +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kv@processor@default} +% \begin{macrocode} +\def\kv@processor@default#1#2{% + \begingroup + \csname @safe@activestrue\endcsname + \let\ifincsname\iftrue + \edef\KVS@temp{\endgroup + \noexpand\KVS@ProcessorDefault{#1}{#2}% + }% + \KVS@temp +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@ProcessorDefault} +% \begin{macrocode} +\long\def\KVS@ProcessorDefault#1#2#3{% + \def\kv@fam{#1}% +& \unless\ifcsname KV@#1@#2\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KV@#1@#2\endcsname\relax +& \unless\ifcsname KVS@#1@handler\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KVS@#1@handler\endcsname\relax + \kv@error@unknownkey{#1}{#2}% + \else + \kv@handled@true + \csname KVS@#1@handler\endcsname{#2}{#3}% + \relax + \ifkv@handled@ + \else + \kv@error@unknownkey{#1}{#2}% + \fi + \fi + \else + \ifx\kv@value\relax +& \unless\ifcsname KV@#1@#2@default\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KV@#1@#2@default\endcsname\relax + \kv@error@novalue{#1}{#2}% + \else + \csname KV@#1@#2@default\endcsname + \relax + \fi + \else + \csname KV@#1@#2\endcsname{#3}% + \fi + \fi +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kv@processor@known} +% \begin{macrocode} +\def\kv@processor@known#1#2#3{% + \begingroup + \csname @safe@activestrue\endcsname + \let\ifincsname\iftrue + \edef\KVS@temp{\endgroup + \noexpand\KVS@ProcessorKnown{#1}\noexpand#2{#3}% + }% + \KVS@temp +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@ProcessorKnown} +% \begin{macrocode} +\long\def\KVS@ProcessorKnown#1#2#3#4{% + \def\kv@fam{#1}% +& \unless\ifcsname KV@#1@#3\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KV@#1@#3\endcsname\relax +& \unless\ifcsname KVS@#1@handler\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KVS@#1@handler\endcsname\relax + \KVS@AddUnhandled#2{#3}{#4}% + \else + \kv@handled@true + \csname KVS@#1@handler\endcsname{#3}{#4}% + \relax + \ifkv@handled@ + \else + \KVS@AddUnhandled#2{#3}{#4}% + \fi + \fi + \else + \ifx\kv@value\relax +& \unless\ifcsname KV@#1@#2@default\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KV@#1@#3@default\endcsname\relax + \kv@error@novalue{#1}{#3}% + \else + \csname KV@#1@#3@default\endcsname + \relax + \fi + \else + \csname KV@#1@#3\endcsname{#4}% + \fi + \fi +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@AddUnhandled} +% \begin{macrocode} +\long\def\KVS@AddUnhandled#1#2#3{% +& \edef#1{% +& \ifx#1\KVS@empty +& \else +& \unexpanded{#1},% +& \fi +& \unexpanded{{#2}={#3}}% +& }% +$ \begingroup +$ \ifx#1\KVS@empty +$ \toks@{{#2}={#3}}% +$ \else +$ \toks@\expandafter{#1,{#2}={#3}}% +$ \fi +$ \xdef\KVS@Global{\the\toks@}% +$ \endgroup +$ \let#1\KVS@Global +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kv@set@family@handler} +% \begin{macrocode} +\long\def\kv@set@family@handler#1#2{% + \begingroup + \csname @safe@activestrue\endcsname + \let\ifincsname\iftrue + \expandafter\endgroup + \expandafter\def\csname KVS@#1@handler\endcsname##1##2{#2}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kv@unset@family@handler} +% \begin{macrocode} +\long\def\kv@unset@family@handler#1#2{% + \begingroup + \csname @safe@activestrue\endcsname + \let\ifincsname\iftrue + \expandafter\endgroup + \expandafter\let\csname KVS@#1@handler\endcsname\@UnDeFiNeD +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Error handling} +% +% \begin{macro}{\kv@error@novalue} +% \begin{macrocode} +\def\kv@error@novalue{% + \kv@error@generic{No value specified for}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\kv@error@unknownkey} +% \begin{macrocode} +\def\kv@error@unknownkey{% + \kv@error@generic{Undefined}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\kv@error@generic} +% \begin{macrocode} +\def\kv@error@generic#1#2#3{% + \PackageError{kvsetkeys}{% + #1 key `#3'% + }{% + The keyval family of the key `#3' is `#2'.\MessageBreak + The setting of the key is ignored because of the error.\MessageBreak + \MessageBreak + \@ehc + }% +} +% \end{macrocode} +% \end{macro} +% +% \subsection{Do it all} +% +% \begin{macro}{\kvsetkeys} +% \begin{macrocode} +\long\def\kvsetkeys#1#2{% + \kv@parse{#2}{\kv@processor@default{#1}}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kvsetkeys@expandafter} +% \begin{macrocode} +\def\kvsetkeys@expandafter#1#2{% + \expandafter\kv@parse\expandafter{#2}{% + \kv@processor@default{#1}% + }% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KVS@cmd} +% \begin{macrocode} +\def\KVS@cmd{0}% +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@cmd@inc} +% \begin{macrocode} +\def\KVS@cmd@inc{% +& \edef\KVS@cmd{\the\numexpr\KVS@cmd+1}% +$ \begingroup +$ \count255=\KVS@cmd\relax +$ \advance\count255 by 1\relax +$ \edef\x{\endgroup +$ \noexpand\def\noexpand\KVS@cmd{\number\count255}% +$ }% +$ \x +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@cmd@dec} +% \begin{macrocode} +\def\KVS@cmd@dec{% +& \edef\KVS@cmd{\the\numexpr\KVS@cmd-1}% +$ \begingroup +$ \count255=\KVS@cmd\relax +$ \advance\count255 by -1\relax +$ \edef\x{\endgroup +$ \noexpand\def\noexpand\KVS@cmd{\number\count255}% +$ }% +$ \x +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@empty} +% \begin{macrocode} +\def\KVS@empty{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kvsetknownkeys} +% \begin{macrocode} +\def\kvsetknownkeys{% + \expandafter + \KVS@setknownkeys\csname KVS@cmd\KVS@cmd\endcsname{}% +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\KVS@setknownkeys} +% \begin{macrocode} +\long\def\KVS@setknownkeys#1#2#3#4#5{% + \let#1\KVS@empty + \KVS@cmd@inc + #2\kv@parse#2{#5}{\kv@processor@known{#3}#1}% + \KVS@cmd@dec + \let#4=#1% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\kvsetknownkeys@expandafter} +% \begin{macrocode} +\def\kvsetknownkeys@expandafter{% + \expandafter + \KVS@setknownkeys + \csname KVS@cmd\KVS@cmd\endcsname\expandafter +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +\KVS@AtEnd% +% +% \end{macrocode} +%% \section{Installation} +% +% \subsection{Download} +% +% \paragraph{Package.} This package is available on +% CTAN\footnote{\CTANpkg{kvsetkeys}}: +% \begin{description} +% \item[\CTAN{macros/latex/contrib/kvsetkeys/kvsetkeys.dtx}] The source file. +% \item[\CTAN{macros/latex/contrib/kvsetkeys/kvsetkeys.pdf}] Documentation. +% \end{description} +% +% +% \paragraph{Bundle.} All the packages of the bundle `kvsetkeys' +% are also available in a TDS compliant ZIP archive. There +% the packages are already unpacked and the documentation files +% are generated. The files and directories obey the TDS standard. +% \begin{description} +% \item[\CTANinstall{install/macros/latex/contrib/kvsetkeys.tds.zip}] +% \end{description} +% \emph{TDS} refers to the standard ``A Directory Structure +% for \TeX\ Files'' (\CTANpkg{tds}). Directories +% with \xfile{texmf} in their name are usually organized this way. +% +% \subsection{Bundle installation} +% +% \paragraph{Unpacking.} Unpack the \xfile{kvsetkeys.tds.zip} in the +% TDS tree (also known as \xfile{texmf} tree) of your choice. +% Example (linux): +% \begin{quote} +% |unzip kvsetkeys.tds.zip -d ~/texmf| +% \end{quote} +% +% \subsection{Package installation} +% +% \paragraph{Unpacking.} The \xfile{.dtx} file is a self-extracting +% \docstrip\ archive. The files are extracted by running the +% \xfile{.dtx} through \plainTeX: +% \begin{quote} +% \verb|tex kvsetkeys.dtx| +% \end{quote} +% +% \paragraph{TDS.} Now the different files must be moved into +% the different directories in your installation TDS tree +% (also known as \xfile{texmf} tree): +% \begin{quote} +% \def\t{^^A +% \begin{tabular}{@{}>{\ttfamily}l@{ $\rightarrow$ }>{\ttfamily}l@{}} +% kvsetkeys.sty & tex/generic/kvsetkeys/kvsetkeys.sty\\ +% kvsetkeys.pdf & doc/latex/kvsetkeys/kvsetkeys.pdf\\ +% kvsetkeys-example.tex & doc/latex/kvsetkeys/kvsetkeys-example.tex\\ +% kvsetkeys.dtx & source/latex/kvsetkeys/kvsetkeys.dtx\\ +% \end{tabular}^^A +% }^^A +% \sbox0{\t}^^A +% \ifdim\wd0>\linewidth +% \begingroup +% \advance\linewidth by\leftmargin +% \advance\linewidth by\rightmargin +% \edef\x{\endgroup +% \def\noexpand\lw{\the\linewidth}^^A +% }\x +% \def\lwbox{^^A +% \leavevmode +% \hbox to \linewidth{^^A +% \kern-\leftmargin\relax +% \hss +% \usebox0 +% \hss +% \kern-\rightmargin\relax +% }^^A +% }^^A +% \ifdim\wd0>\lw +% \sbox0{\small\t}^^A +% \ifdim\wd0>\linewidth +% \ifdim\wd0>\lw +% \sbox0{\footnotesize\t}^^A +% \ifdim\wd0>\linewidth +% \ifdim\wd0>\lw +% \sbox0{\scriptsize\t}^^A +% \ifdim\wd0>\linewidth +% \ifdim\wd0>\lw +% \sbox0{\tiny\t}^^A +% \ifdim\wd0>\linewidth +% \lwbox +% \else +% \usebox0 +% \fi +% \else +% \lwbox +% \fi +% \else +% \usebox0 +% \fi +% \else +% \lwbox +% \fi +% \else +% \usebox0 +% \fi +% \else +% \lwbox +% \fi +% \else +% \usebox0 +% \fi +% \else +% \lwbox +% \fi +% \else +% \usebox0 +% \fi +% \end{quote} +% If you have a \xfile{docstrip.cfg} that configures and enables \docstrip's +% TDS installing feature, then some files can already be in the right +% place, see the documentation of \docstrip. +% +% \subsection{Refresh file name databases} +% +% If your \TeX~distribution +% (\TeX\,Live, \mikTeX, \dots) relies on file name databases, you must refresh +% these. For example, \TeX\,Live\ users run \verb|texhash| or +% \verb|mktexlsr|. +% +% \subsection{Some details for the interested} +% +% \paragraph{Unpacking with \LaTeX.} +% The \xfile{.dtx} chooses its action depending on the format: +% \begin{description} +% \item[\plainTeX:] Run \docstrip\ and extract the files. +% \item[\LaTeX:] Generate the documentation. +% \end{description} +% If you insist on using \LaTeX\ for \docstrip\ (really, +% \docstrip\ does not need \LaTeX), then inform the autodetect routine +% about your intention: +% \begin{quote} +% \verb|latex \let\install=y\input{kvsetkeys.dtx}| +% \end{quote} +% Do not forget to quote the argument according to the demands +% of your shell. +% +% \paragraph{Generating the documentation.} +% You can use both the \xfile{.dtx} or the \xfile{.drv} to generate +% the documentation. The process can be configured by the +% configuration file \xfile{ltxdoc.cfg}. For instance, put this +% line into this file, if you want to have A4 as paper format: +% \begin{quote} +% \verb|\PassOptionsToClass{a4paper}{article}| +% \end{quote} +% An example follows how to generate the +% documentation with pdf\LaTeX: +% \begin{quote} +%\begin{verbatim} +%pdflatex kvsetkeys.dtx +%makeindex -s gind.ist kvsetkeys.idx +%pdflatex kvsetkeys.dtx +%makeindex -s gind.ist kvsetkeys.idx +%pdflatex kvsetkeys.dtx +%\end{verbatim} +% \end{quote} +% +% \begin{thebibliography}{9} +% \bibitem{tb94wright} +% A guide to key-value methods, Joseph Wright, second draft for +% \href{https://www.tug.org/tugboat}{TUGBoat}, 2009-03-17. +% \url{https://www.texdev.net/uploads/2009/03/keyval.pdf} +% +% \bibitem{keyval} +% David Carlisle: +% \textit{The \xpackage{keyval} package}; +% 1999/03/16 v1.13; +% \CTANpkg{keyval}. +% +% \end{thebibliography} +% +% \begin{History} +% \begin{Version}{2006/03/06 v1.0} +% \item +% First version. +% \end{Version} +% \begin{Version}{2006/10/19 v1.1} +% \item +% Fix of \cs{kv@set@family@handler}. +% \item +% Example added. +% \end{Version} +% \begin{Version}{2007/09/09 v1.2} +% \item +% Using package \xpackage{infwarerr} for error messages. +% \item +% Catcode section rewritten. +% \end{Version} +% \begin{Version}{2007/09/29 v1.3} +% \item +% Normalizing and parsing of comma separated lists added. +% \item +% \cs{kv@normalize} rewritten. +% \item +% Robustness increased for normalizing and parsing, +% e.g. for values with unmatched conditionals. +% \item +% \eTeX\ is used if available. +% \item +% Tests added for normalizing and parsing. +% \end{Version} +% \begin{Version}{2009/07/19 v1.4} +% \item +% Bug fix for \cs{kv@normalize}: unwanted space removed (Florent Chervet). +% \end{Version} +% \begin{Version}{2009/07/30 v1.5} +% \item +% Documentation addition: recommendation for Joseph Wright's +% review article. +% \end{Version} +% \begin{Version}{2009/12/12 v1.6} +% \item +% Short info shortened. +% \end{Version} +% \begin{Version}{2009/12/22 v1.7} +% \item +% Internal optimization (\cs{KVS@CommaSpace}, \dots, \cs{KVS@EqualsSpace}). +% \end{Version} +% \begin{Version}{2010/01/28 v1.8} +% \item +% Compatibility to ini\TeX\ added. +% \end{Version} +% \begin{Version}{2010/03/01 v1.9} +% \item +% Support of \cs{par} inside values. +% \end{Version} +% \begin{Version}{2011/01/30 v1.10} +% \item +% Already loaded package files are not input in \hologo{plainTeX}. +% \end{Version} +% \begin{Version}{2011/03/03 v1.11} +% \item +% \cs{kv@break} and \cs{comma@break} added. +% \end{Version} +% \begin{Version}{2011/04/05 v1.12} +% \item +% Error message with recovery action in help message +% (request by GL). +% \end{Version} +% \begin{Version}{2011/04/07 v1.13} +% \item +% \cs{kv@processor@default} supports package \xpackage{babel}'s +% shorthands. +% \item +% \cs{kv@set@family@handler} with shorthand support. +% \end{Version} +% \begin{Version}{2011/06/15 v1.14} +% \item +% Some optimizations in token register uses (GL, HO). +% \end{Version} +% \begin{Version}{2011/10/18 v1.15} +% \item +% \cs{kv@processor@known} and \cs{kvsetknownkeys} added. +% \item +% \cs{kvsetkeys@expandafter} and \cs{kvsetknownkeys@expandafter} added. +% \item +% Family handler can report success or failure by \cs{kv@handled@true} +% or \cs{kv@handled@false}. +% \item +% \cs{kv@unset@family@handler} added. +% \end{Version} +% \begin{Version}{2012/04/25 v1.16} +% \item +% \cs{kv@processor@default} and \cs{kv@processor@known} define +% macro \cs{kv@fam} for convenience. +% \item +% Catcode section: Catcode setting for \texttt{+} added for \hologo{eTeX}. +% \end{Version} +% \begin{Version}{2016/05/16 v1.17} +% \item +% Documentation updates. +% \end{Version} +% \begin{Version}{2019/12/15 v1.18} +% \item +% Documentation updates. +% \item +% Avoid \xpackage{etexcmds} and \xpackage{infwarwerr} in \LaTeX. +% \end{Version} +% \end{History} +% +% \PrintIndex +% +% \Finale +\endinput diff --git a/Master/texmf-dist/tex/generic/kvsetkeys/kvsetkeys.sty b/Master/texmf-dist/tex/generic/kvsetkeys/kvsetkeys.sty new file mode 100644 index 00000000000..2d9ac6197bf --- /dev/null +++ b/Master/texmf-dist/tex/generic/kvsetkeys/kvsetkeys.sty @@ -0,0 +1,573 @@ +%% +%% This is file `kvsetkeys.sty', +%% generated with the docstrip utility. +%% +%% The original source files were: +%% +%% kvsetkeys.dtx (with options: `package') +%% +%% This is a generated file. +%% +%% Project: kvsetkeys +%% Version: 2019/12/15 v1.18 +%% +%% Copyright (C) +%% 2006, 2007, 2009-2012 Heiko Oberdiek +%% 2016-2019 Oberdiek Package Support Group +%% +%% This work may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either +%% version 1.3c of this license or (at your option) any later +%% version. This version of this license is in +%% https://www.latex-project.org/lppl/lppl-1-3c.txt +%% and the latest version of this license is in +%% https://www.latex-project.org/lppl.txt +%% and version 1.3 or later is part of all distributions of +%% LaTeX version 2005/12/01 or later. +%% +%% This work has the LPPL maintenance status "maintained". +%% +%% The Current Maintainers of this work are +%% Heiko Oberdiek and the Oberdiek Package Support Group +%% https://github.com/ho-tex/kvsetkeys/issues +%% +%% +%% The Base Interpreter refers to any `TeX-Format', +%% because some files are installed in TDS:tex/generic//. +%% +%% This work consists of the main source file kvsetkeys.dtx +%% and the derived files +%% kvsetkeys.sty, kvsetkeys.pdf, kvsetkeys.ins, kvsetkeys.drv, +%% kvsetkeys-example.tex, kvsetkeys-test1.tex, +%% kvsetkeys-test2.tex, kvsetkeys-test3.tex, +%% kvsetkeys-test4.tex. +%% +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode35=6 % # + \catcode39=12 % ' + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode58=12 % : + \catcode64=11 % @ + \catcode123=1 % { + \catcode125=2 % } + \expandafter\let\expandafter\x\csname ver@kvsetkeys.sty\endcsname + \ifx\x\relax % plain-TeX, first loading + \else + \def\empty{}% + \ifx\x\empty % LaTeX, first loading, + % variable is initialized, but \ProvidesPackage not yet seen + \else + \expandafter\ifx\csname PackageInfo\endcsname\relax + \def\x#1#2{% + \immediate\write-1{Package #1 Info: #2.}% + }% + \else + \def\x#1#2{\PackageInfo{#1}{#2, stopped}}% + \fi + \x{kvsetkeys}{The package is already loaded}% + \aftergroup\endinput + \fi + \fi +\endgroup% +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode35=6 % # + \catcode39=12 % ' + \catcode40=12 % ( + \catcode41=12 % ) + \catcode44=12 % , + \catcode45=12 % - + \catcode46=12 % . + \catcode47=12 % / + \catcode58=12 % : + \catcode64=11 % @ + \catcode91=12 % [ + \catcode93=12 % ] + \catcode123=1 % { + \catcode125=2 % } + \expandafter\ifx\csname ProvidesPackage\endcsname\relax + \def\x#1#2#3[#4]{\endgroup + \immediate\write-1{Package: #3 #4}% + \xdef#1{#4}% + }% + \else + \def\x#1#2[#3]{\endgroup + #2[{#3}]% + \ifx#1\@undefined + \xdef#1{#3}% + \fi + \ifx#1\relax + \xdef#1{#3}% + \fi + }% + \fi +\expandafter\x\csname ver@kvsetkeys.sty\endcsname +\ProvidesPackage{kvsetkeys}% + [2019/12/15 v1.18 Key value parser (HO)]% +\begingroup\catcode61\catcode48\catcode32=10\relax% + \catcode13=5 % ^^M + \endlinechar=13 % + \catcode123=1 % { + \catcode125=2 % } + \catcode64=11 % @ + \def\x{\endgroup + \expandafter\edef\csname KVS@AtEnd\endcsname{% + \endlinechar=\the\endlinechar\relax + \catcode13=\the\catcode13\relax + \catcode32=\the\catcode32\relax + \catcode35=\the\catcode35\relax + \catcode61=\the\catcode61\relax + \catcode64=\the\catcode64\relax + \catcode123=\the\catcode123\relax + \catcode125=\the\catcode125\relax + }% + }% +\x\catcode61\catcode48\catcode32=10\relax% +\catcode13=5 % ^^M +\endlinechar=13 % +\catcode35=6 % # +\catcode64=11 % @ +\catcode123=1 % { +\catcode125=2 % } +\def\TMP@EnsureCode#1#2{% + \edef\KVS@AtEnd{% + \KVS@AtEnd + \catcode#1=\the\catcode#1\relax + }% + \catcode#1=#2\relax +} +\TMP@EnsureCode{36}{3}% $ +\TMP@EnsureCode{38}{4}% & +\TMP@EnsureCode{39}{12}% ' +\TMP@EnsureCode{43}{12}% + +\TMP@EnsureCode{44}{12}% , +\TMP@EnsureCode{45}{12}% - +\TMP@EnsureCode{46}{12}% . +\TMP@EnsureCode{47}{12}% / +\TMP@EnsureCode{91}{12}% [ +\TMP@EnsureCode{93}{12}% ] +\TMP@EnsureCode{94}{7}% ^ (superscript) +\TMP@EnsureCode{96}{12}% ` +\TMP@EnsureCode{126}{13}% ~ (active) +\edef\KVS@AtEnd{\KVS@AtEnd\noexpand\endinput} +\begingroup\expandafter\expandafter\expandafter\endgroup +\expandafter\ifx\csname RequirePackage\endcsname\relax + \def\TMP@RequirePackage#1[#2]{% + \begingroup\expandafter\expandafter\expandafter\endgroup + \expandafter\ifx\csname ver@#1.sty\endcsname\relax + \input #1.sty\relax + \fi + }% + \TMP@RequirePackage{infwarerr}[2007/09/09]% + \let\PackageError\@PackageError +\else +\fi +\expandafter\ifx\csname toks@\endcsname\relax + \toksdef\toks@=0 % +\fi +\ifx\numexpr\@undefined + \catcode`\$=9 % ignore + \catcode`\&=14 % comment +\else % e-TeX + \catcode`\$=14 % comment + \catcode`\&=9 % ignore +\fi +\def\KVS@Empty{} +\long\def\KVS@FirstOfTwo#1#2{#1} +\long\def\KVS@SecondOfTwo#1#2{#2} +\long\def\KVS@IfEmpty#1{% +& \edef\KVS@Temp{\unexpanded{#1}}% +$ \begingroup +$ \toks@{#1}% +$ \edef\KVS@Temp{\the\toks@}% +$ \expandafter\endgroup + \ifx\KVS@Temp\KVS@Empty + \expandafter\KVS@FirstOfTwo + \else + \expandafter\KVS@SecondOfTwo + \fi +} +\long\def\kv@normalize#1{% + \begingroup + \toks@{,#1,}% + \KVS@Comma + \KVS@SpaceComma + \KVS@CommaSpace + \KVS@CommaComma + \KVS@Equals + \KVS@SpaceEquals + \KVS@EqualsSpace + \xdef\KVS@Global{\the\toks@}% + \endgroup + \let\kv@list\KVS@Global +} +\def\comma@normalize#1{% + \begingroup + \toks@{,#1,}% + \KVS@Comma + \KVS@SpaceComma + \KVS@CommaSpace + \KVS@CommaComma + \xdef\KVS@Global{\the\toks@}% + \endgroup + \let\comma@list\KVS@Global +} +\begingroup + \lccode`\,=`\,% + \lccode`\~=`\,% +\lowercase{\endgroup + \def\KVS@Comma{% + \toks@\expandafter{\expandafter}\expandafter + \KVS@@Comma\the\toks@~\KVS@Nil + }% + \long\def\KVS@@Comma#1~#2\KVS@Nil{% + \toks@\expandafter{\the\toks@#1}% + \KVS@IfEmpty{#2}{% + }{% + \KVS@@Comma,#2\KVS@Nil + }% + }% +} +\def\KVS@SpaceComma#1{% + \def\KVS@SpaceComma{% + \expandafter\KVS@@SpaceComma\the\toks@#1,\KVS@Nil + }% +} +\KVS@SpaceComma{ } +\long\def\KVS@@SpaceComma#1 ,#2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1}% + }{% + \KVS@@SpaceComma#1,#2\KVS@Nil + }% +} +\def\KVS@CommaSpace{% + \expandafter\KVS@@CommaSpace\the\toks@, \KVS@Nil +} +\long\def\KVS@@CommaSpace#1, #2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1}% + }{% + \KVS@@CommaSpace#1,#2\KVS@Nil + }% +} +\def\KVS@CommaComma{% + \expandafter\KVS@@CommaComma\the\toks@,\KVS@Nil +} +\long\def\KVS@@CommaComma#1,,#2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1,}% (!) + }{% + \KVS@@CommaComma#1,#2\KVS@Nil + }% +} +\begingroup + \lccode`\==`\=% + \lccode`\~=`\=% +\lowercase{\endgroup + \def\KVS@Equals{% + \toks@\expandafter{\expandafter}\expandafter + \KVS@@Equals\the\toks@~\KVS@Nil + }% + \long\def\KVS@@Equals#1~#2\KVS@Nil{% + \edef\KVS@Temp{\the\toks@}% + \ifx\KVS@Temp\KVS@Empty + \expandafter\KVS@FirstOfTwo + \else + \expandafter\KVS@SecondOfTwo + \fi + {% + \toks@{#1}% + }{% + \toks@\expandafter{\the\toks@=#1}% + }% + \KVS@IfEmpty{#2}{% + }{% + \KVS@@Equals#2\KVS@Nil + }% + }% +} +\def\KVS@SpaceEquals#1{% + \def\KVS@SpaceEquals{% + \expandafter\KVS@@SpaceEquals\the\toks@#1=\KVS@Nil + }% +} +\KVS@SpaceEquals{ } +\long\def\KVS@@SpaceEquals#1 =#2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1}% + }{% + \KVS@@SpaceEquals#1=#2\KVS@Nil + }% +} +\def\KVS@EqualsSpace{% + \expandafter\KVS@@EqualsSpace\the\toks@= \KVS@Nil +} +\long\def\KVS@@EqualsSpace#1= #2\KVS@Nil{% + \KVS@IfEmpty{#2}{% + \toks@{#1}% + }{% + \KVS@@EqualsSpace#1=#2\KVS@Nil + }% +} +\long\def\kv@parse#1{% + \kv@normalize{#1}% + \expandafter\kv@parse@normalized\expandafter{\kv@list}% +} +\long\def\kv@parse@normalized#1#2{% + \KVS@Parse#1,\KVS@Nil{#2}% +} +\long\def\KVS@Parse#1,#2\KVS@Nil#3{% + \KVS@IfEmpty{#1}{% + }{% + \KVS@Process#1=\KVS@Nil{#3}% + }% + \KVS@MaybeBreak + \KVS@IfEmpty{#2}{% + }{% + \KVS@Parse#2\KVS@Nil{#3}% + }% +} +\long\def\KVS@Process#1=#2\KVS@Nil#3{% + \let\KVS@MaybeBreak\relax + \def\kv@key{#1}% + \KVS@IfEmpty{#2}{% + \let\kv@value\relax + #3{#1}{}% + }{% + \KVS@@Process{#1}#2\KVS@Nil{#3}% + }% +} +\long\def\KVS@@Process#1#2=\KVS@Nil#3{% +& \edef\kv@value{\unexpanded{#2}}% +$ \begingroup +$ \toks@{#2}% +$ \xdef\KVS@Global{\the\toks@}% +$ \endgroup +$ \let\kv@value\KVS@Global + #3{#1}{#2}% +} +\let\KVS@MaybeBreak\relax +\def\KVS@break#1#2#3#4{% + \let\KVS@MaybeBreak\relax +} +\def\kv@break{% + \let\KVS@MaybeBreak\KVS@break +} +\def\comma@parse#1{% + \comma@normalize{#1}% + \expandafter\comma@parse@normalized\expandafter{\comma@list}% +} +\def\comma@parse@normalized#1#2{% + \KVS@CommaParse#1,\KVS@Nil{#2}% +} +\def\KVS@CommaParse#1,#2\KVS@Nil#3{% + \KVS@IfEmpty{#1}{% + }{% + \def\comma@entry{#1}% + #3{#1}% + }% + \KVS@MaybeBreak + \KVS@IfEmpty{#2}{% + }{% + \KVS@CommaParse#2\KVS@Nil{#3}% + }% +} +\def\comma@break{% + \let\KVS@MaybeBreak\KVS@break +} +\def\kv@handled@false{% + \let\ifkv@handled@\iffalse +} +\def\kv@handled@true{% + \let\ifkv@handled@\iftrue +} +\kv@handled@true +\def\kv@processor@default#1#2{% + \begingroup + \csname @safe@activestrue\endcsname + \let\ifincsname\iftrue + \edef\KVS@temp{\endgroup + \noexpand\KVS@ProcessorDefault{#1}{#2}% + }% + \KVS@temp +} +\long\def\KVS@ProcessorDefault#1#2#3{% + \def\kv@fam{#1}% +& \unless\ifcsname KV@#1@#2\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KV@#1@#2\endcsname\relax +& \unless\ifcsname KVS@#1@handler\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KVS@#1@handler\endcsname\relax + \kv@error@unknownkey{#1}{#2}% + \else + \kv@handled@true + \csname KVS@#1@handler\endcsname{#2}{#3}% + \relax + \ifkv@handled@ + \else + \kv@error@unknownkey{#1}{#2}% + \fi + \fi + \else + \ifx\kv@value\relax +& \unless\ifcsname KV@#1@#2@default\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KV@#1@#2@default\endcsname\relax + \kv@error@novalue{#1}{#2}% + \else + \csname KV@#1@#2@default\endcsname + \relax + \fi + \else + \csname KV@#1@#2\endcsname{#3}% + \fi + \fi +} +\def\kv@processor@known#1#2#3{% + \begingroup + \csname @safe@activestrue\endcsname + \let\ifincsname\iftrue + \edef\KVS@temp{\endgroup + \noexpand\KVS@ProcessorKnown{#1}\noexpand#2{#3}% + }% + \KVS@temp +} +\long\def\KVS@ProcessorKnown#1#2#3#4{% + \def\kv@fam{#1}% +& \unless\ifcsname KV@#1@#3\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KV@#1@#3\endcsname\relax +& \unless\ifcsname KVS@#1@handler\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KVS@#1@handler\endcsname\relax + \KVS@AddUnhandled#2{#3}{#4}% + \else + \kv@handled@true + \csname KVS@#1@handler\endcsname{#3}{#4}% + \relax + \ifkv@handled@ + \else + \KVS@AddUnhandled#2{#3}{#4}% + \fi + \fi + \else + \ifx\kv@value\relax +& \unless\ifcsname KV@#1@#2@default\endcsname +$ \begingroup\expandafter\expandafter\expandafter\endgroup +$ \expandafter\ifx\csname KV@#1@#3@default\endcsname\relax + \kv@error@novalue{#1}{#3}% + \else + \csname KV@#1@#3@default\endcsname + \relax + \fi + \else + \csname KV@#1@#3\endcsname{#4}% + \fi + \fi +} +\long\def\KVS@AddUnhandled#1#2#3{% +& \edef#1{% +& \ifx#1\KVS@empty +& \else +& \unexpanded{#1},% +& \fi +& \unexpanded{{#2}={#3}}% +& }% +$ \begingroup +$ \ifx#1\KVS@empty +$ \toks@{{#2}={#3}}% +$ \else +$ \toks@\expandafter{#1,{#2}={#3}}% +$ \fi +$ \xdef\KVS@Global{\the\toks@}% +$ \endgroup +$ \let#1\KVS@Global +} +\long\def\kv@set@family@handler#1#2{% + \begingroup + \csname @safe@activestrue\endcsname + \let\ifincsname\iftrue + \expandafter\endgroup + \expandafter\def\csname KVS@#1@handler\endcsname##1##2{#2}% +} +\long\def\kv@unset@family@handler#1#2{% + \begingroup + \csname @safe@activestrue\endcsname + \let\ifincsname\iftrue + \expandafter\endgroup + \expandafter\let\csname KVS@#1@handler\endcsname\@UnDeFiNeD +} +\def\kv@error@novalue{% + \kv@error@generic{No value specified for}% +} +\def\kv@error@unknownkey{% + \kv@error@generic{Undefined}% +} +\def\kv@error@generic#1#2#3{% + \PackageError{kvsetkeys}{% + #1 key `#3'% + }{% + The keyval family of the key `#3' is `#2'.\MessageBreak + The setting of the key is ignored because of the error.\MessageBreak + \MessageBreak + \@ehc + }% +} +\long\def\kvsetkeys#1#2{% + \kv@parse{#2}{\kv@processor@default{#1}}% +} +\def\kvsetkeys@expandafter#1#2{% + \expandafter\kv@parse\expandafter{#2}{% + \kv@processor@default{#1}% + }% +} +\def\KVS@cmd{0}% +\def\KVS@cmd@inc{% +& \edef\KVS@cmd{\the\numexpr\KVS@cmd+1}% +$ \begingroup +$ \count255=\KVS@cmd\relax +$ \advance\count255 by 1\relax +$ \edef\x{\endgroup +$ \noexpand\def\noexpand\KVS@cmd{\number\count255}% +$ }% +$ \x +} +\def\KVS@cmd@dec{% +& \edef\KVS@cmd{\the\numexpr\KVS@cmd-1}% +$ \begingroup +$ \count255=\KVS@cmd\relax +$ \advance\count255 by -1\relax +$ \edef\x{\endgroup +$ \noexpand\def\noexpand\KVS@cmd{\number\count255}% +$ }% +$ \x +} +\def\KVS@empty{} +\def\kvsetknownkeys{% + \expandafter + \KVS@setknownkeys\csname KVS@cmd\KVS@cmd\endcsname{}% +} +\long\def\KVS@setknownkeys#1#2#3#4#5{% + \let#1\KVS@empty + \KVS@cmd@inc + #2\kv@parse#2{#5}{\kv@processor@known{#3}#1}% + \KVS@cmd@dec + \let#4=#1% +} +\def\kvsetknownkeys@expandafter{% + \expandafter + \KVS@setknownkeys + \csname KVS@cmd\KVS@cmd\endcsname\expandafter +} +\KVS@AtEnd% +%% \section{Installation} +\endinput +%% +%% End of file `kvsetkeys.sty'. diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index c685190417d..8d9a1436ef8 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -386,7 +386,7 @@ my @TLP_working = qw( koma-moderncvclassic koma-script koma-script-examples koma-script-sfs komacv komacv-rg kotex-oblivoir kotex-plain kotex-utf kotex-utils kpfonts ksfh_nat ksp-thesis - ktv-texdata ku-template kurdishlipsum kurier kvmap kvoptions + ktv-texdata ku-template kurdishlipsum kurier kvmap kvoptions kvsetkeys l2picfaq l2tabu l2tabu-english l2tabu-french l2tabu-italian l2tabu-spanish l3backend l3build l3kernel l3packages l3experimental labbook labels labels4easylist labelschanged diff --git a/Master/tlpkg/tlpsrc/collection-latex.tlpsrc b/Master/tlpkg/tlpsrc/collection-latex.tlpsrc index cfa541902e5..b649a235c22 100644 --- a/Master/tlpkg/tlpsrc/collection-latex.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-latex.tlpsrc @@ -25,6 +25,7 @@ depend graphics-cfg depend grfext depend hyperref depend kvoptions +depend kvsetkeys depend latex depend latex-bin depend latex-fonts diff --git a/Master/tlpkg/tlpsrc/kvsetkeys.tlpsrc b/Master/tlpkg/tlpsrc/kvsetkeys.tlpsrc new file mode 100644 index 00000000000..e69de29bb2d -- cgit v1.2.3