[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: bad define semantics in GNU m4
From: |
Paul Eggert |
Subject: |
Re: bad define semantics in GNU m4 |
Date: |
03 Jul 2003 15:41:01 -0700 |
User-agent: |
Gnus/5.09 (Gnus v5.9.0) Emacs/21.3 |
Richard Stallman <address@hidden> writes:
> How about if we modify m4 so that it disables incompatibilities with
> POSIX if the POSIXLY_CORRECT environment variable is set? This is
> what the GNU coding standards suggest.
>
> That is an ok solution. I had thought that an option would be more
> convenient as an interface, but your argument in favor of using the
> envvar seems to make sense.
OK, here is a proposed patch against CVS m4 to implement this. It
suppresses all the POSIX incompatibilities that I found in m4, if
POSIXLY_CORRECT is set. Unfortunately I can't easily test this, as
CVS m4 requires a CVS libtool version that I don't have, and the
bootstrap fails with the latest released libtool.
2003-07-03 Gary V. Vaughan <address@hidden>
* tests/builtins.at: New test for smashed definitions.
2003-07-03 Paul Eggert <address@hidden> and
Gary V. Vaughan <address@hidden>
Conform to POSIX if the POSIXLY_CORRECT environment is set.
--traditional `define' now smashes all the definitions.
* NEWS: Explain this.
* doc/m4.texinfo (Defn): `defn' takes any number of arguments.
(Extensions): Explain that extensions that are incompatible with
POSIX are disabled if POSIXLY_CORRECT is set.
(Incompatibilities): Remove.
(Define, Other Incompat): Explain difference
between GNU and POSIX behavior of define, pushdef, popdef.
* m4/m4.c (m4_get_posixly_correct_opt): New undef.
* m4/m4module.h (m4_context_opt_bit_table): Add POSIXLY_CORRECT entry.
* m4/m4private.h (M4_OPT_POSIXLY_CORRECT_BIT): New macro.
(m4_get_posixly_correct_opt): New macro.
* m4/m4macro.c (m4_process_macro): Disable $10, $abc etc. if
POSIXLY_CORRECT.
* modules/m4.c (builtin_functions): defn now takes any number of args.
(M4BUILTIN_HANDLER (define)): Smash all the definitions if
POSIXLY_CORRECT.
(M4BUILTIN_HANDLER (defn)): Allow any number of arguments.
(M4BUILTIN_HANDLER (undivert)): Do not allow nonnumeric arguments
if POSIXLY_CORRECT.
* src/main.c (main): Set posixly-correct behavior if either
POSIXLY_CORRECT is set, or if -G is given.
Index: NEWS
===================================================================
RCS file: /cvsroot/m4/m4/NEWS,v
retrieving revision 1.8
diff -p -u -r1.8 NEWS
--- NEWS 4 Oct 2001 08:03:18 -0000 1.8
+++ NEWS 3 Jul 2003 22:37:15 -0000
@@ -1,6 +1,16 @@
GNU m4 NEWS - History of user-visible changes. -*- outline -*-
Copyright 1992, 1993, 1994, 1998, 2000, 2001 Free Software Foundation, Inc.
+Version beta 1.4r - ???, by ???
+
+* If the POSIXLY_CORRECT environment variable is set, m4 now disables
+ GNU extensions that are incompatible with POSIX.
+
+* POSIXLY_CORRECT and `m4 --traditional' now makes the `define' builtin
+ replace all `pushdef'ed values of a macro, as POSIX requires.
+
+* The `defn' builtin now allows any number of arguments, as POSIX requires.
+
Version beta 1.4q - August 2001, by Gary V. Vaughan
* Support for the experimental `changeword' has been dropped.
Index: doc/m4.texinfo
===================================================================
RCS file: /cvsroot/m4/m4/doc/m4.texinfo,v
retrieving revision 1.17
diff -p -u -r1.17 m4.texinfo
--- doc/m4.texinfo 27 Jun 2003 14:00:25 -0000 1.17
+++ doc/m4.texinfo 3 Jul 2003 22:37:16 -0000
@@ -235,7 +235,6 @@ Miscellaneous builtin macros
Compatibility with other versions of @code{m4}
* Extensions:: Extensions in GNU m4
-* Incompatibilities:: Facilities in System V m4 not in GNU m4
* Other Incompat:: Other incompatibilities
@end detailmenu
@@ -1032,6 +1031,14 @@ a part of the macro definition, and it i
the output. This can be avoided by use of the macro @code{dnl}.
@xref{Dnl}, for details.
address@hidden GNU extensions
+GNU @code{m4} normally replaces only the @emph{topmost} definition of a
+macro if it has several definitions from @code{pushdef}.
address@hidden, , Temporarily redefining macros}, for an explanation of
address@hidden Some other UNIX implementations replace all definitions
+of a macro with @code{define}.
address@hidden Incompat, , Other incompatibilities}, for more details.
+
The first argument to @code{define} does not have to be a simple word.
It can be any text string. A macro with a non standard name cannot be
invoked in the normal way, as the name is not recognised. It can only
@@ -1245,6 +1252,11 @@ points to the builtin's internal definit
meaningful as the second argument to @code{define} (and @code{pushdef}),
and is ignored in any other context.
address@hidden can be given any number of arguments; it expands to the
+concatenation of the quoted definitions of each argument. The
+usefulness of this behavior is unclear, but @acronym{POSIX} requires
+it.
+
The macro @code{defn} is recognized only with parameters.
@end deffn
@@ -3761,7 +3773,6 @@ is made to summarize these here.
@menu
* Extensions:: Extensions in GNU m4
-* Incompatibilities:: Facilities in System V m4 not in GNU m4
* Other Incompat:: Other incompatibilities
@end menu
@@ -3769,10 +3780,16 @@ is made to summarize these here.
@section Extensions in GNU @code{m4}
@cindex GNU extensions
address@hidden @acronym{POSIX}
address@hidden @env{POSIXLY_CORRECT}
This version of @code{m4} contains a few facilities, that do not exist
in System V @code{m4}. These extra facilities are all suppressed by
using the @samp{-G} command line option, unless overridden by other
command line options.
+Most of these extensions are compatible with
address@hidden://www.unix.org/single_unix_specification/,
address@hidden; the few exceptions are suppressed if the
address@hidden environment variable is set.
@itemize @bullet
@item
@@ -3780,6 +3797,8 @@ In the @address@hidden notation for macr
several digits, while the System V @code{m4} only accepts one digit.
This allows macros in GNU @code{m4} to take any number of arguments, and
not only nine (@pxref{Arguments}).
address@hidden does not allow this extension, so it is disabled if
address@hidden is set.
@item
Files included with @code{include} and @code{sinclude} are sought in a
@@ -3790,6 +3809,8 @@ directory. The search path is specified
@item
Arguments to @code{undivert} can be non-numeric, in which case the named
file will be included uninterpreted in the output (@pxref{Undivert}).
address@hidden does not allow this extension, so it is disabled if
address@hidden is set.
@item
Formatted output is supported through the @code{format} builtin, which
@@ -3846,18 +3867,6 @@ description of these options.
Also, the debugging and tracing facilities in GNU @code{m4} are much
more extensive than in most other versions of @code{m4}.
address@hidden Incompatibilities
address@hidden Facilities in System V @code{m4} not in GNU @code{m4}
-
-The version of @code{m4} from System V contains a few facilities that
-have not been implemented in GNU @code{m4} yet.
-
address@hidden @bullet
address@hidden
-System V @code{m4} supports multiple arguments to @code{defn}. This is
-not implemented in GNU @code{m4}. Its usefulness is unclear to me.
address@hidden itemize
-
@node Other Incompat
@section Other incompatibilities
@@ -3908,6 +3917,15 @@ name would be a useless limitation. Of
for the GNU @code{m4} user to hang himself! Rescanning hangs may be
avoided through careful programming, a little like for endless loops
in traditional programming languages.
+
address@hidden
+Some implementations of @code{m4} (Solaris for example) conform to
address@hidden, which requires @code{define(@var{macro})} to behave
+like @code{undefine(@var{macro})pushdef(@var{macro})}. Other
+implementations, including GNU @code{m4} without the @samp{-G} option
+and without @env{POSIXLY_CORRECT} set, treat
address@hidden(@var{macro})} as
address@hidden(@var{macro})pushdef(@var{macro})}.
@item
@findex __gnu__
Index: m4/m4.c
===================================================================
RCS file: /cvsroot/m4/m4/m4/m4.c,v
retrieving revision 1.4
diff -p -u -r1.4 m4.c
--- m4/m4.c 26 Jun 2003 14:57:32 -0000 1.4
+++ m4/m4.c 3 Jul 2003 22:37:16 -0000
@@ -62,6 +62,7 @@ m4_delete (m4 *context)
#undef m4_get_discard_comments_opt
#undef m4_get_interactive_opt
#undef m4_get_sync_output_opt
+#undef m4_get_posixly_correct_opt
#define M4FIELD(type, base, field) \
Index: m4/m4module.h
===================================================================
RCS file: /cvsroot/m4/m4/m4/m4module.h,v
retrieving revision 1.53
diff -p -u -r1.53 m4module.h
--- m4/m4module.h 27 Jun 2003 14:00:25 -0000 1.53
+++ m4/m4module.h 3 Jul 2003 22:37:16 -0000
@@ -105,6 +105,7 @@ extern void m4_delete (m4 *);
M4OPT_BIT(M4_OPT_DISCARD_COMMENTS_BIT, discard_comments_opt) \
M4OPT_BIT(M4_OPT_INTERACTIVE_BIT, interactive_opt) \
M4OPT_BIT(M4_OPT_SYNC_OUTPUT_BIT, sync_output_opt) \
+ M4OPT_BIT(M4_OPT_POSIXLY_CORRECT_BIT, posixly_correct_opt) \
#define M4FIELD(type, base, field) \
Index: m4/m4private.h
===================================================================
RCS file: /cvsroot/m4/m4/m4/m4private.h,v
retrieving revision 1.26
diff -p -u -r1.26 m4private.h
--- m4/m4private.h 26 Jun 2003 14:57:32 -0000 1.26
+++ m4/m4private.h 3 Jul 2003 22:37:16 -0000
@@ -59,6 +59,7 @@ struct m4 {
#define M4_OPT_DISCARD_COMMENTS_BIT (1 << 2) /* -c */
#define M4_OPT_INTERACTIVE_BIT (1 << 3) /* -e */
#define M4_OPT_SYNC_OUTPUT_BIT (1 << 4) /* -s */
+#define M4_OPT_POSIXLY_CORRECT_BIT (1 << 5) /* POSIXLY_CORRECT */
#ifdef NDEBUG
# define m4_get_symbol_table(C) ((C)->symtab)
@@ -79,6 +80,8 @@ struct m4 {
(BIT_TEST((C)->opt_flags, M4_OPT_INTERACTIVE_BIT))
# define m4_get_sync_output_opt(C) \
(BIT_TEST((C)->opt_flags, M4_OPT_SYNC_OUTPUT_BIT))
+# define m4_get_posixly_correct_opt(C)
\
+ (BIT_TEST((C)->opt_flags, M4_OPT_POSIXLY_CORRECT_BIT))
#endif
Index: m4/macro.c
===================================================================
RCS file: /cvsroot/m4/m4/m4/macro.c,v
retrieving revision 1.31
diff -p -u -r1.31 macro.c
--- m4/macro.c 27 Jun 2003 14:00:25 -0000 1.31
+++ m4/macro.c 3 Jul 2003 22:37:16 -0000
@@ -343,7 +343,7 @@ m4_process_macro (m4 *context, m4_symbol
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- if (m4_get_no_gnu_extensions_opt (context) || !isdigit(text[1]))
+ if (m4_get_posixly_correct_opt (context) || !isdigit(text[1]))
{
i = *text++ - '0';
}
@@ -369,7 +369,7 @@ m4_process_macro (m4 *context, m4_symbol
break;
default:
- if (m4_get_no_gnu_extensions_opt (context)
+ if (m4_get_posixly_correct_opt (context)
|| !SYMBOL_ARG_SIGNATURE (symbol))
{
obstack_1grow (obs, ch);
Index: modules/m4.c
===================================================================
RCS file: /cvsroot/m4/m4/modules/m4.c,v
retrieving revision 1.45
diff -p -u -r1.45 m4.c
--- modules/m4.c 26 Jun 2003 14:57:32 -0000 1.45
+++ modules/m4.c 3 Jul 2003 22:37:16 -0000
@@ -56,7 +56,7 @@ extern int errno;
BUILTIN(changequote, FALSE, FALSE, 1, 3 ) \
BUILTIN(decr, FALSE, TRUE, 2, 2 ) \
BUILTIN(define, TRUE, TRUE, 2, 3 ) \
- BUILTIN(defn, FALSE, TRUE, 2, 2 ) \
+ BUILTIN(defn, FALSE, TRUE, 0, -1 ) \
BUILTIN(divert, FALSE, FALSE, 1, 2 ) \
BUILTIN(divnum, FALSE, FALSE, 1, 1 ) \
BUILTIN(dnl, FALSE, FALSE, 1, 1 ) \
@@ -161,6 +161,9 @@ M4BUILTIN_HANDLER (define)
else
m4_symbol_value_copy (value, argv[2]);
+ if (m4_get_posixly_correct_opt (context))
+ m4_symbol_delete (M4SYMTAB, M4ARG (1));
+
m4_symbol_define (M4SYMTAB, M4ARG (1), value);
}
}
@@ -311,22 +314,24 @@ M4BUILTIN_HANDLER (dumpdef)
macro-definition token on the input stack. */
M4BUILTIN_HANDLER (defn)
{
- m4_symbol *symbol;
+ int i;
- symbol = m4_symbol_lookup (M4SYMTAB, M4ARG (1));
- if (symbol == NULL)
+ for (i = 1; i < argc; i++)
{
- M4WARN ((m4_get_warning_status_opt (context), 0,
- _("Warning: %s: undefined name: %s"), M4ARG (0), M4ARG (1)));
- return;
- }
+ const char *name = m4_get_symbol_value_text (argv[i]);
+ m4_symbol *symbol = m4_symbol_lookup (M4SYMTAB, name);
- if (m4_is_symbol_text (symbol))
- m4_shipout_string (context, obs, m4_get_symbol_text (symbol), 0, TRUE);
- else if (m4_is_symbol_func (symbol))
- m4_push_builtin (m4_get_symbol_value (symbol));
- else
- assert (!"Bad token data type in m4_defn");
+ if (!symbol)
+ M4WARN ((m4_get_warning_status_opt (context), 0,
+ _("Warning: %s: undefined name: %s"),
+ m4_get_symbol_value_text (argv[0]), name));
+ else if (m4_is_symbol_text (symbol))
+ m4_shipout_string (context, obs, m4_get_symbol_text (symbol), 0, TRUE);
+ else if (m4_is_symbol_func (symbol))
+ m4_push_builtin (m4_get_symbol_value (symbol));
+ else
+ assert (!"Bad token data type in m4_defn");
+ }
}
@@ -402,7 +407,7 @@ M4BUILTIN_HANDLER (undivert)
{
if (sscanf (M4ARG (1), "%d", &i) == 1)
m4_insert_diversion (i);
- else if (m4_get_no_gnu_extensions_opt (context))
+ else if (m4_get_posixly_correct_opt (context))
m4_numeric_arg (context, argc, argv, 1, &i);
else
{
Index: src/main.c
===================================================================
RCS file: /cvsroot/m4/m4/src/main.c,v
retrieving revision 1.43
diff -p -u -r1.43 main.c
--- src/main.c 26 Jun 2003 14:57:32 -0000 1.43
+++ src/main.c 3 Jul 2003 22:37:16 -0000
@@ -240,6 +240,9 @@ main (int argc, char *const *argv, char
if (isatty (STDIN_FILENO))
m4_set_interactive_opt (context, TRUE);
+ if (getenv ("POSIXLY_CORRECT"))
+ m4_set_posixly_correct_opt (context, TRUE);
+
/* First, we decode the arguments, to size up tables and stuff. */
head = tail = NULL;
@@ -290,6 +293,7 @@ main (int argc, char *const *argv, char
case 'G':
m4_set_no_gnu_extensions_opt (context, TRUE);
+ m4_set_posixly_correct_opt (context, TRUE);
break;
case 'I':
Index: tests/builtins.at
===================================================================
RCS file: /cvsroot/m4/m4/tests/builtins.at,v
retrieving revision 1.7
diff -p -u -r1.7 builtins.at
--- tests/builtins.at 13 Oct 2001 08:55:55 -0000 1.7
+++ tests/builtins.at 3 Jul 2003 22:37:16 -0000
@@ -20,6 +20,44 @@ AT_BANNER([Torturing builtins.])
## ------ ##
+## define ##
+## ------ ##
+
+AT_SETUP([[define]])
+
+AT_DATA([[define.m4]],
+[[undefine(`macro')dnl
+pushdef(`macro', `base value')dnl
+pushdef(`macro', `hello, world')dnl
+pushdef(`macro', `top value')dnl
+define(`macro', `new value')dnl
+macro.
+popdef(`macro')dnl
+macro.
+popdef(`macro')dnl
+macro.
+]])
+
+AT_CHECK_M4([define.m4], 0,
+[[new value.
+hello, world.
+base value.
+]], [[m4: define.m4: 1: Warning: undefine: undefined name: macro
+]])
+
+AT_CHECK_M4([--traditional define.m4], 0,
+[[new value.
+macro.
+macro.
+]], [[m4: define.m4: 1: Warning: undefine: undefined name: macro
+m4: define.m4: 9: Warning: popdef: undefined name: macro
+]])
+
+AT_CLEANUP
+
+
+
+## ------ ##
## divert ##
## ------ ##