summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx')
-rw-r--r--Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx854
1 files changed, 661 insertions, 193 deletions
diff --git a/Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx b/Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx
index 6d9d13470f6..7c4bd21a780 100644
--- a/Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx
+++ b/Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx
@@ -17,7 +17,8 @@
% 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-example.tex, kvsetkeys-test1.tex,
+% kvsetkeys-test2.tex, kvsetkeys-test3.tex.
%
% Distribution:
% CTAN:macros/latex/contrib/oberdiek/kvsetkeys.dtx
@@ -54,6 +55,8 @@
% TDS:doc/latex/oberdiek/kvsetkeys.pdf
% TDS:doc/latex/oberdiek/kvsetkeys-example.tex
% TDS:doc/latex/oberdiek/kvsetkeys-test1.tex
+% TDS:doc/latex/oberdiek/kvsetkeys-test2.tex
+% TDS:doc/latex/oberdiek/kvsetkeys-test3.tex
% TDS:source/latex/oberdiek/kvsetkeys.dtx
%
%<*ignore>
@@ -69,7 +72,7 @@
\input docstrip.tex
\Msg{************************************************************************}
\Msg{* Installation}
-\Msg{* Package: kvsetkeys 2007/09/09 v1.2 Key value parser with default handler support (HO)}
+\Msg{* Package: kvsetkeys 2007/09/29 v1.3 Key value parser with default handler support (HO)}
\Msg{************************************************************************}
\keepsilent
@@ -96,7 +99,8 @@ This Current Maintainer of this work is Heiko Oberdiek.
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-example.tex, kvsetkeys-test1.tex,
+ kvsetkeys-test2.tex, kvsetkeys-test3.tex.
\endpreamble
@@ -108,6 +112,8 @@ and the derived files
\usedir{doc/latex/oberdiek}%
\file{kvsetkeys-example.tex}{\from{kvsetkeys.dtx}{example}}%
\file{kvsetkeys-test1.tex}{\from{kvsetkeys.dtx}{test1}}%
+ \file{kvsetkeys-test2.tex}{\from{kvsetkeys.dtx}{test2}}%
+ \file{kvsetkeys-test3.tex}{\from{kvsetkeys.dtx}{test2,noetex}}%
}
\obeyspaces
@@ -133,7 +139,7 @@ and the derived files
%<*driver>
\NeedsTeXFormat{LaTeX2e}
\ProvidesFile{kvsetkeys.drv}%
- [2007/09/09 v1.2 Key value parser with default handler support (HO)]%
+ [2007/09/29 v1.3 Key value parser with default handler support (HO)]%
\documentclass{ltxdoc}
\usepackage{holtxdoc}
\begin{document}
@@ -142,7 +148,7 @@ and the derived files
%</driver>
% \fi
%
-% \CheckSum{625}
+% \CheckSum{1010}
%
% \CharacterTable
% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
@@ -163,7 +169,7 @@ and the derived files
% \GetFileInfo{kvsetkeys.drv}
%
% \title{The \xpackage{kvsetkeys} package}
-% \date{2007/09/09 v1.2}
+% \date{2007/09/29 v1.3}
% \author{Heiko Oberdiek\\\xemail{oberdiek@uni-freiburg.de}}
%
% \maketitle
@@ -182,8 +188,44 @@ and the derived files
%
% \section{Documentation}
%
-% \cs{kvsetkeys} can be used as replacement for \xpackage{keyval}'s
-% \cs{setkeys}. Also it uses the same syntax. Before I describe
+% \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.
@@ -192,8 +234,8 @@ and the derived files
%
% \begin{declcs}{kv@normalize}\,\M{key value list}
% \end{declcs}
-% Specifying key value lists, the user usually wants to have
-% nice formatted souce code, e.g.:
+% If the user specifies key value lists, he usually prefers
+% nice formatted source code, e.g.:
% \begin{quote}
%\begin{verbatim}
%\hypersetup{
@@ -216,16 +258,25 @@ and the derived files
% \begin{itemize}
% \item Spaces are removed.
% \item Syntax characters (comma and equal sign) that are active
-% are replaces by the same characters with standard catcode.
+% 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={},...,|
+% |\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}
%
@@ -297,7 +348,7 @@ and the derived files
% can be used for the key and the value. If the value is not given,
% \cs{kv@value} has the meaning \cs{relax}.
%
-% \subsection{Do it all}
+% \subsection{Put it all together}
%
% \begin{declcs}{kvsetkeys}\,\M{family}\,\M{key value list}
% \end{declcs}
@@ -316,6 +367,31 @@ and the derived files
% |\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}%
+% \,\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}.
+%
% \section{Example}
%
% The following example prints a short piece of HTML code using
@@ -439,7 +515,7 @@ and the derived files
\fi
\expandafter\x\csname ver@kvsetkeys.sty\endcsname
\ProvidesPackage{kvsetkeys}%
- [2007/09/09 v1.2 Key value parser with default handler support (HO)]
+ [2007/09/29 v1.3 Key value parser with default handler support (HO)]
% \end{macrocode}
%
% \begin{macrocode}
@@ -454,6 +530,8 @@ and the derived files
}%
\catcode#1 #2\relax
}
+\TMP@EnsureCode{36}{3}% $
+\TMP@EnsureCode{38}{4}% &
\TMP@EnsureCode{39}{12}% '
\TMP@EnsureCode{44}{12}% ,
\TMP@EnsureCode{46}{12}% .
@@ -464,31 +542,112 @@ and the derived files
\TMP@EnsureCode{126}{13}% ~ (active)
% \end{macrocode}
%
+% \subsection{Package loading}
+%
+% \begin{macrocode}
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname RequirePackage\endcsname\relax
+ \input infwarerr.sty\relax
+ \input etexcmds.sty\relax
+\else
+ \RequirePackage{infwarerr}[2007/09/09]%
+ \RequirePackage{etexcmds}[2007/09/09]%
+\fi
+% \end{macrocode}
+%
+% \subsection{Check for \eTeX}
+%
+% \cs{unexpanded}, \cs{ifcsname}, and \cs{unless} are used if found.
% \begin{macrocode}
-\def\KVS@empty{}
-\long\def\@ReturnAfterFi#1\fi{\fi#1}
+\begingroup\expandafter\endgroup
+\ifcase0\ifetex@unexpanded
+ \expandafter\ifx\csname ifcsname\endcsname\relax
+ \else
+ \expandafter\ifx\csname unless\endcsname\relax
+ \else
+ 1%
+ \fi
+ \fi
+ \fi
+ \catcode`\$=9 % ignore
+ \catcode`\&=14 % comment
+\else % e-TeX
+ \catcode`\$=14 % comment
+ \catcode`\&=9 % ignore
+\fi
% \end{macrocode}
%
-% \subsection{Normalizing key value lists}
+% \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}
+\def\KVS@IfEmpty#1{%
+& \edef\KVS@Temp{\etex@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}
\def\kv@normalize#1{%
\begingroup
- \toks@{,#1}%
- \KVS@comma
- \KVS@equal
- \KVS@spaceA
- \KVS@spaceB{ }%
- \KVS@spaceC
- \KVS@spaceD{ }%
- \xdef\kv@global{\the\toks@}%
+ \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\kv@global
+ \let\kv@list\KVS@Global
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\KVS@comma}
+% \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.
@@ -497,154 +656,153 @@ and the derived files
\lccode`\,=`\,%
\lccode`\~=`\,%
\lowercase{\endgroup
- \def\KVS@comma{%
+ \def\KVS@Comma{%
\toks@\expandafter{\expandafter}\expandafter
- \KVS@@comma\the\toks@~\KVS@nil
+ \KVS@@Comma\the\toks@~\KVS@Nil
}%
- \def\KVS@@comma#1~#2\KVS@nil{%
- \toks@\expandafter{\the\toks@#1,}%
- \toks2{#2}%
- \edef\x{\the\toks2}%
- \ifx\x\KVS@empty
- \else
- \@ReturnAfterFi{%
- \KVS@@comma#2\KVS@nil
- }%
- \fi
+ \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{%
+ \toks@\expandafter{\the\toks@#1,}%
+ \expandafter\KVS@@SpaceComma\the\toks@\KVS@Nil
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\KVS@@SpaceComma}
+% \begin{macrocode}
+\def\KVS@@SpaceComma#1 ,#2\KVS@Nil{%
+ \KVS@IfEmpty{#2}{%
+ \toks@{#1}%
+ }{%
+ \toks@{#1,#2}%
+ \expandafter\KVS@@SpaceComma\the\toks@\KVS@Nil
}%
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\KVS@equal}
-% Converts active equal signs into catcode other characters.
+% \begin{macro}{\KVS@CommaSpace}
+% Removes spaces after the comma, may add commas at the end.
+% \begin{macrocode}
+\def\KVS@CommaSpace{%
+ \toks@\expandafter{\the\toks@, }%
+ \expandafter\KVS@@CommaSpace\the\toks@\KVS@Nil
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\KVS@@CommaSpace}
+% \begin{macrocode}
+\def\KVS@@CommaSpace#1, #2\KVS@Nil{%
+ \KVS@IfEmpty{#2}{%
+ \toks@{#1}%
+ }{%
+ \toks@{#1,#2}%
+ \expandafter\KVS@@CommaSpace\the\toks@\KVS@Nil
+ }%
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\KVS@CommaComma}
+% Replaces multiple commas by one comma.
+% \begin{macrocode}
+\def\KVS@CommaComma{%
+ \toks@\expandafter{\the\toks@,}%
+ \expandafter\KVS@@CommaComma\the\toks@\KVS@Nil
+}
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\KVS@@CommaComma}
+% \begin{macrocode}
+\def\KVS@@CommaComma#1,,#2\KVS@Nil{%
+ \toks@{#1,#2}%
+ \KVS@IfEmpty{#2}{%
+ }{%
+ \expandafter\KVS@@CommaComma\the\toks@\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@equal{%
+ \def\KVS@Equals{%
\toks@\expandafter{\expandafter}\expandafter
- \KVS@@equal\the\toks@~\KVS@nil
+ \KVS@@Equals\the\toks@~\KVS@Nil
}%
- \def\KVS@@equal#1~#2\KVS@nil{%
- \edef\x{\the\toks@}%
- \ifx\x\KVS@empty
- \toks@{#1}%
+ \def\KVS@@Equals#1~#2\KVS@Nil{%
+ \edef\KVS@Temp{\the\toks@}%
+ \ifx\KVS@Temp\KVS@Empty
+ \expandafter\KVS@FirstOfTwo
\else
- \toks@\expandafter{\the\toks@=#1}%
- \fi
- \toks2{#2}%
- \edef\x{\the\toks2}%
- \ifx\x\KVS@empty
- \else
- \@ReturnAfterFi{%
- \KVS@@equal#2\KVS@nil
- }%
+ \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@spaceA}
-% Removes one space after the equal sign. In theory also several
-% spaces could be removed, but this is not really necessary,
-% because \TeX\ usually collapses several spaces to one already.
+% \begin{macro}{\KVS@SpaceEquals}
+% Removes spaces before the equals sign.
% \begin{macrocode}
-\def\KVS@spaceA{%
- \toks@\expandafter{\expandafter}\expandafter
- \KVS@@spaceA\the\toks@= \KVS@nil
-}
-\def\KVS@@spaceA#1= #2\KVS@nil{%
- \edef\x{\the\toks@}%
- \ifx\x\KVS@empty
- \toks@{#1}%
- \else
- \toks@\expandafter{\the\toks@=#1}%
- \fi
- \toks2{#2}%
- \edef\x{\the\toks2}%
- \ifx\x\KVS@empty
- \else
- \@ReturnAfterFi{%
- \KVS@@spaceA#2\KVS@nil
- }%
- \fi
+\def\KVS@SpaceEquals#1{%
+ \toks@\expandafter{\the\toks@#1=}%
+ \expandafter\KVS@@SpaceEquals\the\toks@\KVS@Nil
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\KVS@spaceB}
-% Removes one space before the comma.
+% \begin{macro}{\KVS@@SpaceEquals}
% \begin{macrocode}
-\def\KVS@spaceB#1{%
- \toks@\expandafter{\expandafter}\expandafter
- \KVS@@spaceB\the\toks@#1,\KVS@nil
-}
-\def\KVS@@spaceB#1 ,#2\KVS@nil{%
- \edef\x{\the\toks@}%
- \ifx\x\KVS@empty
+\def\KVS@@SpaceEquals#1 =#2\KVS@Nil{%
+ \KVS@IfEmpty{#2}{%
\toks@{#1}%
- \else
- \toks@\expandafter{\the\toks@,#1}%
- \fi
- \toks2{#2}%
- \edef\x{\the\toks2}%
- \ifx\x\KVS@empty
- \else
- \@ReturnAfterFi{%
- \KVS@@spaceB#2\KVS@nil
- }%
- \fi
+ }{%
+ \toks@{#1=#2}%
+ \expandafter\KVS@@SpaceEquals\the\toks@\KVS@Nil
+ }%
}
% \end{macrocode}
% \end{macro}
-%
-% \begin{macro}{\KVS@spaceC}
-% Removes one space after the comma.
+% \begin{macro}{\KVS@EqualsSpace}
+% Removes spaces after the equals sign.
% \begin{macrocode}
-\def\KVS@spaceC{%
- \toks@\expandafter{\expandafter}\expandafter
- \KVS@@spaceC\the\toks@, \KVS@nil
-}
-\def\KVS@@spaceC#1, #2\KVS@nil{%
- \edef\x{\the\toks@}%
- \ifx\x\KVS@empty
- \toks@{#1}%
- \else
- \toks@\expandafter{\the\toks@,#1}%
- \fi
- \toks2{#2}%
- \edef\x{\the\toks2}%
- \ifx\x\KVS@empty
- \else
- \@ReturnAfterFi{%
- \KVS@@spaceC#2\KVS@nil
- }%
- \fi
+\def\KVS@EqualsSpace{%
+ \toks@\expandafter{\the\toks@= }%
+ \expandafter\KVS@@EqualsSpace\the\toks@\KVS@Nil
}
% \end{macrocode}
% \end{macro}
-% \begin{macro}{\KVS@spaceD}
-% Removes one space before the equal sign.
+% \begin{macro}{\KVS@@EqualsSpace}
% \begin{macrocode}
-\def\KVS@spaceD#1{%
- \toks@\expandafter{\expandafter}\expandafter
- \KVS@@spaceD\the\toks@#1=\KVS@nil
-}
-\def\KVS@@spaceD#1 =#2\KVS@nil{%
- \edef\x{\the\toks@}%
- \ifx\x\KVS@empty
+\def\KVS@@EqualsSpace#1= #2\KVS@Nil{%
+ \KVS@IfEmpty{#2}{%
\toks@{#1}%
- \else
- \toks@\expandafter{\the\toks@=#1}%
- \fi
- \toks2{#2}%
- \edef\x{\the\toks2}%
- \ifx\x\KVS@empty
- \else
- \@ReturnAfterFi{%
- \KVS@@spaceD#2\KVS@nil
- }%
- \fi
+ }{%
+ \toks@{#1=#2}%
+ \expandafter\KVS@@EqualsSpace\the\toks@\KVS@Nil
+ }%
}
% \end{macrocode}
% \end{macro}
@@ -661,67 +819,113 @@ and the derived files
% \end{macrocode}
% \end{macro}
% \begin{macro}{\kv@parse@normalized}
+% |#1|: key value list\\
+% |#2|: processor
% \begin{macrocode}
\def\kv@parse@normalized#1#2{%
- \KVS@parse#1,\KVS@nil{#2}%
+ \KVS@Parse#1,\KVS@Nil{#2}%
}
% \end{macrocode}
% \end{macro}
+% \begin{macro}{\KVS@Parse}
+% |#1,#2|: key value list\\
+% |#3|: processor
% \begin{macrocode}
-\def\KVS@parse#1,#2\KVS@nil#3{%
- \begingroup
- \toks@{#1}%
- \edef\x{\the\toks@}%
- \expandafter\endgroup
- \ifx\x\KVS@empty
- \else
- \KVS@process#1=\KVS@nil{#3}%
- \fi
- \begingroup
- \toks@{#2}%
- \edef\x{\the\toks@}%
- \expandafter\endgroup
- \ifx\x\KVS@empty
- \else
- \@ReturnAfterFi{%
- \KVS@parse#2\KVS@nil{#3}%
- }%
- \fi
+\def\KVS@Parse#1,#2\KVS@Nil#3{%
+ \KVS@IfEmpty{#1}{%
+ }{%
+ \KVS@Process#1=\KVS@Nil{#3}%
+ }%
+ \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}
-\def\KVS@process#1=#2\KVS@nil#3{%
+\def\KVS@Process#1=#2\KVS@Nil#3{%
\def\kv@key{#1}%
- \begingroup
- \toks@{#2}%
- \edef\x{\the\toks@}%
- \expandafter\endgroup
- \ifx\x\KVS@empty
+ \KVS@IfEmpty{#2}{%
\let\kv@value\relax
#3{#1}{}%
- \else
- \KVS@@process{#1}#2\KVS@nil{#3}%
- \fi
+ }{%
+ \KVS@@Process{#1}#2\KVS@Nil{#3}%
+ }%
}
-\def\KVS@@process#1#2=\KVS@nil#3{%
- \begingroup
- \toks@{#2}%
- \xdef\KVS@global{\the\toks@}%
- \endgroup
- \let\kv@value\KVS@global
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\KVS@@Process}
+% |#1|: key\\
+% |#2|: value\\
+% |#3|: processor
+% \begin{macrocode}
+\def\KVS@@Process#1#2=\KVS@Nil#3{%
+& \edef\kv@value{\etex@unexpanded{#2}}%
+$ \begingroup
+$ \toks@{#2}%
+$ \xdef\KVS@Global{\the\toks@}%
+$ \endgroup
+$ \let\kv@value\KVS@Global
#3{#1}{#2}%
}
% \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@IfEmpty{#2}{%
+ }{%
+ \KVS@CommaParse#2\KVS@Nil{#3}%
+ }%
+}
+% \end{macrocode}
+% \end{macro}
%
% \subsection{Processing key value pairs}
%
% \begin{macro}{\kv@processor@default}
% \begin{macrocode}
\def\kv@processor@default#1#2#3{%
- \begingroup\expandafter\expandafter\expandafter\endgroup
- \expandafter\ifx\csname KV@#1@#2\endcsname\relax
- \begingroup\expandafter\expandafter\expandafter\endgroup
- \expandafter\ifx\csname KVS@#1@handler\endcsname\relax
+& \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
\csname KVS@#1@handler\endcsname{#2}{#3}%
@@ -729,8 +933,9 @@ and the derived files
\fi
\else
\ifx\kv@value\relax
- \begingroup\expandafter\expandafter\expandafter\endgroup
- \expandafter\ifx\csname KV@#1@#2@default\endcsname\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
@@ -747,9 +952,13 @@ and the derived files
% \begin{macro}{\kv@set@family@handler}
% \begin{macrocode}
\def\kv@set@family@handler#1{%
- \KVS@set@family@handler{#1}\@nil
+ \KVS@SetFamilyHandler{#1}\@nil
}
-\def\KVS@set@family@handler#1\@nil#{%
+% \end{macrocode}
+% \end{macro}
+% \begin{macro}{\KVS@SetFamilyHandler}
+% \begin{macrocode}
+\def\KVS@SetFamilyHandler#1\@nil#{%
\expandafter\def\csname KVS@#1@handler\endcsname##1##2%
}
% \end{macrocode}
@@ -757,15 +966,6 @@ and the derived files
%
% \subsection{Error handling}
%
-% \begin{macrocode}
-\begingroup\expandafter\expandafter\expandafter\endgroup
-\expandafter\ifx\csname RequirePackage\endcsname\relax
- \input infwarerr.sty\relax
-\else
- \RequirePackage{infwarerr}[2007/09/09]%
-\fi
-% \end{macrocode}
-%
% \begin{macro}{\kv@error@novalue}
% \begin{macrocode}
\def\kv@error@novalue{%
@@ -863,6 +1063,259 @@ and the derived files
%</test1>
% \end{macrocode}
%
+% \subsection{Macro tests}
+%
+% \subsubsection{Preamble}
+%
+% \begin{macrocode}
+%<*test2>
+\NeedsTeXFormat{LaTeX2e}
+\nofiles
+\documentclass{article}
+%<noetex>\let\SavedUnexpanded\unexpanded
+%<noetex>\let\unexpanded\UNDEFINED
+\makeatletter
+\chardef\KVS@TestMode=1 %
+\makeatother
+\usepackage{kvsetkeys}[2007/09/29]
+%<noetex>\let\unexpanded\SavedUnexpanded
+\usepackage{qstest}
+\IncludeTests{*}
+\LogTests{log}{*}{*}
+% \end{macrocode}
+%
+% \subsubsection{Time}
+%
+% \begin{macrocode}
+\begingroup\expandafter\expandafter\expandafter\endgroup
+\expandafter\ifx\csname pdfresettimer\endcsname\relax
+\else
+ \makeatletter
+ \newcount\SummaryTime
+ \newcount\TestTime
+ \SummaryTime=\z@
+ \newcommand*{\PrintTime}[2]{%
+ \typeout{%
+ [Time #1: \strip@pt\dimexpr\number#2sp\relax\space s]%
+ }%
+ }%
+ \newcommand*{\StartTime}[1]{%
+ \renewcommand*{\TimeDescription}{#1}%
+ \pdfresettimer
+ }%
+ \newcommand*{\TimeDescription}{}%
+ \newcommand*{\StopTime}{%
+ \TestTime=\pdfelapsedtime
+ \global\advance\SummaryTime\TestTime
+ \PrintTime\TimeDescription\TestTime
+ }%
+ \let\saved@qstest\qstest
+ \let\saved@endqstest\endqstest
+ \def\qstest#1#2{%
+ \saved@qstest{#1}{#2}%
+ \StartTime{#1}%
+ }%
+ \def\endqstest{%
+ \StopTime
+ \saved@endqstest
+ }%
+ \AtEndDocument{%
+ \PrintTime{summary}\SummaryTime
+ }%
+ \makeatother
+\fi
+% \end{macrocode}
+%
+% \subsubsection{Test sets}
+%
+% \begin{macrocode}
+\makeatletter
+\def\@makeactive#1{%
+ \catcode`#1=13\relax
+}
+\@makeactive\,
+\def,{\errmessage{COMMA}}
+\@makeother\,
+\@makeactive\=
+\def={\errmessage{EQUALS}}
+\@makeother\=
+
+\begin{qstest}{normalize}{normalize,active-chars,space-removal}%
+ \def\Test#1#2{%
+ \@makeother\,%
+ \@makeother\=%
+ \scantokens{\toks@={#2}}%
+ \edef\Result{\the\toks@}%
+ \@makeother\,%
+ \@makeother\=%
+ \@Test{#1}%
+ \@makeactive\,%
+ \@Test{#1}%
+ \@makeactive\=%
+ \@Test{#1}%
+ \@makeother\,%
+ \@Test{#1}%
+ \@makeother\=%
+ }%
+ \def\@Test#1{%
+ \scantokens{\kv@normalize{#1}}%
+ \expandafter\expandafter\expandafter\Expect
+ \expandafter\expandafter\expandafter
+ {\expandafter\kv@list\expandafter}\expandafter{\Result}%
+ \Expect*{\ifx\kv@list\Result true\else false\fi}{true}%
+ }%
+ \Test{}{,}%
+ \Test{,}{,}%
+ \Test{,,}{,}%
+ \Test{,,,}{,}%
+ \Test{ , }{,}%
+ \Test{{a}}{,{a},}%
+ \Test{,{a}}{,{a},}%
+ \Test{{a},}{,{a},}%
+ \Test{{a},{b}}{,{a},{b},}%
+ \Test{{b}={c},{}=,{}={},{d}=}{,{b}={c},{}=,{}={},{d}=,}%
+ \Test{{}}{,{},}%
+ \Test{{},{},{}}{,{},{},{},}%
+ \Test{=}{,=,}%
+ \Test{=,=,=}{,=,=,=,}%
+ \def\TestSet#1{%
+ \Test{#1#1}{,}%
+ \Test{#1#1,#1#1}{,}%
+ \Test{#1#1,#1#1,#1#1}{,}%
+ \Test{#1#1#1#1#1}{,}%
+ \Test{{a}#1#1=#1#1{b}}{,{a}={b},}%
+ }%
+ \TestSet{ }%
+ \begingroup
+ \let\saved@normalize\kv@normalize
+ \def\kv@normalize#1{%
+ \saved@normalize{#1}%
+ \@onelevel@sanitize\kv@list
+ \@onelevel@sanitize\Result
+ }%
+ \Test{#,#=#,{#}={#},{#}=,{#}}{,#,#=#,{#}={#},{#}=,{#},}%
+ \endgroup
+ \begingroup
+ \def\Test#1#2{%
+ \edef\Result{#2}%
+ \@Test{#1}%
+ }%
+ \Test{{ a = b }}{,{ a = b },}%
+ \@makeactive\,%
+ \Test{{,}}{\string,{\noexpand,}\string,}%
+ \@makeother\,%
+ \@makeactive\=%
+ \Test{a={=}}{,a\string={\noexpand=},}%
+ \endgroup
+ \Test{a=b}{,a=b,}%
+ \Test{a={b}}{,a={b},}%
+ \Test{a ={b}}{,a={b},}%
+ \Test{a= {b}}{,a={b},}%
+ \Test{a = {b}}{,a={b},}%
+ \Test{a = {b} ,}{,a={b},}%
+ \Test{a}{,a,}%
+ \Test{ a}{,a,}%
+ \Test{a }{,a,}%
+ \Test{ a }{,a,}%
+ \Test{, a ,}{,a,}%
+ \Test{, a b ,}{,a b,}%
+ \Test{,a ,}{,a,}%
+ \Test{ a =}{,a=,}%
+ \Test{ a = }{,a=,}%
+ \Test{a =}{,a=,}%
+ \Test{{a} =}{,{a}=,}%
+ \Test{{a}= {}}{,{a}={},}%
+ \Test{, a = {}}{,a={},}%
+ \Test{a,,b}{,a,b,}%
+ \Test{a=\fi}{,a=\fi,}%
+ \Test{a=\iffalse}{,a=\iffalse,}%
+ \Test{a=\iffalse,b=\fi}{,a=\iffalse,b=\fi,}%
+\end{qstest}
+
+\begin{qstest}{parse}{parse,brace-removal}
+ \def\Processor#1#2{%
+ \expandafter\Expect\expandafter{\kv@key}{#1}%
+ \toks@{#2}%
+ \edef\x{\the\toks@}%
+ \ifx\kv@value\relax
+ \Expect*{\the\toks@}{}%
+ \def\Value{<>}%
+ \else
+ \edef\Value{[\the\toks@]}%
+ \@onelevel@sanitize\Value
+ \fi
+ \toks@{#1}%
+ \ifx\Result\@empty
+ \edef\Result{[\the\toks@]=\Value}%
+ \else
+ \edef\Result{\Result,[\the\toks@]=\Value}%
+ \fi
+ \@onelevel@sanitize\Result
+ }%
+ \def\Test#1#2{%
+ \let\Result\@empty
+ \kv@parse{#1}\Processor
+ \Expect*{\Result}{#2}%
+ }%
+ \Test{}{}%
+ \Test{{}}{}%
+ \Test{{{}}}{[]=<>}%
+ \Test{{{{}}}}{[{}]=<>}%
+ \Test{a}{[a]=<>}%
+ \Test{{a}}{[a]=<>}%
+ \Test{{a}}{[a]=<>}%
+ \Test{{{a}}}{[a]=<>}%
+ \Test{{{{a}}}}{[{a}]=<>}%
+ \Test{a=}{[a]=[]}%
+ \Test{{a}=}{[a]=[]}%
+ \Test{{{a}}=}{[{a}]=[]}%
+ \Test{a={}}{[a]=[]}%
+ \Test{{a}={{}}}{[a]=[{}]}%
+ \Test{a=b}{[a]=[b]}%
+ \Test{a=\fi}{[a]=[\fi]}%
+ \Test{a=\iffalse}{[a]=[\iffalse]}%
+ \Test{a=\iffalse,b=\fi}{[a]=[\iffalse],[b]=[\fi]}%
+ \Test{{ a = b }}{[ a ]=[ b ]}%
+ \Test{{{ a = b }}}{[ a = b ]=<>}%
+\end{qstest}
+
+\begin{qstest}{comma}{comma,parse}
+ \def\Processor#1{%
+ \expandafter\Expect\expandafter{\comma@entry}{#1}%
+ \toks@{#1}%
+ \ifx\Result\@empty
+ \edef\Result{[\the\toks@]}%
+ \else
+ \edef\Result{\Result,[\the\toks@]}%
+ \fi
+ \@onelevel@sanitize\Result
+ }%
+ \def\Test#1#2{%
+ \let\Result\@empty
+ \comma@parse{#1}\Processor
+ \Expect*{\Result}{#2}%
+ }%
+\tracingmacros=1
+ \Test{}{}%
+ \Test{{}}{}%
+ \Test{{{}}}{[{}]}%
+ \Test{a}{[a]}%
+ \Test{{a}}{[a]}%
+ \Test{{{a}}}{[{a}]}%
+ \Test{a=}{[a=]}%
+ \Test{a\fi}{[a\fi]}%
+ \Test{a\iffalse}{[a\iffalse]}%
+ \Test{\iffalse,\fi}{[\iffalse],[\fi]}%
+ \Test{ a , b , c }{[a],[b],[c]}%
+ \Test{ { } ,{ }, { }, { } , { } }{[ ],[ ],[ ],[ ],[ ]}%
+ \Test{ {{}} ,{{}}, {{}}, {{}} , {{}} }{[{}],[{}],[{}],[{}],[{}]}%
+\end{qstest}
+
+\begin{document}
+\end{document}
+%</test2>
+% \end{macrocode}
+%
% \section{Installation}
%
% \subsection{Download}
@@ -926,6 +1379,8 @@ and the derived files
% kvsetkeys.pdf & doc/latex/oberdiek/kvsetkeys.pdf\\
% kvsetkeys-example.tex & doc/latex/oberdiek/kvsetkeys-example.tex\\
% kvsetkeys-test1.tex & doc/latex/oberdiek/kvsetkeys-test1.tex\\
+% kvsetkeys-test2.tex & doc/latex/oberdiek/kvsetkeys-test2.tex\\
+% kvsetkeys-test3.tex & doc/latex/oberdiek/kvsetkeys-test3.tex\\
% kvsetkeys.dtx & source/latex/oberdiek/kvsetkeys.dtx\\
% \end{tabular}^^A
% }^^A
@@ -1073,6 +1528,19 @@ and the derived files
% \item
% Catcode section rewritten.
% \end{Version}
+% \begin{Version}{2007/09/29 v1.4}
+% \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}
% \end{History}
%
% \PrintIndex