diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/oberdiek/kvsetkeys.dtx | 854 |
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 |