3

I have fallen into a hole of never-expanding macros and don't feel that I will be able to climb out without any help.

In general, I think that my question can be formulated as:

What do I do when I have a macro \x that I do not want to expand but wants to supply it with an argument \y that I do want to expand?

That is not really a well-defined question, so I have constructed an MWE that is printed in its entirety after some explanation. I will start by explaining the background of the problem, in the hopes that it will make it clearer what I'm trying to do. I have created a sort of cut and paste function using the aux-file to be able to duplicate text across a document (idea taken from this answer: https://tex.stackexchange.com/a/150839/214956)

\makeatletter
\newcommand\ctrlC[1]{
  \immediate\write\@auxout{\unexpanded{\global\long\@namedef{aux_clipboard}{#1}}}%
  #1
}
\newcommand\ctrlV{
  \ifcsname aux_clipboard\endcsname
    \@nameuse{aux_clipboard}
  \else
    ``??''
  \fi
}
\makeatother

(I removed a lot of functionality for this MWE.) The idea is that the command

ctrlC{This is a test}

will create the following line in the aux-file:

\global \long \@namedef {aux_clipboard}{This is a test}

The ctrlV function on the other hand can search for the "csname: aux_clipboard" in the aux-file, and print the stored text if found.

That works great.

However, I want to be able to duplicate text from theorem-environments, and to automate this, I came up with the following (using the environ-package to got control of the text-body of the environment with the variable \BODY) - which is the MWE of my problem:

\documentclass{article}
\usepackage{environ}

\makeatletter
\newcommand\ctrlC[1]{
  \immediate\write\@auxout{\unexpanded{\global\long\@namedef{aux_clipboard}{#1}}}%
  #1
}
\newcommand\ctrlV{
  \ifcsname aux_clipboard\endcsname
    \@nameuse{aux_clipboard}
  \else
    ``??''
  \fi
}
\makeatother

\NewEnviron{foo}[1]{
\ctrlC{\BODY}
}
\begin{document}

\begin{foo}{a}
This is a test.
\end{foo}

\ctrlV

\end{document}

However, this doesn't work since \BODY is not expanded. The aux-file looks like this:

\global \long \@namedef {aux_clipboard}{\BODY }

resulting in the error (which is obvious since ctrlV has no idea what \BODY is):

! Undefined control sequence. \aux_clipboard ->\BODY

The reason behind the error is on the line:

\immediate\write\@auxout{\unexpanded{\global\long\@namedef{aux_clipboard}{#1}}}

where I want to not expand @namedef to \def, but I want to expand #1 (which is \BODY) to the text "This is a test". In summary, I feel like an idiot and can't figure out how to expand \BODY before it is written to the aux-file...

I would be very happy if someone could give me an idea of how to solve this specific problem, as well as if someone could give a general answer to my original fuzzy question. Thanks in advance!

3

You want to expand \BODY before passing it to \ctrlC:

\documentclass{article}
\usepackage{environ}

\makeatletter
\newcommand\ctrlC[1]{%
  \immediate\write\@auxout{%
    \unexpanded{\global\long\@namedef{aux_clipboard}{#1}}%
  }%
  #1%
}
\newcommand\ctrlV{%
  \ifcsname aux_clipboard\endcsname
    \@nameuse{aux_clipboard}%
  \else
    ``??''%
  \fi
}
\makeatother

\NewEnviron{foo}[1]{%
  \expandafter\ctrlC\expandafter{\BODY}%
}

\begin{document}

\begin{foo}{a}
This is a test.
\end{foo}

\ctrlV

\end{document}

This is the contents of the generated .aux file:

\relax 
\global \long \@namedef {aux_clipboard}{This is a test.}

I've added several missing % characters.

An expl3 version:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\ctrlC}{m}
 {
  \iow_now:cn { @auxout } 
   {
    \global\long\@namedef{aux_clipboard}{#1}
   }
  #1
}

\NewDocumentCommand{\ctrlV}{}
 {
  \cs_if_exist_use:cF { aux_clipboard } { ``??'' }
 }
\ExplSyntaxOff

\NewDocumentEnvironment{foo}{mb}
 {\ctrlC{#2}}
 {}

\begin{document}

\begin{foo}{a}
This is a test.
\end{foo}

\ctrlV

\end{document}
| improve this answer | |
  • Thanks a lot, this solved my problem! I guess this answer circumvents my general fuzzy question, as you very nicely expanded the variable before passing it the problematic function - if the situation was different and we couldn't expand the variable beforehand, do you know if it would be possible to expand \y while not expanding \x in something like: \unexpanded\x#1\y (maybe with same clever combination of several \expandafter). I realize that you imply that expl3 would be a better solution, where such a situation might never occur. – Gustahl May 7 at 19:12
  • @Gustahl The question you pose cannot be answered in generality: what you place in \unexpanded is not expanded at the time of a \write, So you need to expand what you need before passing it to \write. Case by case strategy applies. – egreg May 7 at 20:23

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.