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?
- 250,273
2 Answers
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.
- 1,121,712
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.
- 13,724
- 43
- 67
\long\let\somemacro=\somemacrodoesn'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\apptocmdofetoolbox. – Martin Scharrer Jul 27 '11 at 16:12\parinside\thanksit's much easier to say\endgrafto do the business. In a non\longmacro it's exactly the token whose name is\parthat'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\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\let\amp&, TeX sees a&at the outer brace level and inserts\endtemplateto end the cell. This wouldn't happen with\def\amp{&}. – egreg Jul 28 '11 at 13:48\meaningis still looked at. Only explicit\-p-a-rare 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