> Now suppose @email is itself called from a macro. In that case, @@ will
> be passed to execute_string more than once, and bad things will happen
> the second time. Under -E, the macro-expanded output is also incorrect
> in some cases like this.
>
> Okay, I'll go along with this.
Actually, I didn't mention the most important reason that macro
expansion in @email (and @xref, for that matter) cannot be postponed
until execute_string time. (It's been a long time since I made those
changes, sorry.)
The problem is that get_xref_token relies on commas to find the
arguments of @email, and a macro inside @email can change the commas.
Consider the following fragment:
@macro foo
bar, baz
@end macro
@email{@foo{}}
Unless you expand @foo *before* you look for the commas, you get
incorrect results.
Here's another disaster like that:
@macro addr{user, server}
\user\@\server\
@end macro
@email{foo, bar}
So you MUST expand all the macros (and only macros!) before looking
for the commas.
> So why isn't NAME treated the same way
> as ADDR, i.e., get_xref_token (1)?
It *is* treated the same way. get_xref_token (1) actually expands
macros inside the entire brace-delimited text, and only then gets the
first argument. So when the next call to get_xref_token (0) is made,
all the macros are already expanded, and the expansion has replaced
the original text in the input stream.
Here's the code from get_xref_token, for your reference. As you see,
when EXPAND is non-zero, it replaces the entire braced argument list
with its expansion (that's what the call to replace_with_expansion
does):
char *
get_xref_token (expand)
int expand;
{
char *string;
if (expand)
{
int old_offset = input_text_offset;
int old_lineno = line_number;
get_until_in_braces ("}", &string);
if (curchar () == '}') /* as opposed to end of text */
input_text_offset++;
if (input_text_offset > old_offset)
{
int limit = input_text_offset;
input_text_offset = old_offset;
line_number = old_lineno;
only_macro_expansion++;
replace_with_expansion (input_text_offset, &limit);
only_macro_expansion--;
}
free (string);
}
get_until_in_braces (",", &string);
if (curchar () == ',')
input_text_offset++;
fix_whitespace (string);
return string;
}