On Tue, Oct 07, 2025 at 02:08:17PM -0400, R. Clayton wrote:
...

> But LNK() is scoped to LINKS() and I'd like the code to reflect that.  Seems
> easy too:
> 
>   $ cat x
>   #! /bin/bash
> 
>   m4 -P <<'eof!'
>   m4_define(LINKS,
>     `m4_define(LNK, `hrf(flquotes-$1.html, $1)')
>      LNK(m4_eval($1 + 1))
>      m4_undefine(`LNK')
>     ')
> 
>   LINKS(2025)
>   eof!
> 
>   $ ./x
> 
> 
> 
>      hrf(flquotes-2025.html, 2025)
> 
> 
> 
>   $
> 
> except it doesn't work.  It seems $1 in LNK() is being bound at definition
> time, and I can't figure out a quoting structure to delay the binding to call
> time.  Is that sort of thing possible, and if so, how do I do it?

Yes, you are correct that $1 in the definition of LINKS is bound
before the m4_define(LNK...) is expanded.  But what you want is
possible; here's one way:

m4_define(`LINKS',
  `m4_define(`LNK', `hrf(flquotes-$'`1.html, $'`1)')
   LNK(m4_eval($1 + 1))
   m4_undefine(`LNK')
  ')
LINKS(2025)

The trick here was to use consecutive string concatenation, defining
LNK to the strings `hrf(flquotes-$', `1.html, $', and `1)' each in
turn, so that its overall content assigned to LNK is
"hrf(flquotes-$1.html, $1)", even though a literal $1 did not appear
in that part of the definition of LINKS.

I also took the liberty of adding quotes around the macro name being
defined, as that is safer if you ever want to redefine a macro.

You may encounter situations where you cannot break up a macro body
into consecutive strings; there are other approaches that can still
defer the injection of $1 into a secondary macro defined in a first,
such as this that passes a literal "1" as the $2 argument to LINKS, so
that the "$$2" text becomes a literal "$1" before the nested m4_define
(also taking the liberty to optimize m4_eval into m4_incr, and use
pushdef/popdef instead of define/undefine for a bit more safety in
case LNK is used as a macro elsewhere):

m4_define(`LINKS',
  `m4_pushdef(`LNK', `hrf(flquotes-$$2.html, $$2)')
   LNK(m4_incr($1))
   m4_popdef(`LNK')
  ')
LINKS(2025, 1)

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.
Virtualization:  qemu.org | libguestfs.org


Reply via email to