diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3keyval.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3keyval.dtx | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3keyval.dtx b/Master/texmf-dist/source/latex/expl3/l3keyval.dtx new file mode 100644 index 00000000000..8848946602a --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3keyval.dtx @@ -0,0 +1,666 @@ +% \iffalse +%% File: l3keyval.dtx Copyright (C) 2006 LaTeX3 project +%% +%% It may be distributed and/or modified under the conditions of the +%% LaTeX Project Public License (LPPL), either version 1.3c of this +%% license or (at your option) any later version. The latest version +%% of this license is in the file +%% +%% http://www.latex-project.org/lppl.txt +%% +%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% and all files in that bundle must be distributed together. +%% +%% The released version of this bundle is available from CTAN. +%% +%% ----------------------------------------------------------------------- +%% +%% The development version of the bundle can be found at +%% +%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% +%% for those people who are interested. +%% +%%%%%%%%%%% +%% NOTE: %% +%%%%%%%%%%% +%% +%% Snapshots taken from the repository represent work in progress and may +%% not work or may contain conflicting material! We therefore ask +%% people _not_ to put them into distributions, archives, etc. without +%% prior consultation with the LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3keyval.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental keyval processing} +% \iffalse +%<*driver> +\documentclass{l3doc} + +\begin{document} +\DocInput{l3keyval.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{l3keyval} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Key-value parsing} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% \section{Introduction} +% +% Currently, this module only provides functions for extracting keys +% and values from a list. How this information is used is up to the +% programmer. +% +% A \meta{keyval list} is a list consisting of +% \begin{verbatim} +% key 1 = value 1 , +% key 2 , +% key 3 = value 3 , +% \end{verbatim} +% +% The function names for retrieving the keys and values are long but +% explain what they do. All these functions start with the name +% |\KV_parse_|. If a value is surrounded by braces, one level (and +% only one) is removed from the value. This is useful if you need to +% input a value which contains |=| or |,|. There are two primary +% actions we can take on a \meta{keyval list}. +% \begin{itemize} +% \item A \meta{keyval list} can be sanitized so that top level active +% commas or equal signs are converted into catcode 12. When +% declaring templates in the preamble one can probably safely assume +% that there are no active commas or equals; these things should +% only be active in the document. The name for this is either +% |no_sanitize| or |sanitize|. +% \item Spaces on either side of a key or value can be trimmed. When +% using the \LaTeX3 programming interface, spaces are automatically +% ignored so there it would be a waste of time to search for extra +% spaces since there would be none. At the document level however, +% spaces must be removed. The name for this is either +% |no_space_removal| or |space_removal|. Note that when +% |space_removal| is called you get an additional option where you +% can decide if one level of braces should be stripped from the key +% and/or value; see the description of the boolean +% |\l_KV_remove_one_level_of_braces_bool| for details. +% \end{itemize} +% +% During the parsing process, keys or values are not expanded and no +% |#|s are doubled. When the parsing process is over, the keys and +% values are executed in the form +% \begin{quote} +% "\KV_key_value_elt:nn{key 1}{value 1}" \\ +% "\KV_key_no_value_elt:n{key 2}" \\ +% "\KV_key_value_elt:nn{key 3}{value 3}" +% \end{quote} +% It is up to the programmer to provide a suitable definition of these +% two functions before starting the parsing process. +% +% +% \subsection{Functions} +% +% +% +% +% \begin{function}{ +% \KV_parse_no_space_removal_no_sanitize:n | +% } +% \begin{syntax} +% "\KV_parse_no_space_removal_no_sanitize:n" "{"<keyval list>"}" +% \end{syntax} +% Parses the keys and values literally. For use when spaces are +% ignored and |=| and |,| have normal catcodes. +% \end{function} +% +% \begin{function}{ +% \KV_parse_space_removal_no_sanitize:n | +% } +% \begin{syntax} +% "\KV_parse_space_removal_no_sanitize:n" "{"<keyval list>"}" +% \end{syntax} +% As above but also removes spaces around keys and values. For use +% when spaces are not ignored. +% \end{function} +% +% \begin{function}{ +% \KV_parse_space_removal_sanitize:n | +% } +% \begin{syntax} +% "\KV_parse_space_removal_sanitize:n" "{"<keyval list>"}" +% \end{syntax} +% As above but additionally also replaces top-level active |=| and +% |,| with harmless versions. +% \end{function} +% +% \begin{variable}{ +% \l_KV_remove_one_level_of_braces_bool | +% } +% \begin{syntax} +% \end{syntax} +% This boolean controls whether or not one level of braces is +% stripped from the key and value. The default value for this +% boolean is \meta{true} so that exactly one level of braces is +% stripped. For certain applications it is desirable to keep the +% braces in which case the programmer just has to set the boolean +% false temporarily. Setting this boolean has no effect when you +% call the |no_space_removal| functions since not stripping braces +% is a rare request and would clutter the otherwise elegant code of +% the |no_space_removal| functions for very little gain. If you need +% to preserve braces choose the slower |space_removal| functions. +% \end{variable} +% +% \begin{function}{ +% \KV_key_no_value_elt:n | +% \KV_key_value_elt:nn | +% } +% \begin{syntax} +% "\KV_key_no_value_elt:n" "{"<key>"}" \\ +% "\KV_key_value_elt:n" "{"<key>"}" "{"<value>"}" +% \end{syntax} +% Functions returned by the |\KV_parse_| functions. The default +% definition of these two functions is an error message! +% \end{function} +% +% +% \StopEventually{} +% +% \section{Implementation} +% +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\RequirePackage{l3quark} +\RequirePackage{l3toks} +\RequirePackage{l3int} +\RequirePackage{l3token} +%</package> +%<*initex|package> +% \end{macrocode} +% +% +% +% +% \begin{macro}{\l_KV_tmpa_tlp} +% \begin{macro}{\l_KV_tmpb_tlp} +% \begin{macro}{\c_KV_single_equal_sign_tlp} +% Various useful things. +% \begin{macrocode} +\tlp_new:Nn\l_KV_tmpa_tlp{} +\tlp_new:Nn\l_KV_tmpb_tlp{} +\tlp_new:Nn \c_KV_single_equal_sign_tlp{=} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_KV_parse_toks} +% \begin{macro}{\l_KV_currkey_toks} +% \begin{macro}{\l_KV_currval_toks} +% Some more useful things. +% \begin{macrocode} +\toks_new:N \l_KV_parse_toks +\toks_new:N \l_KV_currkey_toks +\toks_new:N \l_KV_currval_toks +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_KV_remove_one_level_of_braces_bool} +% A boolean to control +% \begin{macrocode} +\bool_new:N \l_KV_remove_one_level_of_braces_bool +\bool_set_true:N \l_KV_remove_one_level_of_braces_bool +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KV_sanitize_outerlevel_active_equals:N} +% \begin{macro}{\KV_sanitize_outerlevel_active_commas:N} +% Some functions for sanitizing top level equals and commas. Replace +% |=|$\sb{13}$ and |,|$\sb{13}$ with |=|$\sb{12}$ and |,|$\sb{12}$ +% resp. +% \begin{macrocode} +\group_begin: +\char_set_catcode:nn{`\=}{13} +\char_set_catcode:nn{`\,}{13} +\char_set_lccode:nn{`\8}{`\=} +\char_set_lccode:nn{`\9}{`\,} +\tlist_to_lowercase:n{\group_end: +\def_new:Npn \KV_sanitize_outerlevel_active_equals:N #1{ + \tlp_replace_all_in:Nnn #1 = 8 +} +\def_new:Npn \KV_sanitize_outerlevel_active_commas:N #1{ + \tlp_replace_all_in:Nnn #1 , 9 +} +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% +% +% \begin{macro}{\KV_remove_surrounding_spaces:nw} +% \begin{macro}{\KV_remove_surrounding_spaces_auxi:w} +% \begin{macro}{\KV_remove_surrounding_spaces_auxii:w} +% \begin{macro}{\KV_set_key_element:w} +% \begin{macro}{\KV_set_value_element:w} +% The macro |\KV_remove_surrounding_spaces:Nw| removes a possible +% leading space plus a possible ending space from its second +% argument and stores it in the token register |#1|. +% +% Based on Around the Bend No.~15 but with some enhancements. For +% instance, this definition is purely expandable. +% +% We use a funny token |Q|$\sb3$ as a delimiter. +% \begin{macrocode} +\group_begin: +\char_set_catcode:nn{`\Q}{3} +% \end{macrocode} +% \begin{macrocode} +\gdef_long_new:Npn\KV_remove_surrounding_spaces:nw#1#2\q_nil{ +% \end{macrocode} +% The idea in this processing is to use a Q with strange catcode to +% remove a trailing space. But first, how to get this expansion going? +% +% If you have read the fine print in the \textsf{l3expan} module, +% you'll know that the |f| type expansion will expand until the first +% non-expandable token is seen and if this token is a space, it will +% be gobbled. Sounds useful for removing a leading space but we also +% need to make sure that it does nothing but removing that space! +% Therefore we prepend the argument to be trimmed with an +% |\exp_not:N|. Now why is that? |\exp_not:N| in itself is an +% expandable command so will allow the |f| expansion to continue. If +% the first token in the argument to be trimmed is a space, it will be +% gobbled and the expansion stop. If the first token isn't a space, +% the |\exp_not:N| turns it temporarily into |\scan_stop:| which is +% unexpandable. The processing stops but the token following directly +% after |\exp_not:N| is now back to normal. +% +% The function here allows you to insert arbitrary functions in the +% first argument but they should all be with an |f| type +% expansion. For the application in this module, we use +% |\toks_set:Nf|. +% +% Once the expansion has been kick-started, we apply +% |\KV_remove_surrounding_spaces_auxi:w| to the replacement text of +% |#2|, adding a leading |\exp_not:N|. Note that no braces are +% stripped off of the original argument. +% \begin{macrocode} + #1{\KV_remove_surrounding_spaces_auxi:w \exp_not:N#2Q~Q} +} +% \end{macrocode} +% |\KV_remove_surrounding_spaces_auxi:w| removes a trailing space if +% present, then calls |\KV_remove_surrounding_spaces_auxii:w| to clean +% up any leftover bizarre Qs. In order for +% |\KV_remove_surrounding_spaces_auxii:w| to work properly we need to +% put back a Q first. +% \begin{macrocode} +\gdef_long_new:Npn\KV_remove_surrounding_spaces_auxi:w#1~Q{ + \KV_remove_surrounding_spaces_auxii:w #1 Q +} +% \end{macrocode} +% Now all that is left to do is remove a leading space which should be +% taken care of by the function used to initiate the expansion. Simply +% return the argument before the funny Q. +% \begin{macrocode} +\gdef_long_new:Npn\KV_remove_surrounding_spaces_auxii:w#1Q#2{#1} +% \end{macrocode} +% Here are some specialized versions of the above. They do exactly +% what we want in one go. First trim spaces from the value and then +% put the result surrounded in braces onto |\l_KV_parse_toks|. +% \begin{macrocode} +\gdef_long_new:Npn\KV_add_value_element:w\q_stop#1\q_nil{ + \toks_set:Nf\l_KV_currval_toks { + \KV_remove_surrounding_spaces_auxi:w \exp_not:N#1Q~Q + } + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN {\toks_use:N \l_KV_currval_toks} + } +} +% \end{macrocode} +% When storing the key we firstly remove spaces plus the prepended +% |\q_no_value|. +% \begin{macrocode} +\gdef_long_new:Npn\KV_set_key_element:w#1\q_nil{ + \toks_set:Nf\l_KV_currkey_toks + { + \exp_after:NN\KV_remove_surrounding_spaces_auxi:w + \exp_after:NN\exp_not:N\use_none:n #1Q~Q + } +% \end{macrocode} +% Afterwards we gobble an extra level of braces if that's what we are +% asked to do. +% \begin{macrocode} + \bool_if:NT \l_KV_remove_one_level_of_braces_bool + { + \toks_set:Nd \l_KV_currkey_toks{ + \exp_after:NN \KV_add_element_aux:w + \toks_use:N \l_KV_currkey_toks \q_nil + } + } +} +\group_end: +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\KV_add_element_aux:w} +% A helper function for fixing braces around keys and values. +% \begin{macrocode} +\def_long_new:Npn \KV_add_element_aux:w#1\q_nil{#1} +% \end{macrocode} +% \end{macro} +% +% +% Parse a list of keyvals, put them into list form with entries like +% |\KV_key_no_value_elt:n{key1}| and |\KV_key_value_elt:nn{key2}{val2}|. +% +% \begin{macro}{\KV_parse_sanitize_aux:n} +% The slow parsing algorithm sanitizes active commas and equal signs +% at the top level first. Then uses |#1| as inspector of each +% element in the comma list. +% \begin{macrocode} +\def_long_new:Npn \KV_parse_sanitize_aux:n #1{ + \group_begin: + \toks_clear:N \l_KV_parse_toks + \tlp_set:Nx\l_KV_tmpa_tlp{\exp_not:n{#1}} + \KV_sanitize_outerlevel_active_equals:N\l_KV_tmpa_tlp + \KV_sanitize_outerlevel_active_commas:N\l_KV_tmpa_tlp + \exp_after:NN \KV_parse_elt:w \exp_after:NN\q_no_value \l_KV_tmpa_tlp,\q_nil, +% \end{macrocode} +% We evaluate the parsed keys and values outside the group so the +% token register is restored to its previous value. +% \begin{macrocode} + \exp_after:NN\group_end: + \toks_use:N \l_KV_parse_toks +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\KV_parse_no_sanitize_aux:n} +% Like above but we don't waste time sanitizing. This is probably +% the one we will use for preamble parsing where catcodes of |=| and +% |,| are as expected! +% \begin{macrocode} +\def_long_new:Npn \KV_parse_no_sanitize_aux:n #1{ + \group_begin: + \toks_clear:N \l_KV_parse_toks + \KV_parse_elt:w \q_no_value #1,\q_nil, + \exp_after:NN\group_end: + \toks_use:N \l_KV_parse_toks +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\KV_parse_elt:w} +% This function will always have a |\q_no_value| stuffed in as the +% rightmost token in |#1|. In case there was a blank entry in the +% comma separated list we just run it again. The |\use_none:n| makes +% sure to gobble the quark |\q_no_value|. A similar test is made to +% check if we hit the end of the recursion. +% \begin{macrocode} +\def_long:Npn \KV_parse_elt:w #1,{ + \tlist_if_blank:oTF{\use_none:n #1} + { \KV_parse_elt:w \q_no_value } + { + \quark_if_nil:oF {\use_arg_ii:nn #1 } +% \end{macrocode} +% If we made it to here we can start parsing the key and value. When +% done try, try again. +% \begin{macrocode} + { + \KV_split_key_value_current:w #1==\q_nil + \KV_parse_elt:w \q_no_value + } + } +} +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\KV_split_key_value_current:w} +% The function called to split the keys and values. +% \begin{macrocode} +\let_new:NN \KV_split_key_value_current:w \ERROR +% \end{macrocode} +% \end{macro} +% +% We provide two functions for splitting keys and values. The reason +% being that most of the time, we should probably be in the special +% coding regime where spaces are ignored. Hence it makes no sense to +% spend time searching for extra space tokens and we can do the +% settings directly. When comparing these two versions (neither doing +% any sanitizing) the |no_space_removal| version is more than 40\% +% faster than |space_removal|. +% +% It is up to functions like |\DeclareTemplate| to check which catcode +% regime is active and then pick up the version best suited for it. +% +% +% +% \begin{macro}{\KV_split_key_value_space_removal:w} +% \begin{macro}{\KV_split_key_value_space_removal_detect_error:wTF} +% \begin{macro}{\KV_split_key_value_space_removal_aux:w} +% The code below removes extraneous spaces around the keys and +% values plus one set of braces around the entire value. +% +% Unlike the version to be used when spaces are ignored, this one +% only grabs the key which is everything up to the first = and save +% the rest for closer inspection. Reason is that if a user has +% entered |mykey={{myval}},| then the outer braces have already been +% removed before we even look at what might come after the key. So +% this is slightly more tedious (but only slightly) but at least it +% always removes only one level of braces. +% \begin{macrocode} +\def_long_new:Npn \KV_split_key_value_space_removal:w #1 = #2\q_nil{ +% \end{macrocode} +% First grab the key. +% \begin{macrocode} + \KV_set_key_element:w#1\q_nil +% \end{macrocode} +% Then we start checking. If only a key was entered, |#2| contains +% |=| and nothing else, so we test for that first. +% \begin{macrocode} + \tlp_set:Nx\l_KV_tmpa_tlp{\exp_not:n{#2}} + \tlp_if_eq:NNTF\l_KV_tmpa_tlp\c_KV_single_equal_sign_tlp +% \end{macrocode} +% Then we just insert the default key. +% \begin{macrocode} + { + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN \KV_key_no_value_elt:n + \exp_after:NN {\toks_use:N\l_KV_currkey_toks} + } + } +% \end{macrocode} +% Otherwise we must take a closer look at what is left. The remainder +% of the original list up to the comma is now stored in |#2| plus an +% additional |==|, which wasn't gobbled during the initial reading of +% arguments. If there is an error then we can see at least one more +% |=| so we call an auxiliary function to check for this. +% \begin{macrocode} + { + \KV_split_key_value_space_removal_detect_error:wTF#2\q_no_value\q_nil + {\KV_split_key_value_space_removal_aux:w \q_stop #2} + {\ERROR} + } +} +% \end{macrocode} +% The error test. +% \begin{macrocode} +\def_long_new:Npn + \KV_split_key_value_space_removal_detect_error:wTF#1=#2#3\q_nil{ + \tlist_if_head_eq_meaning:nNTF{#3}\q_no_value +} +% \end{macrocode} +% Now we can start extracting the value. Recall that |#1| here starts +% with |\q_stop| so all braces are still there! First we try to see +% how much is left if we gobble three brace groups from |#1|. If |#1| +% is empty or blank, all three quarks are gobbled. If |#1| consists of +% exactly one token or brace group, only the latter quark is left. +% \begin{macrocode} +\def_long_new:Npn \KV_val_preserve_braces:NnN #1#2#3{{#2}} +\def_long_new:Npn\KV_split_key_value_space_removal_aux:w #1=={ + \tlp_set:Nx\l_KV_tmpa_tlp{\exp_not:o{\use_none:nnn#1\q_nil\q_nil}} + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN \KV_key_value_elt:nn + \exp_after:NN {\toks_use:N\l_KV_currkey_toks} + } +% \end{macrocode} +% If there a blank space or nothing at all, |\l_KV_tmpa_tlp| is now +% completely empty. +% \begin{macrocode} + \tlp_if_empty:NTF\l_KV_tmpa_tlp +% \end{macrocode} +% We just put an empty value on the stack. +% \begin{macrocode} + { \toks_put_right:Nn\l_KV_parse_toks{{}} } + { +% \end{macrocode} +% If there was exactly one brace group or token in |#1|, +% |\l_KV_tmpa_tlp| is now equal to |\q_nil|. Then we can just pick it +% up as the second argument of |#1|. This will also take care of any +% spaces which might surround it. +% \begin{macrocode} + \quark_if_nil:NTF\l_KV_tmpa_tlp + { + \bool_if:NTF \l_KV_remove_one_level_of_braces_bool + { + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN{\use_arg_ii:nnn #1\q_nil} + } + } + { + \toks_put_right:No\l_KV_parse_toks{ + \exp_after:NN{\KV_val_preserve_braces:NnN #1\q_nil} + } + } + } +% \end{macrocode} +% Otherwise we grab the value. +% \begin{macrocode} + { \KV_add_value_element:w #1\q_nil } + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\KV_split_key_value_no_space_removal:w} +% This version is for when in the special coding regime where spaces +% are ignored so there is no need to do any fancy space hacks, +% however fun they may be. Since there are no spaces, a set of +% braces around a value is automatically stripped by \TeX. +% \begin{macrocode} +\def_long_new:Npn \KV_split_key_value_no_space_removal:w #1#2=#3=#4\q_nil{ + \tlp_set:Nn\l_KV_tmpa_tlp{#4} + \tlp_if_empty:NTF \l_KV_tmpa_tlp + { + \toks_put_right:Nn\l_KV_parse_toks{\KV_key_no_value_elt:n{#2}} + } + { + \tlp_if_eq:NNTF\c_KV_single_equal_sign_tlp\l_KV_tmpa_tlp + { + \toks_put_right:Nn\l_KV_parse_toks{\KV_key_value_elt:nn{#2}{#3}} + } + {\ERROR} + } +} +% \end{macrocode} +% \end{macro} +% +% +% +% \begin{macro}{\KV_key_no_value_elt:n} +% \begin{macro}{\KV_key_value_elt:nn} +% \begin{macrocode} +\def_long_new:Npn \KV_key_no_value_elt:n #1{\ERROR} +\def_long_new:Npn \KV_key_value_elt:nn #1#2{\ERROR} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% +% +% \begin{macro}{\KV_parse_no_space_removal_no_sanitize:n} +% Finally we can put all the things +% together. |\KV_parse_no_space_removal_no_sanitize:n| is the +% version that disallows unmatched conditional and does no space +% removal. +% \begin{macrocode} +\def_new:Npn \KV_parse_no_space_removal_no_sanitize:n { + \let:NN \KV_split_key_value_current:w \KV_split_key_value_no_space_removal:w + \KV_parse_no_sanitize_aux:n +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\KV_parse_space_removal_sanitize:n} +% \begin{macro}{\KV_parse_space_removal_no_sanitize:n} +% The other varieties can be defined in a similar manner. For the +% version needed at the document level, we can use this one. +% \begin{macrocode} +\def_new:Npn \KV_parse_space_removal_sanitize:n { + \let:NN \KV_split_key_value_current:w \KV_split_key_value_space_removal:w + \KV_parse_sanitize_aux:n +} +% \end{macrocode} +% For preamble use by the non-programmer this is probably best. +% \begin{macrocode} +\def_new:Npn \KV_parse_space_removal_no_sanitize:n { + \let:NN \KV_split_key_value_current:w \KV_split_key_value_space_removal:w + \KV_parse_no_sanitize_aux:n +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% \begin{macrocode} +%</initex|package> +%<*showmemory> +\showMemUsage +%</showmemory> +% \end{macrocode} +% +% \endinput +% +% $Log$ +% Revision 1.4 2006/07/25 22:38:58 morten +% Removed spurious \exp_after:NN in \KV_add_value_element:w. Sigh. +% +% Revision 1.3 2006/07/25 22:34:03 morten +% Fixed silly bug in \KV_set_key_element:w plus clean-up of code +% +% Revision 1.2 2006/07/25 16:21:30 morten +% Allow values to contain unmatched conditionals such as `val +% \fi:'. Provide option to not strip any braces at all. +% +% Revision 1.1 2006/01/27 10:14:24 morten +% Initial version of keyval parser +% |