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

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@.

  • I get ! Undefined control sequence. <recently read> \reversed@in@ I'm using pdflatex. – Tim A Apr 12 at 18:12
  • @TimA I think you forgot to copy the definition of \reversed@in@ I added. I clarified this in the answer. – Phelype Oleinik Apr 12 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 Apr 12 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} :-) – Phelype Oleinik Apr 12 at 18:36
  • @TimA Side note: this argument swapping is more or less how expl3 controls argument expansion. – Phelype Oleinik Apr 12 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}
  • 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 Apr 15 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 Apr 15 at 12:30

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.