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?

1 Answer 1

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.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .