[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-r
From: |
Eric Blake |
Subject: |
[SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-readonly-21-gac88455 |
Date: |
Sun, 25 Nov 2007 00:28:04 +0000 |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU M4 source repository".
http://git.sv.gnu.org/gitweb/?p=m4.git;a=commitdiff;h=ac8845562f0066ef07d74a1f5b0e749eceb19b89
The branch, branch-1_4 has been updated
via ac8845562f0066ef07d74a1f5b0e749eceb19b89 (commit)
from 9de0b8950ca83762363605805c40f8f8614acbc8 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit ac8845562f0066ef07d74a1f5b0e749eceb19b89
Author: Eric Blake <address@hidden>
Date: Fri Oct 19 07:43:34 2007 -0600
Stage 1: convert token_data** into new object.
* m4/gnulib-cache.m4: Import flexmember module.
* src/m4.h (struct macro_arguments, struct token_chain): New
structs.
(builtin_func): Alter signature.
(token_data): Add new TOKEN_COMP alternative.
* src/builtin.c: All builtins changed.
(ARG, dump_args, define_macro, expand_user_macro): Update to use
struct.
* src/debug.c (trace_pre, trace_post): Likewise.
* src/format.c (ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE, format):
Likewise.
* src/macro.c (collect_arguments): Build new struct.
(call_macro, expand_macro): Update to use new struct.
(cherry picked from commit 44f5da7de32ac8f71f26d9e441316fa563db30d6)
Signed-off-by: Eric Blake <address@hidden>
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 17 +++++
m4/gnulib-cache.m4 | 4 +-
src/builtin.c | 201 ++++++++++++++++++++++++++++++----------------------
src/debug.c | 10 ++--
src/format.c | 45 +++++-------
src/m4.h | 71 ++++++++++++++-----
src/macro.c | 51 ++++++++------
7 files changed, 243 insertions(+), 156 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 9bbf726..14deb9f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2007-11-24 Eric Blake <address@hidden>
+
+ Stage 1: convert token_data** into new object.
+ * m4/gnulib-cache.m4: Import flexmember module.
+ * src/m4.h (struct macro_arguments, struct token_chain): New
+ structs.
+ (builtin_func): Alter signature.
+ (token_data): Add new TOKEN_COMP alternative.
+ * src/builtin.c: All builtins changed.
+ (ARG, dump_args, define_macro, expand_user_macro): Update to use
+ struct.
+ * src/debug.c (trace_pre, trace_post): Likewise.
+ * src/format.c (ARG_INT, ARG_LONG, ARG_STR, ARG_DOUBLE, format):
+ Likewise.
+ * src/macro.c (collect_arguments): Build new struct.
+ (call_macro, expand_macro): Update to use new struct.
+
2007-11-22 Eric Blake <address@hidden>
More error messages tied to macro names.
diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4
index 4d1727d..a89650c 100644
--- a/m4/gnulib-cache.m4
+++ b/m4/gnulib-cache.m4
@@ -15,11 +15,11 @@
# Specification in the form of a command-line invocation:
-# gnulib-tool --import --dir=. --local-dir=local --lib=libm4
--source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests
--no-libtool --macro-prefix=M4 assert avltree-oset binary-io clean-temp cloexec
close-stream closein config-h error fdl fflush fopen-safer free fseeko gendocs
getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint stdlib-safer
strtol unlocked-io verror version-etc version-etc-fsf xalloc xprintf
xvasprintf-posix
+# gnulib-tool --import --dir=. --local-dir=local --lib=libm4
--source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests
--no-libtool --macro-prefix=M4 assert avltree-oset binary-io clean-temp cloexec
close-stream closein config-h error fdl fflush flexmember fopen-safer free
fseeko gendocs getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint
stdlib-safer strtol unlocked-io verror version-etc version-etc-fsf xalloc
xprintf xvasprintf-posix
# Specification in the form of a few gnulib-tool.m4 macro invocations:
gl_LOCAL_DIR([local])
-gl_MODULES([assert avltree-oset binary-io clean-temp cloexec close-stream
closein config-h error fdl fflush fopen-safer free fseeko gendocs getopt
gnupload gpl-3.0 mkstemp obstack regex stdbool stdint stdlib-safer strtol
unlocked-io verror version-etc version-etc-fsf xalloc xprintf xvasprintf-posix])
+gl_MODULES([assert avltree-oset binary-io clean-temp cloexec close-stream
closein config-h error fdl fflush flexmember fopen-safer free fseeko gendocs
getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint stdlib-safer
strtol unlocked-io verror version-etc version-etc-fsf xalloc xprintf
xvasprintf-posix])
gl_AVOID([])
gl_SOURCE_BASE([lib])
gl_M4_BASE([m4])
diff --git a/src/builtin.c b/src/builtin.c
index cc4e469..eb66465 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -30,14 +30,16 @@
# include <sys/wait.h>
#endif
-#define ARG(i) (argc > (i) ? TOKEN_DATA_TEXT (argv[i]) : "")
+#define ARG(i) \
+ ((i) == 0 ? argv->argv0 \
+ : argv->argc > (i) ? TOKEN_DATA_TEXT (argv->array[(i) - 1]) : "")
/* Initialization of builtin and predefined macros. The table
"builtin_tab" is both used for initialization, and by the "builtin"
builtin. */
#define DECLARE(name) \
- static void name (struct obstack *, int, token_data **)
+ static void name (struct obstack *, int, macro_arguments *)
DECLARE (m4___file__);
DECLARE (m4___line__);
@@ -602,16 +604,19 @@ shipout_int (struct obstack *obs, int val)
`----------------------------------------------------------------------*/
static void
-dump_args (struct obstack *obs, int argc, token_data **argv,
+dump_args (struct obstack *obs, int start, macro_arguments *argv,
const char *sep, bool quoted)
{
int i;
+ bool dump_sep = false;
size_t len = strlen (sep);
- for (i = 1; i < argc; i++)
+ for (i = start; i < argv->argc; i++)
{
- if (i > 1)
+ if (dump_sep)
obstack_grow (obs, sep, len);
+ else
+ dump_sep = true;
if (quoted)
obstack_grow (obs, lquote.string, lquote.length);
obstack_grow (obs, ARG (i), strlen (ARG (i)));
@@ -623,14 +628,15 @@ dump_args (struct obstack *obs, int argc, token_data
**argv,
/* The rest of this file is code for builtins and expansion of user
defined macros. All the functions for builtins have a prototype as:
- void m4_MACRONAME (struct obstack *obs, int argc, char *argv[]);
+ void m4_MACRONAME (struct obstack *obs, int argc, macro_arguments *argv);
- The function are expected to leave their expansion on the obstack OBS,
- as an unfinished object. ARGV is a table of ARGC pointers to the
- individual arguments to the macro. Please note that in general
- argv[argc] != NULL. */
+ The functions are expected to leave their expansion on the obstack OBS,
+ as an unfinished object. ARGV is an object representing ARGC pointers
+ to the individual arguments to the macro; the object may be compressed
+ due to references to $@ expansions, so accessors should be used. Please
+ note that in general argv[argc] != NULL. */
-/* The first section are macros for definining, undefining, examining,
+/* The first section are macros for defining, undefining, examining,
changing, ... other macros. */
/*-------------------------------------------------------------------------.
@@ -641,7 +647,7 @@ dump_args (struct obstack *obs, int argc, token_data **argv,
`-------------------------------------------------------------------------*/
static void
-define_macro (int argc, token_data **argv, symbol_lookup mode)
+define_macro (int argc, macro_arguments *argv, symbol_lookup mode)
{
const builtin *bp;
const char *me = ARG (0);
@@ -649,7 +655,7 @@ define_macro (int argc, token_data **argv, symbol_lookup
mode)
if (bad_argc (me, argc, 1, 2))
return;
- if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
+ if (TOKEN_DATA_TYPE (argv->array[0]) != TOKEN_TEXT)
{
m4_warn (0, me, _("invalid macro name ignored"));
return;
@@ -661,14 +667,14 @@ define_macro (int argc, token_data **argv, symbol_lookup
mode)
return;
}
- switch (TOKEN_DATA_TYPE (argv[2]))
+ switch (TOKEN_DATA_TYPE (argv->array[1]))
{
case TOKEN_TEXT:
define_user_macro (ARG (1), ARG (2), mode);
break;
case TOKEN_FUNC:
- bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[2]));
+ bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv->array[1]));
if (bp == NULL)
return;
else
@@ -682,13 +688,13 @@ define_macro (int argc, token_data **argv, symbol_lookup
mode)
}
static void
-m4_define (struct obstack *obs, int argc, token_data **argv)
+m4_define (struct obstack *obs, int argc, macro_arguments *argv)
{
define_macro (argc, argv, SYMBOL_INSERT);
}
static void
-m4_undefine (struct obstack *obs, int argc, token_data **argv)
+m4_undefine (struct obstack *obs, int argc, macro_arguments *argv)
{
int i;
if (bad_argc (ARG (0), argc, 1, -1))
@@ -698,13 +704,13 @@ m4_undefine (struct obstack *obs, int argc, token_data
**argv)
}
static void
-m4_pushdef (struct obstack *obs, int argc, token_data **argv)
+m4_pushdef (struct obstack *obs, int argc, macro_arguments *argv)
{
- define_macro (argc, argv, SYMBOL_PUSHDEF);
+ define_macro (argc, argv, SYMBOL_PUSHDEF);
}
static void
-m4_popdef (struct obstack *obs, int argc, token_data **argv)
+m4_popdef (struct obstack *obs, int argc, macro_arguments *argv)
{
int i;
if (bad_argc (ARG (0), argc, 1, -1))
@@ -718,7 +724,7 @@ m4_popdef (struct obstack *obs, int argc, token_data **argv)
`---------------------*/
static void
-m4_ifdef (struct obstack *obs, int argc, token_data **argv)
+m4_ifdef (struct obstack *obs, int argc, macro_arguments *argv)
{
symbol *s;
const char *result;
@@ -739,10 +745,11 @@ m4_ifdef (struct obstack *obs, int argc, token_data
**argv)
}
static void
-m4_ifelse (struct obstack *obs, int argc, token_data **argv)
+m4_ifelse (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *result;
const char *me;
+ int index;
if (argc == 2)
return;
@@ -754,14 +761,14 @@ m4_ifelse (struct obstack *obs, int argc, token_data
**argv)
/* Diagnose excess arguments if 5, 8, 11, etc., actual arguments. */
bad_argc (me, argc, 0, argc - 2);
- argv++;
+ index = 1;
argc--;
result = NULL;
while (result == NULL)
- if (strcmp (ARG (0), ARG (1)) == 0)
- result = ARG (2);
+ if (strcmp (ARG (index), ARG (index + 1)) == 0)
+ result = ARG (index + 2);
else
switch (argc)
@@ -771,12 +778,12 @@ m4_ifelse (struct obstack *obs, int argc, token_data
**argv)
case 4:
case 5:
- result = ARG (3);
+ result = ARG (index + 3);
break;
default:
argc -= 3;
- argv += 3;
+ index += 3;
}
obstack_grow (obs, result, strlen (result));
@@ -826,7 +833,7 @@ dumpdef_cmp (const void *s1, const void *s2)
`-------------------------------------------------------------------------*/
static void
-m4_dumpdef (struct obstack *obs, int argc, token_data **argv)
+m4_dumpdef (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
symbol *s;
@@ -900,7 +907,7 @@ m4_dumpdef (struct obstack *obs, int argc, token_data
**argv)
`---------------------------------------------------------------------*/
static void
-m4_builtin (struct obstack *obs, int argc, token_data **argv)
+m4_builtin (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
const builtin *bp;
@@ -908,7 +915,7 @@ m4_builtin (struct obstack *obs, int argc, token_data
**argv)
if (bad_argc (me, argc, 1, -1))
return;
- if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
+ if (TOKEN_DATA_TYPE (argv->array[0]) != TOKEN_TEXT)
{
m4_warn (0, me, _("invalid macro name ignored"));
return;
@@ -921,14 +928,25 @@ m4_builtin (struct obstack *obs, int argc, token_data
**argv)
else
{
int i;
+ /* TODO make use of $@ reference, instead of copying argv. */
+ macro_arguments *new_argv = xmalloc (offsetof (macro_arguments, array)
+ + ((argc - 2)
+ * sizeof (token_data *)));
+ new_argv->argc = argc - 1;
+ new_argv->inuse = false;
+ new_argv->argv0 = name;
+ new_argv->arraylen = argc - 2;
+ memcpy (&new_argv->array[0], &argv->array[1],
+ (argc - 2) * sizeof (token_data *));
if (!bp->groks_macro_args)
for (i = 2; i < argc; i++)
- if (TOKEN_DATA_TYPE (argv[i]) != TOKEN_TEXT)
+ if (TOKEN_DATA_TYPE (new_argv->array[i - 2]) != TOKEN_TEXT)
{
- TOKEN_DATA_TYPE (argv[i]) = TOKEN_TEXT;
- TOKEN_DATA_TEXT (argv[i]) = (char *) "";
+ TOKEN_DATA_TYPE (new_argv->array[i - 2]) = TOKEN_TEXT;
+ TOKEN_DATA_TEXT (new_argv->array[i - 2]) = (char *) "";
}
- bp->func (obs, argc - 1, argv + 1);
+ bp->func (obs, argc - 1, new_argv);
+ free (new_argv);
}
}
@@ -940,7 +958,7 @@ m4_builtin (struct obstack *obs, int argc, token_data
**argv)
`------------------------------------------------------------------------*/
static void
-m4_indir (struct obstack *obs, int argc, token_data **argv)
+m4_indir (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
symbol *s;
@@ -948,7 +966,7 @@ m4_indir (struct obstack *obs, int argc, token_data **argv)
if (bad_argc (me, argc, 1, -1))
return;
- if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
+ if (TOKEN_DATA_TYPE (argv->array[0]) != TOKEN_TEXT)
{
m4_warn (0, me, _("invalid macro name ignored"));
return;
@@ -961,14 +979,25 @@ m4_indir (struct obstack *obs, int argc, token_data
**argv)
else
{
int i;
+ /* TODO make use of $@ reference, instead of copying argv. */
+ macro_arguments *new_argv = xmalloc (offsetof (macro_arguments, array)
+ + ((argc - 2)
+ * sizeof (token_data *)));
+ new_argv->argc = argc - 1;
+ new_argv->inuse = false;
+ new_argv->argv0 = name;
+ new_argv->arraylen = argc - 2;
+ memcpy (&new_argv->array[0], &argv->array[1],
+ (argc - 2) * sizeof (token_data *));
if (!SYMBOL_MACRO_ARGS (s))
for (i = 2; i < argc; i++)
- if (TOKEN_DATA_TYPE (argv[i]) != TOKEN_TEXT)
+ if (TOKEN_DATA_TYPE (new_argv->array[i - 2]) != TOKEN_TEXT)
{
- TOKEN_DATA_TYPE (argv[i]) = TOKEN_TEXT;
- TOKEN_DATA_TEXT (argv[i]) = (char *) "";
+ TOKEN_DATA_TYPE (new_argv->array[i - 2]) = TOKEN_TEXT;
+ TOKEN_DATA_TEXT (new_argv->array[i - 2]) = (char *) "";
}
- call_macro (s, argc - 1, argv + 1, obs);
+ call_macro (s, argc - 1, new_argv, obs);
+ free (new_argv);
}
}
@@ -979,7 +1008,7 @@ m4_indir (struct obstack *obs, int argc, token_data **argv)
`-------------------------------------------------------------------------*/
static void
-m4_defn (struct obstack *obs, int argc, token_data **argv)
+m4_defn (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
symbol *s;
@@ -1060,7 +1089,7 @@ m4_defn (struct obstack *obs, int argc, token_data **argv)
static int sysval;
static void
-m4_syscmd (struct obstack *obs, int argc, token_data **argv)
+m4_syscmd (struct obstack *obs, int argc, macro_arguments *argv)
{
if (bad_argc (ARG (0), argc, 1, 1))
{
@@ -1084,7 +1113,7 @@ m4_syscmd (struct obstack *obs, int argc, token_data
**argv)
}
static void
-m4_esyscmd (struct obstack *obs, int argc, token_data **argv)
+m4_esyscmd (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
FILE *pin;
@@ -1114,7 +1143,7 @@ m4_esyscmd (struct obstack *obs, int argc, token_data
**argv)
}
static void
-m4_sysval (struct obstack *obs, int argc, token_data **argv)
+m4_sysval (struct obstack *obs, int argc, macro_arguments *argv)
{
shipout_int (obs, (sysval == -1 ? 127
: (M4SYSVAL_EXITBITS (sysval)
@@ -1127,7 +1156,7 @@ m4_sysval (struct obstack *obs, int argc, token_data
**argv)
`-------------------------------------------------------------------------*/
static void
-m4_eval (struct obstack *obs, int argc, token_data **argv)
+m4_eval (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
int32_t value = 0;
@@ -1190,7 +1219,7 @@ m4_eval (struct obstack *obs, int argc, token_data **argv)
}
static void
-m4_incr (struct obstack *obs, int argc, token_data **argv)
+m4_incr (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
int value;
@@ -1205,7 +1234,7 @@ m4_incr (struct obstack *obs, int argc, token_data **argv)
}
static void
-m4_decr (struct obstack *obs, int argc, token_data **argv)
+m4_decr (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
int value;
@@ -1228,7 +1257,7 @@ m4_decr (struct obstack *obs, int argc, token_data **argv)
`-----------------------------------------------------------------------*/
static void
-m4_divert (struct obstack *obs, int argc, token_data **argv)
+m4_divert (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
int i = 0;
@@ -1245,7 +1274,7 @@ m4_divert (struct obstack *obs, int argc, token_data
**argv)
`-----------------------------------------------------*/
static void
-m4_divnum (struct obstack *obs, int argc, token_data **argv)
+m4_divnum (struct obstack *obs, int argc, macro_arguments *argv)
{
bad_argc (ARG (0), argc, 0, 0);
shipout_int (obs, current_diversion);
@@ -1259,7 +1288,7 @@ m4_divnum (struct obstack *obs, int argc, token_data
**argv)
`-----------------------------------------------------------------------*/
static void
-m4_undivert (struct obstack *obs, int argc, token_data **argv)
+m4_undivert (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
int i;
@@ -1303,7 +1332,7 @@ m4_undivert (struct obstack *obs, int argc, token_data
**argv)
`------------------------------------------------------------------------*/
static void
-m4_dnl (struct obstack *obs, int argc, token_data **argv)
+m4_dnl (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
@@ -1317,11 +1346,12 @@ m4_dnl (struct obstack *obs, int argc, token_data
**argv)
`-------------------------------------------------------------------------*/
static void
-m4_shift (struct obstack *obs, int argc, token_data **argv)
+m4_shift (struct obstack *obs, int argc, macro_arguments *argv)
{
if (bad_argc (ARG (0), argc, 1, -1))
return;
- dump_args (obs, argc - 1, argv + 1, ",", true);
+ /* TODO push a $@ reference. */
+ dump_args (obs, 2, argv, ",", true);
}
/*--------------------------------------------------------------------------.
@@ -1329,13 +1359,13 @@ m4_shift (struct obstack *obs, int argc, token_data
**argv)
`--------------------------------------------------------------------------*/
static void
-m4_changequote (struct obstack *obs, int argc, token_data **argv)
+m4_changequote (struct obstack *obs, int argc, macro_arguments *argv)
{
bad_argc (ARG (0), argc, 0, 2);
/* Explicit NULL distinguishes between empty and missing argument. */
set_quotes ((argc >= 2) ? ARG (1) : NULL,
- (argc >= 3) ? ARG (2) : NULL);
+ (argc >= 3) ? ARG (2) : NULL);
}
/*--------------------------------------------------------------------.
@@ -1344,7 +1374,7 @@ m4_changequote (struct obstack *obs, int argc, token_data
**argv)
`--------------------------------------------------------------------*/
static void
-m4_changecom (struct obstack *obs, int argc, token_data **argv)
+m4_changecom (struct obstack *obs, int argc, macro_arguments *argv)
{
bad_argc (ARG (0), argc, 0, 2);
@@ -1361,7 +1391,7 @@ m4_changecom (struct obstack *obs, int argc, token_data
**argv)
`-----------------------------------------------------------------------*/
static void
-m4_changeword (struct obstack *obs, int argc, token_data **argv)
+m4_changeword (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
@@ -1382,7 +1412,7 @@ m4_changeword (struct obstack *obs, int argc, token_data
**argv)
`-------------------------------------------------------------------------*/
static void
-include (int argc, token_data **argv, bool silent)
+include (int argc, macro_arguments *argv, bool silent)
{
const char *me = ARG (0);
FILE *fp;
@@ -1408,7 +1438,7 @@ include (int argc, token_data **argv, bool silent)
`------------------------------------------------*/
static void
-m4_include (struct obstack *obs, int argc, token_data **argv)
+m4_include (struct obstack *obs, int argc, macro_arguments *argv)
{
include (argc, argv, false);
}
@@ -1418,7 +1448,7 @@ m4_include (struct obstack *obs, int argc, token_data
**argv)
`----------------------------------*/
static void
-m4_sinclude (struct obstack *obs, int argc, token_data **argv)
+m4_sinclude (struct obstack *obs, int argc, macro_arguments *argv)
{
include (argc, argv, true);
}
@@ -1462,7 +1492,7 @@ mkstemp_helper (struct obstack *obs, const char *me,
const char *name)
}
static void
-m4_maketemp (struct obstack *obs, int argc, token_data **argv)
+m4_maketemp (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
@@ -1507,7 +1537,7 @@ m4_maketemp (struct obstack *obs, int argc, token_data
**argv)
}
static void
-m4_mkstemp (struct obstack *obs, int argc, token_data **argv)
+m4_mkstemp (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
@@ -1521,11 +1551,11 @@ m4_mkstemp (struct obstack *obs, int argc, token_data
**argv)
`----------------------------------------*/
static void
-m4_errprint (struct obstack *obs, int argc, token_data **argv)
+m4_errprint (struct obstack *obs, int argc, macro_arguments *argv)
{
if (bad_argc (ARG (0), argc, 1, -1))
return;
- dump_args (obs, argc, argv, " ", false);
+ dump_args (obs, 1, argv, " ", false);
obstack_1grow (obs, '\0');
debug_flush_files ();
xfprintf (stderr, "%s", (char *) obstack_finish (obs));
@@ -1533,7 +1563,7 @@ m4_errprint (struct obstack *obs, int argc, token_data
**argv)
}
static void
-m4___file__ (struct obstack *obs, int argc, token_data **argv)
+m4___file__ (struct obstack *obs, int argc, macro_arguments *argv)
{
bad_argc (ARG (0), argc, 0, 0);
obstack_grow (obs, lquote.string, lquote.length);
@@ -1542,14 +1572,14 @@ m4___file__ (struct obstack *obs, int argc, token_data
**argv)
}
static void
-m4___line__ (struct obstack *obs, int argc, token_data **argv)
+m4___line__ (struct obstack *obs, int argc, macro_arguments *argv)
{
bad_argc (ARG (0), argc, 0, 0);
shipout_int (obs, current_line);
}
static void
-m4___program__ (struct obstack *obs, int argc, token_data **argv)
+m4___program__ (struct obstack *obs, int argc, macro_arguments *argv)
{
bad_argc (ARG (0), argc, 0, 0);
obstack_grow (obs, lquote.string, lquote.length);
@@ -1567,7 +1597,7 @@ m4___program__ (struct obstack *obs, int argc, token_data
**argv)
`-------------------------------------------------------------------------*/
static void
-m4_m4exit (struct obstack *obs, int argc, token_data **argv)
+m4_m4exit (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
int exit_code = EXIT_SUCCESS;
@@ -1600,14 +1630,14 @@ m4_m4exit (struct obstack *obs, int argc, token_data
**argv)
`-------------------------------------------------------------------------*/
static void
-m4_m4wrap (struct obstack *obs, int argc, token_data **argv)
+m4_m4wrap (struct obstack *obs, int argc, macro_arguments *argv)
{
if (bad_argc (ARG (0), argc, 1, -1))
return;
if (no_gnu_extensions)
obstack_grow (obs, ARG (1), strlen (ARG (1)));
else
- dump_args (obs, argc, argv, " ", false);
+ dump_args (obs, 1, argv, " ", false);
obstack_1grow (obs, '\0');
push_wrapup ((char *) obstack_finish (obs));
}
@@ -1632,7 +1662,7 @@ set_trace (symbol *sym, void *data)
}
static void
-m4_traceon (struct obstack *obs, int argc, token_data **argv)
+m4_traceon (struct obstack *obs, int argc, macro_arguments *argv)
{
symbol *s;
int i;
@@ -1652,7 +1682,7 @@ m4_traceon (struct obstack *obs, int argc, token_data
**argv)
`------------------------------------------------------------------------*/
static void
-m4_traceoff (struct obstack *obs, int argc, token_data **argv)
+m4_traceoff (struct obstack *obs, int argc, macro_arguments *argv)
{
symbol *s;
int i;
@@ -1675,7 +1705,7 @@ m4_traceoff (struct obstack *obs, int argc, token_data
**argv)
`----------------------------------------------------------------------*/
static void
-m4_debugmode (struct obstack *obs, int argc, token_data **argv)
+m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
const char *str = ARG (1);
@@ -1727,7 +1757,7 @@ m4_debugmode (struct obstack *obs, int argc, token_data
**argv)
`-------------------------------------------------------------------------*/
static void
-m4_debugfile (struct obstack *obs, int argc, token_data **argv)
+m4_debugfile (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
@@ -1748,7 +1778,7 @@ m4_debugfile (struct obstack *obs, int argc, token_data
**argv)
`---------------------------------------------*/
static void
-m4_len (struct obstack *obs, int argc, token_data **argv)
+m4_len (struct obstack *obs, int argc, macro_arguments *argv)
{
if (bad_argc (ARG (0), argc, 1, 1))
return;
@@ -1761,7 +1791,7 @@ m4_len (struct obstack *obs, int argc, token_data **argv)
`-------------------------------------------------------------------------*/
static void
-m4_index (struct obstack *obs, int argc, token_data **argv)
+m4_index (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *haystack;
const char *needle;
@@ -1801,7 +1831,7 @@ m4_index (struct obstack *obs, int argc, token_data
**argv)
`-------------------------------------------------------------------------*/
static void
-m4_substr (struct obstack *obs, int argc, token_data **argv)
+m4_substr (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
int start = 0;
@@ -1885,7 +1915,7 @@ expand_ranges (const char *s, struct obstack *obs)
`----------------------------------------------------------------------*/
static void
-m4_translit (struct obstack *obs, int argc, token_data **argv)
+m4_translit (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *data;
const char *from;
@@ -1950,7 +1980,7 @@ m4_translit (struct obstack *obs, int argc, token_data
**argv)
`--------------------------------------------------------------*/
static void
-m4_format (struct obstack *obs, int argc, token_data **argv)
+m4_format (struct obstack *obs, int argc, macro_arguments *argv)
{
if (bad_argc (ARG (0), argc, 1, -1))
return;
@@ -2047,7 +2077,7 @@ init_pattern_buffer (struct re_pattern_buffer *buf,
struct re_registers *regs)
`------------------------------------------------------------------*/
static void
-m4_regexp (struct obstack *obs, int argc, token_data **argv)
+m4_regexp (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
const char *victim; /* first argument */
@@ -2117,7 +2147,7 @@ m4_regexp (struct obstack *obs, int argc, token_data
**argv)
`------------------------------------------------------------------*/
static void
-m4_patsubst (struct obstack *obs, int argc, token_data **argv)
+m4_patsubst (struct obstack *obs, int argc, macro_arguments *argv)
{
const char *me = ARG (0);
const char *victim; /* first argument */
@@ -2222,7 +2252,7 @@ m4_patsubst (struct obstack *obs, int argc, token_data
**argv)
`--------------------------------------------------------------------*/
void
-m4_placeholder (struct obstack *obs, int argc, token_data **argv)
+m4_placeholder (struct obstack *obs, int argc, macro_arguments *argv)
{
m4_warn (0, NULL, _("builtin `%s' requested by frozen file not found"),
ARG (0));
@@ -2238,7 +2268,7 @@ m4_placeholder (struct obstack *obs, int argc, token_data
**argv)
void
expand_user_macro (struct obstack *obs, symbol *sym,
- int argc, token_data **argv)
+ int argc, macro_arguments *argv)
{
const char *text;
int i;
@@ -2263,7 +2293,7 @@ expand_user_macro (struct obstack *obs, symbol *sym,
else
{
for (i = 0; isdigit (to_uchar (*text)); text++)
- i = i*10 + (*text - '0');
+ i = i * 10 + (*text - '0');
}
if (i < argc)
obstack_grow (obs, ARG (i), strlen (ARG (i)));
@@ -2276,7 +2306,8 @@ expand_user_macro (struct obstack *obs, symbol *sym,
case '*': /* all arguments */
case '@': /* ... same, but quoted */
- dump_args (obs, argc, argv, ",", *text == '@');
+ /* TODO push a $@ reference. */
+ dump_args (obs, 1, argv, ",", *text == '@');
text++;
break;
diff --git a/src/debug.c b/src/debug.c
index c22a482..e5bd280 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -362,7 +362,7 @@ trace_prepre (const char *name, int id)
`-----------------------------------------------------------------------*/
void
-trace_pre (const char *name, int id, int argc, token_data **argv)
+trace_pre (const char *name, int id, int argc, macro_arguments *argv)
{
int i;
const builtin *bp;
@@ -379,14 +379,14 @@ trace_pre (const char *name, int id, int argc, token_data
**argv)
if (i != 1)
trace_format (", ");
- switch (TOKEN_DATA_TYPE (argv[i]))
+ switch (TOKEN_DATA_TYPE (argv->array[i - 1]))
{
case TOKEN_TEXT:
- trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv[i]));
+ trace_format ("%l%S%r", TOKEN_DATA_TEXT (argv->array[i - 1]));
break;
case TOKEN_FUNC:
- bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv[i]));
+ bp = find_builtin_by_addr (TOKEN_DATA_FUNC (argv->array[i - 1]));
if (bp == NULL)
{
assert (!"trace_pre");
@@ -417,7 +417,7 @@ trace_pre (const char *name, int id, int argc, token_data
**argv)
`-------------------------------------------------------------------*/
void
-trace_post (const char *name, int id, int argc, token_data **argv,
+trace_post (const char *name, int id, int argc, macro_arguments *argv,
const char *expanded)
{
if (debug_level & DEBUG_TRACE_CALL)
diff --git a/src/format.c b/src/format.c
index 96ac562..4c2b60a 100644
--- a/src/format.c
+++ b/src/format.c
@@ -27,21 +27,17 @@
/* Simple varargs substitute. We assume int and unsigned int are the
same size; likewise for long and unsigned long. */
-#define ARG_INT(argc, argv) \
- ((argc == 0) ? 0 : \
- (--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1]))))
+#define ARG_INT(i, argc, argv) \
+ ((i == argc) ? 0 : atoi (TOKEN_DATA_TEXT (argv->array[i++ - 1])))
-#define ARG_LONG(argc, argv) \
- ((argc == 0) ? 0 : \
- (--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1]))))
+#define ARG_LONG(i, argc, argv)
\
+ ((i == argc) ? 0L : atol (TOKEN_DATA_TEXT (argv->array[i++ - 1])))
-#define ARG_STR(argc, argv) \
- ((argc == 0) ? "" : \
- (--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
+#define ARG_STR(i, argc, argv) \
+ ((i == argc) ? "" : TOKEN_DATA_TEXT (argv->array[i++ - 1]))
-#define ARG_DOUBLE(argc, argv) \
- ((argc == 0) ? 0 : \
- (--argc, argv++, atof (TOKEN_DATA_TEXT (argv[-1]))))
+#define ARG_DOUBLE(i, argc, argv) \
+ ((i == argc) ? 0.0 : atof (TOKEN_DATA_TEXT (argv->array[i++ - 1])))
/*------------------------------------------------------------------.
@@ -53,14 +49,15 @@
`------------------------------------------------------------------*/
void
-format (struct obstack *obs, int argc, token_data **argv)
+format (struct obstack *obs, int argc, macro_arguments *argv)
{
- const char *me = TOKEN_DATA_TEXT (argv[0]);
+ const char *me = argv->argv0;
const char *f; /* format control string */
const char *fmt; /* position within f */
char fstart[] = "%'+- 0#*.*hhd"; /* current format spec */
char *p; /* position within fstart */
unsigned char c; /* a simple character */
+ int index = 1; /* index within argc used so far */
/* Flags. */
char flags; /* flags to use in fstart */
@@ -88,9 +85,7 @@ format (struct obstack *obs, int argc, token_data **argv)
char *str; /* malloc'd buffer of formatted text */
enum {CHAR, INT, LONG, DOUBLE, STR} datatype;
- argv++;
- argc--;
- f = fmt = ARG_STR (argc, argv);
+ f = fmt = ARG_STR (index, argc, argv);
memset (ok, 0, sizeof ok);
for (;;)
{
@@ -175,7 +170,7 @@ format (struct obstack *obs, int argc, token_data **argv)
*p++ = '*';
if (*fmt == '*')
{
- width = ARG_INT (argc, argv);
+ width = ARG_INT (index, argc, argv);
fmt++;
}
else
@@ -195,7 +190,7 @@ format (struct obstack *obs, int argc, token_data **argv)
ok['c'] = 0;
if (*(++fmt) == '*')
{
- prec = ARG_INT (argc, argv);
+ prec = ARG_INT (index, argc, argv);
++fmt;
}
else
@@ -280,27 +275,27 @@ format (struct obstack *obs, int argc, token_data **argv)
switch (datatype)
{
case CHAR:
- str = xasprintf (fstart, width, ARG_INT(argc, argv));
+ str = xasprintf (fstart, width, ARG_INT (index, argc, argv));
break;
case INT:
- str = xasprintf (fstart, width, prec, ARG_INT(argc, argv));
+ str = xasprintf (fstart, width, prec, ARG_INT (index, argc, argv));
break;
case LONG:
- str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv));
+ str = xasprintf (fstart, width, prec, ARG_LONG (index, argc, argv));
break;
case DOUBLE:
- str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv));
+ str = xasprintf (fstart, width, prec, ARG_DOUBLE (index, argc, argv));
break;
case STR:
- str = xasprintf (fstart, width, prec, ARG_STR(argc, argv));
+ str = xasprintf (fstart, width, prec, ARG_STR (index, argc, argv));
break;
default:
- abort();
+ abort ();
}
/* NULL was returned on failure, such as invalid format string.
diff --git a/src/m4.h b/src/m4.h
index 4f1fa1f..94276e9 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -89,7 +89,8 @@ typedef struct string STRING;
/* Those must come first. */
typedef struct token_data token_data;
-typedef void builtin_func (struct obstack *, int, token_data **);
+typedef struct macro_arguments macro_arguments;
+typedef void builtin_func (struct obstack *, int, macro_arguments *);
/* Gnulib's stdbool doesn't work with bool bitfields. For nicer
debugging, use bool when we know it works, but use the more
@@ -103,14 +104,14 @@ typedef unsigned int bool_bitfield;
/* Take advantage of GNU C compiler source level optimization hints,
using portable macros. */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6)
-# define M4_GNUC_ATTRIBUTE(args) __attribute__(args)
+# define M4_GNUC_ATTRIBUTE(args) __attribute__ (args)
#else
# define M4_GNUC_ATTRIBUTE(args)
#endif /* __GNUC__ */
-#define M4_GNUC_UNUSED M4_GNUC_ATTRIBUTE((__unused__))
+#define M4_GNUC_UNUSED M4_GNUC_ATTRIBUTE ((__unused__))
#define M4_GNUC_PRINTF(fmt, arg) \
- M4_GNUC_ATTRIBUTE((__format__ (__printf__, fmt, arg)))
+ M4_GNUC_ATTRIBUTE ((__format__ (__printf__, fmt, arg)))
/* File: m4.c --- global definitions. */
@@ -132,12 +133,13 @@ extern const char *user_word_regexp; /* -W */
extern int retcode;
extern const char *program_name;
-void m4_error (int, int, const char *, const char *, ...) M4_GNUC_PRINTF(4, 5);
+void m4_error (int, int, const char *, const char *, ...)
+ M4_GNUC_PRINTF (4, 5);
void m4_error_at_line (int, int, const char *, int, const char *,
- const char *, ...) M4_GNUC_PRINTF(6, 7);
-void m4_warn (int, const char *, const char *, ...) M4_GNUC_PRINTF(3, 4);
+ const char *, ...) M4_GNUC_PRINTF (6, 7);
+void m4_warn (int, const char *, const char *, ...) M4_GNUC_PRINTF (3, 4);
void m4_warn_at_line (int, const char *, int, const char *,
- const char *, ...) M4_GNUC_PRINTF(5, 6);
+ const char *, ...) M4_GNUC_PRINTF (5, 6);
#ifdef USE_STACKOVF
void setup_stackovf_trap (char *const *, char *const *,
@@ -235,11 +237,13 @@ bool debug_set_output (const char *, const char *);
void debug_message_prefix (void);
void trace_prepre (const char *, int);
-void trace_pre (const char *, int, int, token_data **);
-void trace_post (const char *, int, int, token_data **, const char *);
+void trace_pre (const char *, int, int, macro_arguments *);
+void trace_post (const char *, int, int, macro_arguments *, const char *);
/* File: input.c --- lexical definitions. */
+typedef struct token_chain token_chain;
+
/* Various different token types. */
enum token_type
{
@@ -256,9 +260,19 @@ enum token_type
/* The data for a token, a macro argument, and a macro definition. */
enum token_data_type
{
- TOKEN_VOID,
- TOKEN_TEXT,
- TOKEN_FUNC
+ TOKEN_VOID, /* Token still being constructed, u is invalid. */
+ TOKEN_TEXT, /* Straight text, u.u_t is valid. */
+ TOKEN_FUNC, /* Builtin function definition, u.func is valid. */
+ TOKEN_COMP /* Composite argument, u.chain is valid. */
+};
+
+/* Composite tokens are built of a linked list of chains. */
+struct token_chain
+{
+ token_chain *next; /* Pointer to next link of chain. */
+ char *str; /* NUL-terminated string if text, else NULL. */
+ macro_arguments *argv; /* Reference to earlier address@hidden */
+ unsigned int index; /* Index within argv to start reading from. */
};
struct token_data
@@ -275,10 +289,31 @@ struct token_data
}
u_t;
builtin_func *func;
+
+ /* Composite text: a linked list of straight text and $@
+ placeholders. */
+ token_chain *chain;
}
u;
};
+struct macro_arguments
+{
+ /* Number of arguments owned by this object, may be larger than
+ arraylen since the array can refer to multiple arguments via a
+ single $@ reference. */
+ unsigned int argc;
+ /* False unless the macro expansion refers to $@, determines whether
+ this object can be freed at end of macro expansion or must wait
+ until next byte read from file. */
+ bool inuse;
+ const char *argv0; /* The macro name being expanded. */
+ size_t arraylen; /* True length of allocated elements in array. */
+ /* Used as a variable-length array, storing information about each
+ argument. */
+ token_data *array[FLEXIBLE_ARRAY_MEMBER];
+};
+
#define TOKEN_DATA_TYPE(Td) ((Td)->type)
#define TOKEN_DATA_TEXT(Td) ((Td)->u.u_t.text)
#ifdef ENABLE_CHANGEWORD
@@ -358,7 +393,7 @@ struct symbol
int pending_expansions;
char *name;
- token_data data;
+ token_data data; /* Type should be only TOKEN_TEXT or TOKEN_FUNC. */
};
#define SYMBOL_NEXT(S) ((S)->next)
@@ -391,7 +426,7 @@ void hack_all_symbols (hack_symbol *, void *);
extern int expansion_level;
void expand_input (void);
-void call_macro (symbol *, int, token_data **, struct obstack *);
+void call_macro (symbol *, int, macro_arguments *, struct obstack *);
/* File: builtin.c --- builtins. */
@@ -427,8 +462,8 @@ void set_macro_sequence (const char *);
void free_regex (void);
void define_user_macro (const char *, const char *, symbol_lookup);
void undivert_all (void);
-void expand_user_macro (struct obstack *, symbol *, int, token_data **);
-void m4_placeholder (struct obstack *, int, token_data **);
+void expand_user_macro (struct obstack *, symbol *, int, macro_arguments *);
+void m4_placeholder (struct obstack *, int, macro_arguments *);
void init_pattern_buffer (struct re_pattern_buffer *, struct re_registers *);
const char *ntoa (int32_t, int);
@@ -448,7 +483,7 @@ bool evaluate (const char *, const char *, int32_t *);
/* File: format.c --- printf like formatting. */
-void format (struct obstack *, int, token_data **);
+void format (struct obstack *, int, macro_arguments *);
/* File: freeze.c --- frozen state files. */
diff --git a/src/macro.c b/src/macro.c
index 8a678d4..d2f2cb7 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -241,19 +241,22 @@ expand_argument (struct obstack *obs, token_data *argp,
const char *caller)
| on the obstack ARGPTR. |
`-------------------------------------------------------------------------*/
-static void
-collect_arguments (symbol *sym, struct obstack *argptr,
+static macro_arguments *
+collect_arguments (symbol *sym, struct obstack *argptr, unsigned argv_base,
struct obstack *arguments)
{
token_data td;
token_data *tdp;
bool more_args;
bool groks_macro_args = SYMBOL_MACRO_ARGS (sym);
+ macro_arguments args;
+ macro_arguments *argv;
- TOKEN_DATA_TYPE (&td) = TOKEN_TEXT;
- TOKEN_DATA_TEXT (&td) = SYMBOL_NAME (sym);
- tdp = (token_data *) obstack_copy (arguments, &td, sizeof td);
- obstack_ptr_grow (argptr, tdp);
+ args.argc = 1;
+ args.inuse = false;
+ args.argv0 = SYMBOL_NAME (sym);
+ args.arraylen = 0;
+ obstack_grow (argptr, &args, offsetof (macro_arguments, array));
if (peek_token () == TOKEN_OPEN)
{
@@ -269,9 +272,15 @@ collect_arguments (symbol *sym, struct obstack *argptr,
}
tdp = (token_data *) obstack_copy (arguments, &td, sizeof td);
obstack_ptr_grow (argptr, tdp);
+ args.arraylen++;
+ args.argc++;
}
while (more_args);
}
+ argv = (macro_arguments *) ((char *) obstack_base (argptr) + argv_base);
+ argv->argc = args.argc;
+ argv->arraylen = args.arraylen;
+ return argv;
}
@@ -285,13 +294,13 @@ collect_arguments (symbol *sym, struct obstack *argptr,
`------------------------------------------------------------------------*/
void
-call_macro (symbol *sym, int argc, token_data **argv,
- struct obstack *expansion)
+call_macro (symbol *sym, int argc, macro_arguments *argv,
+ struct obstack *expansion)
{
switch (SYMBOL_TYPE (sym))
{
case TOKEN_FUNC:
- (*SYMBOL_FUNC (sym)) (expansion, argc, argv);
+ SYMBOL_FUNC (sym) (expansion, argc, argv);
break;
case TOKEN_TEXT:
@@ -319,8 +328,8 @@ expand_macro (symbol *sym)
{
struct obstack arguments; /* Alternate obstack if argc_stack is busy. */
unsigned argv_base; /* Size of argv_stack on entry. */
- bool use_argc_stack = true; /* Whether argc_stack is safe. */
- token_data **argv;
+ void *argc_start; /* Start of argc_stack, else NULL if unsafe. */
+ macro_arguments *argv;
int argc;
struct obstack *expansion;
const char *expanded;
@@ -357,18 +366,17 @@ expand_macro (symbol *sym)
outer invocation has an unfinished argument being
collected. */
obstack_init (&arguments);
- use_argc_stack = false;
+ argc_start = NULL;
}
+ else
+ argc_start = obstack_finish (&argc_stack);
if (traced && (debug_level & DEBUG_TRACE_CALL))
trace_prepre (SYMBOL_NAME (sym), my_call_id);
- collect_arguments (sym, &argv_stack,
- use_argc_stack ? &argc_stack : &arguments);
-
- argc = ((obstack_object_size (&argv_stack) - argv_base)
- / sizeof (token_data *));
- argv = (token_data **) ((char *) obstack_base (&argv_stack) + argv_base);
+ argv = collect_arguments (sym, &argv_stack, argv_base,
+ argc_start ? &argc_stack : &arguments);
+ argc = argv->argc;
loc_close_file = current_file;
loc_close_line = current_line;
@@ -394,9 +402,10 @@ expand_macro (symbol *sym)
if (SYMBOL_DELETED (sym))
free_symbol (sym);
- if (use_argc_stack)
- obstack_free (&argc_stack, argv[0]);
+ /* TODO pay attention to argv->inuse, in case someone is depending on
address@hidden */
+ if (argc_start)
+ obstack_free (&argc_stack, argc_start);
else
obstack_free (&arguments, NULL);
- obstack_blank (&argv_stack, -argc * sizeof (token_data *));
+ obstack_blank (&argv_stack, argv_base - obstack_object_size (&argv_stack));
}
hooks/post-receive
--
GNU M4 source repository
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-readonly-21-gac88455,
Eric Blake <=