On Mon, May 19, 2025 at 02:05:28PM -0400, Nikolaos Chatzikonstantinou wrote:
> On Mon, May 19, 2025, 1:27 PM Eric Blake <[email protected]> wrote:
>
> > On Mon, May 19, 2025 at 10:46:10AM -0500, Eric Blake wrote:
> > > On Fri, May 16, 2025 at 08:16:24AM -0500, Eric Blake wrote:
> > > > Since you continue to patch things as fast as I report them (now
> > > > testing with commit a4cc0f3c):
> > >
> > > Now testing with b686ed, you have a problem with redefining a macro as
> > > empty if it has been undefined in the meantime:
> > >
> > > $ echo 'changequote([,])define(a)undefine([a])define(a)' | m4p
> > > Traceback (most recent call last):
> > > File "/home/eblake/m4p/.venv/bin/m4p", line 8, in <module>
> > > sys.exit(main())
> > > ~~~~^^
> > > ...
> > > File "/home/eblake/m4p/m4p/parser.py", line 279, in add_define
> > > self.macros[ident][-1] = defn
> > > ~~~~~~~~~~~~~~~~~~^^^^
> > > IndexError: list assignment index out of range
> >
> > This appears to fix it for me:
> >
> > diff --git i/m4p/parser.py w/m4p/parser.py
> > index 4793c8a..83c69df 100644
> > --- i/m4p/parser.py
> > +++ w/m4p/parser.py
> > @@ -272,7 +272,7 @@ class Parser:
> >
> > def add_define(self, ident: bytes, defn: bytes | Builtin):
> > """Equivalent to m4_define(ident, defn)."""
> > - if self.macros.get(ident) is None:
> > + if not self.macros.get(ident, []):
> > self.macros[ident] = [defn]
> > else:
> > # GNU ext define: replace top. Others: replace all with 1.
> >
>
> That looks good, I hoped something of the sort would have fixed it. I can
> commit it when I'm back home.
Glad to hear it. This next one will be tougher:
$ m4p -I ~/m4p/tests/resources/
define(`nl',`
')dnl
define(`a', translit((include(long_file.txt)),nl,`,'))dnl
len(a)
8895
define(`a', translit((syscmd(:)include(long_file.txt)),nl,`,'))
(m4:stdin:5: Warning: excess arguments to builtin `define' ignored
)
len(a)
1
m4 reports the same value for len(a) for both translit() wrappings of
long_file.txt, which gives a hint as to where m4p went wrong. I'm
guessing that your code for syscmd() flushes pending output to
diversion 0 (since any output from syscmd itself must appear at that
point, and is not intercepted by m4 because it is not esyscmd); but
even when syscmd has no output, that act of flushing must NOT
interfere with pending text being accumulated in the parameter of a
macro invocation. Tracing m4p shows that because syscmd(:) flushed
the '(' prematurely, at which point translit() is being called with $1
not starting with '(', which in turn means the code is trying to
invoke "define(`a', 1,2,...)" instead of the intended "define(`a',
(1,2,...)".
--
Eric Blake, Principal Software Engineer
Red Hat, Inc.
Virtualization: qemu.org | libguestfs.org