3

I have a project for which I make extensive use of the great xkeyval package. However, I'm still struggling with some more extravagant things. For example, I want to use enumerated keys (key1 to keyN, where N is some arbitrary integer). To avoid copy&paste work, I have come up with the idea of using a loop to make all the calls to \define@key - however, this doesn't quite work as I would have expected it to do.

Please consider the following MWE. You will observe that the document contains the string "test", but not the following string "something", which I would have expected to appear. Whether this works or not seems to depend on the exact definition of the \index command.

\documentclass{article}
\usepackage{xkeyval}
\makeatletter
\count@=0
\loop
\advance\count@ 1
%\edef\index{1}% <-- uncomment this line 
\edef\index{\@arabic\count@}% <-- and comment this one to make it work
\expandafter\def\csname KV@family@key\index\endcsname ##1{\expandafter\def\csname familykey\index\endcsname{##1}}
%\define@key{family}{key\index}{\expandafter\def \csname familykey\index\endcsname{#1}}% <- using this line instead of the above doesn't make a difference
\ifnum\count@<6
\repeat
\makeatother
\begin{document}
test
\setkeys{family}{key1=something}{
  \csname familykey1\endcsname
}
\end{document}

The fact that exchanging the line with the definition of \index makes a difference leads me to the conclusion that something's wrong with the argument expansion, but I can't seem to figure out how to make it work.

Any suggestions?

3

The problem is that \define@key doesn't expand its argument; also \index should be expanded at definition time in the replacement text of \define@key, not at runtime.

Using \index is not necessary, \the\count@ does the same (or \@arabic\count@, if you prefer. And \index is a badly chosen name anyway: try building an index for your document to see why.

\documentclass{article}
\usepackage{xkeyval}
\makeatletter
\count@=0
\loop
  \advance\count@ 1
  \begingroup\edef\x{\endgroup
    \noexpand\define@key{family}{key\the\count@}{%
      \noexpand\@namedef{familykey\the\count@}{####1}%
    }% end of \define@key
  }% end of \edef
  \x % execute \x
\ifnum\count@<6
\repeat
\makeatother
\begin{document}
test
\setkeys{family}{key1=something1}
\setkeys{family}{key2=something2}
\setkeys{family}{key3=something3}
\setkeys{family}{key4=something4}
\setkeys{family}{key5=something5}
\setkeys{family}{key6=something6}
\csname familykey1\endcsname
\csname familykey2\endcsname
\csname familykey3\endcsname
\csname familykey4\endcsname
\csname familykey5\endcsname
\csname familykey6\endcsname

\end{document}

Why is ####1 necessary? We are in a definition (\edef), but also \loop performs a \def, so #1 should be doubled also because of this. Two doublings give ####1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.