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!

1 Answer 1

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}
2
  • 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, 2020 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, 2020 at 20:23

You must log in to answer this question.

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