3

I want to pass a cmdkey from the xkeyval package to a macro. I can print the value of the cmdkey to a message, but when used with \in@ it seems to be unexpanded. Example below. I expect to see the messages

the value is aaacde. the action is true.

Instead I only see the value is aaacde. When I use a string for the comparison it does work (see commented out line).

\documentclass{article}
\usepackage{xkeyval}
\newif\ifaction
\makeatletter
\define@cmdkeys{links}[link@]{book,chap}{}
\setkeys{links}{book=aaacde, chap=asdf}
\def\testme{%
    \message{the value  is \link@book.}
    \in@{aaa}{\link@book}% does not work
    %\in@{aaa}{aaabcd}% works
    \ifin@\actiontrue\message{the action is true.}\fi
}
\makeatother
\begin{document}

text\testme

\end{document}

2 Answers 2

2

You need to expand \link@book before \in@ does its thing:

\documentclass{article}
\usepackage{xkeyval}
\newif\ifaction
\makeatletter
\define@cmdkeys{links}[link@]{book,chap}{}
\setkeys{links}{book=aaacde, chap=asdf}
\def\reversed@in@#1#2{\in@{#2}{#1}}% <-- Added this
\def\testme{%
    \message{the value  is \link@book.}
    \expandafter\reversed@in@\expandafter{\link@book}{aaa}% <-- Changed here
    %\in@{aaa}{aaabcd}% works
    \ifin@\actiontrue\message{the action is true.}\fi
}
\makeatother
\begin{document}

text\testme

\end{document}

I added a \reversed@in@ macro so that we can expand the first argument instead of the second. As a rule of thumb, the latter the argument is, the harder it is to expand it (not always true, though). Thus I used the \reversed@in@ macro to swap the arguments to \in@.

6
  • I get ! Undefined control sequence. <recently read> \reversed@in@ I'm using pdflatex.
    – Tim A
    Commented Apr 12, 2019 at 18:12
  • @TimA I think you forgot to copy the definition of \reversed@in@ I added. I clarified this in the answer. Commented Apr 12, 2019 at 18:15
  • thanks for that pointer, you're right I didn't see that definition. So you did that to make the expandafter work, because otherwise it couldn't be done, right?
    – Tim A
    Commented Apr 12, 2019 at 18:25
  • @TimA I did that to simplify the code. As I said, later arguments can be expanded, but it gets trickier. You could, instead of the \reversed@in@ thing, replace \in@{aaa}{\link@book} by \edef\@tempa{\noexpand\in@{\unexpanded{aaa}}{\expandafter\noexpand\link@book}}\@tempa. It would also expand \link@book once. Or, if \expandafters are your thing, you could use \def\aaa{aaa}\expandafter\expandafter\expandafter\in@\expandafter\expandafter\expandafter{\expandafter\aaa\expandafter}\expandafter{\link@book} :-) Commented Apr 12, 2019 at 18:36
  • @TimA Side note: this argument swapping is more or less how expl3 controls argument expansion. Commented Apr 12, 2019 at 18:37
1

You can define \expandedin@:

\documentclass{article}
\usepackage{xkeyval}

\newif\ifaction

\makeatletter
\newcommand{\expandedin@}[2]{%
  \begingroup\edef\x{\endgroup\noexpand\in@{#1}{#2}}\x
}

\define@cmdkeys{links}[link@]{book,chap}{}
\def\testme{%
    \message{the value is \link@book.}%
    \expandedin@{aaa}{\link@book}%
    \ifin@\actiontrue\message{the action is true.}\fi
}
\makeatother

\setkeys{links}{book=aaacde, chap=asdf}

\begin{document}

text\testme

\end{document}

With a newer version of the engines (available with TeX Live 2019), you can use \expanded.

\documentclass{article}
\usepackage{xkeyval}

\newif\ifaction

\makeatletter
\define@cmdkeys{links}[link@]{book,chap}{}
\def\testme{%
    \message{the value is \link@book.}%
    \expanded{\noexpand\in@{aaa}{\link@book}}% 
    \ifin@\actiontrue\message{the action is true.}\fi
}
\makeatother

\setkeys{links}{book=aaacde, chap=asdf}

\begin{document}

text\testme

\end{document}
2
  • wow, that makes it worth installing the 2019 distro, so simple. In your first example, can you explain the begingroup--endgroup pair? I think I understand the rest. What happens if I left them out? \edef\x{\noexpand\in@{#1}{#2}}\x (I don't see a difference in the result).
    – Tim A
    Commented Apr 15, 2019 at 12:08
  • 1
    @TimA That's for avoiding to leave a definition of \x: after \x is expanded, TeX finds \endgroup, which removes the (re)definition of \x, but the resulting token list is already there.
    – egreg
    Commented Apr 15, 2019 at 12:30

You must log in to answer this question.

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