[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: m4 fails to expand macros after changequote
From: |
Eric Blake |
Subject: |
Re: m4 fails to expand macros after changequote |
Date: |
Tue, 16 May 2023 11:33:55 -0500 |
User-agent: |
NeoMutt/20230512 |
On Tue, May 16, 2023 at 12:16:17PM +0200, Andreas F. Borchert wrote:
>
> Here is a minimal example that demonstrates the problem:
>
> changequote({,})dnl
> define(P1, {changequote([,])`}$[]1{'changequote()})dnl
> changequote()dnl
This line is your problem. Per POSIX,
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/m4.html
changequote
The changequote macro shall set the begin-quote and end-quote
strings. With no arguments, the quote strings shall be set to the
default values (that is, `'). The behavior is unspecified if there
is a single argument or either argument is null. With two non-null
arguments, the first argument shall become the begin-quote string
and the second argument shall become the end-quote string. Systems
shall support quote strings of at least five characters.
You have called changequote() which passes a single null argument,
rather than a well-specified behavior of zero arguments or two
non-null arguments. But even though POSIX says behavior is
unspecified, 'info m4 changequote' does declare what GNU does:
-- Builtin: changequote ([START = ‘`’], [END = ‘'’])
This sets START as the new begin-quote delimiter and END as the new
end-quote delimiter. If both arguments are missing, the default
quotes (‘`’ and ‘'’) are used. If START is void, then quoting is
disabled. Otherwise, if END is missing or void, the default
end-quote delimiter (‘'’) is used. The quote delimiters can be of
any length.
Thus, you have managed to disable quoting altogether (m4's choice of
disabling quoting may seem an odd decision, but it was made decades
ago before I started m4 development, and since it is documented, it is
one that is unlikely to be changed due to back-compat concerns). I
don't know if Solaris m4 documents their behavior, but based on their
behavior and your email, I'm assuming they treat "changequote()" as a
synonym to "changequote".
But I can offer some advice: to be portable to both GNU and Solaris
m4, write:
changequote`'dnl
Since ` is neither ( nor a macro name character, it forces a call of
changequote with zero parameters per POSIX, which in turn restores
quoting to normal, so that the `' is then parsed as an empty string
after quotes are removed.
> define(`foo', `$1 is not P1')dnl
Given your mistake in the line above, this was defining the macro
named "`foo'" (5-character name, non-invokable without indir) rather
than the macro "foo" (3-character name),...
> foo(`bar')
...so this line sees no macro invocations whatsoever, but neither does
it recognize `' as quote characters.
>
> Running this example with GNU m4:
>
> theon$ m4 --version
> m4 (GNU M4) 1.4.19
> Copyright (C) 2021 Free Software Foundation, Inc.
> License GPLv3+: GNU GPL version 3 or later
> <https://gnu.org/licenses/gpl.html>.
> This is free software: you are free to change and redistribute it.
> There is NO WARRANTY, to the extent permitted by law.
>
> Written by René Seindal.
> theon$ m4 bug.m4
> foo(`bar')
> theon$
>
> In comparison, running this with Solaris 11.4 m4:
>
> theon$ /usr/bin/m4 bug.m4
> bar is not `$1'
> theon$
Thanks for a nice report, even if the bug turned out to be in your
script rather than in GNU m4 proper.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org