15

According to chapter 20 of the TeXbook, a macro that is defined as "long" (by saying \long just before \def\<macroname>) allows arguments with \par tokens (i.e., paragraphs). Suppose I encounter a macro that is not "long" (e.g. \thanks, the title equivalent of \footnote). I want to allow paragraphs in its argument, but not to change the macro's definition in any other way. Obviously, I could look up the meaning and define the macro anew, this time as "long". But is there a simple way to add the \long prefix?

  • 3
    Unfortunately \long\let\somemacro=\somemacro doesn't do it. (However, this works well with \global). It should be possible to define a macro as long with the same definition of an existing macro (of the same name or not), using a similar technique as \apptocmd of etoolbox. – Martin Scharrer Jul 27 '11 at 16:12
  • 2
    If all that's needed is a \par inside \thanks it's much easier to say \endgraf to do the business. In a non \long macro it's exactly the token whose name is \par that's disallowed in arguments: TeX doesn't look at its meaning (it wouldn't be able, because expansion is suppressed when scanning an argument). – egreg Jul 28 '11 at 12:57
  • @egreg: "TeX doesn't look at it's meaning" that's almost, but not entirely true in an alignment context. \def\foo#1\bar{}\halign{#\cr\relax\foo\amp\bar\cr} works, but adding \let\amp& before screws up everything. – Bruno Le Floch Jul 28 '11 at 13:23
  • @Bruno Yes, but here another mechanism is involved; with \let\amp&, TeX sees a & at the outer brace level and inserts \endtemplate to end the cell. This wouldn't happen with \def\amp{&}. – egreg Jul 28 '11 at 13:48
  • @egreg: that's right. I just wanted to point out that the \meaning is still looked at. Only explicit \-p-a-r are detected, but TeX still looks at the meaning for other tokens: outer tokens, &, \cr, and \crcr (only those, I think). – Bruno Le Floch Jul 28 '11 at 15:16
17

If one is sure that the command to be made \long is a macro, this should work

\def\longpatch#1{\expandafter\getparts\meaning#1\longpatch
  \begingroup\edef#1{\long\def\noexpand#1\the\toks0 {\the\toks2}}%
  \scantokens\expandafter{\expandafter\endgroup#1}}
\def\getparts#1:#2->#3\longpatch{\toks0={#2}\toks2={#3}}

From \def\x#1#2{a#1|#2b\hfil}, using \longpatch\x will use \meaning\x that generates

macro:#1#2->a#1|#2b\hfil

so \expandafter\getparts\meaning\x\longpatch will store #1#2 into \toks0 and a#1|#2b\hfil into \toks2. Then we define, with \edef, the same \x to expand to

\endgroup\long\def\x#1#2{a#1|#2b\hfil}

but the problem is that what comes after \x is just a string of characters all having category code 12 (spaces will have category code 10), even the backslash. We solve the problem by expanding \x inside \scantokens that rereads the characters as if they were just input from a file. Of course this won't work if the tokens in the definition of \x have non ordinary category codes.

(Note: we use #1 also as scratch macro, so that it won't interfere with other possibly defined macros; it's safe, because its redefinition will disappear when the \endgroup inside \scantokens is executed, just before redefining #1 again.)

Another "solution" is to use \endgraf instead of \par in the arguments to the non \long macro.

14

You can not retroactively add a \long prefix to a definition (as Martin wrote, using \long\let does not work).

That leaves redefinition as the only option, and this is always hazardous. If you know exactly how the original macro is defined in terms of expected arguments and you are certain that it does not do any catcode trickery, then there is a possible hack:

\newtoks\patchtoks    % helper token register
\def\longpatch#1%     % worker macro
  {\let\myoldmac#1%
   \long\def#1##1{\patchtoks={##1}\myoldmac{\the\patchtoks}}}

\def\a#1{#1}          % original definition

\longpatch\a          % redefition

\a{\TeX\par text}     % test

\bye

The trick here is the \the\patchtoks: this is a situation in which the appearance of embedded \par tokens is ignored.

I'll leave this answer as community wiki, because it is rather ugly and perhaps someone else can improve it.

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.