[SCM] GNU M4 source repository branch, master, updated. cvs-readonly-86-g6608fa6

"Eric Blake" <[email protected]>
Newsgroups gmane.comp.gnu.m4.cvs
Message-ID <[email protected]>
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=6608fa6d084d320401f049b259adcf6b383eaa43

The branch, master has been updated
       via  6608fa6d084d320401f049b259adcf6b383eaa43 (commit)
       via  1761b0d68f12c701abfdcf0a36d955f787849e3c (commit)
       via  44c6706b4fa8c438df0f1ff44a5da6e2b3f8b294 (commit)
      from  6b1c5a2cbd84a5eb48fe352b7bc8c0568a020d62 (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 6608fa6d084d320401f049b259adcf6b383eaa43
Author: Eric Blake <[email protected]>
Date:   Tue Mar 18 14:00:39 2008 -0600

    Stage 20b: make m4wrap obey POSIX fifo ordering.
    
    * m4/m4module.h (m4_wrap_args): Add prototype.
    * m4/m4private.h (enum m4__symbol_chain_type): Add M4__CHAIN_LOC.
    (struct m4__symbol_chain): Add struct u_l.
    * m4/input.c (m4_push_wrapup_init, m4_push_wrapup_finish): Use
    new link type.
    (composite_peek, composite_read, composite_clean): Handle location
    link.
    * m4/macro.c (m4_wrap_args): New function.
    * modules/m4.c (m4wrap): Use it.
    * doc/m4.texinfo (M4wrap): Sync with branch and POSIX.
    (Extensions): Document extension of multiple arguments.
    (Location, Improved m4wrap): Adjust example to match FIFO order.
    * tests/builtins.at (wrap): Likewise.
    * NEWS: Document this change.
    
    Signed-off-by: Eric Blake <[email protected]>

commit 1761b0d68f12c701abfdcf0a36d955f787849e3c
Author: Eric Blake <[email protected]>
Date:   Mon Mar 17 16:03:57 2008 -0600

    Stage 20a: reduce unget's in input engine.
    
    * m4/input.c (struct input_funcs): Alter read_func prototype.
    (next_char, file_read, buildin_read, string_read, composite_read):
    Add allow_argv parameter.
    (init_builtin_token, init_argv_symbol): Require all prior input to
    be consumed.
    (m4_skip_line, match_input, consume_syntax): Adjust callers.
    (m4__next_token): Consume first byte without peek.
    
    Signed-off-by: Eric Blake <[email protected]>

commit 44c6706b4fa8c438df0f1ff44a5da6e2b3f8b294
Author: Eric Blake <[email protected]>
Date:   Mon Mar 17 08:16:45 2008 -0600

    Update for fresh bootstrap.
    
    * ltdl/m4/gnulib-cache.m4: Updated copyright from upstream.
    
    Signed-off-by: Eric Blake <[email protected]>

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog               |   44 +++++++++++-
 NEWS                    |    6 +-
 doc/m4.texinfo          |   62 ++++++++++++-----
 ltdl/m4/gnulib-cache.m4 |    2 +-
 m4/input.c              |  179 ++++++++++++++++++++++++++++-------------------
 m4/m4module.h           |    2 +-
 m4/m4private.h          |   13 +++-
 m4/macro.c              |   68 ++++++++++++++++++
 modules/m4.c            |    8 +--
 tests/builtins.at       |    2 +-
 10 files changed, 279 insertions(+), 107 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6e602e1..9d3c860 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2008-03-18  Eric Blake  <[email protected]>
+
+	Stage 20b: make m4wrap obey POSIX fifo ordering.
+	Improve input engine to support location changes within symbol
+	chains, then convert m4wrap to always build symbol chain.
+	Memory impact: none.
+	Speed impact: slight penalty, from more m4wrap bookkeeping.
+	* m4/m4module.h (m4_wrap_args): Add prototype.
+	* m4/m4private.h (enum m4__symbol_chain_type): Add M4__CHAIN_LOC.
+	(struct m4__symbol_chain): Add struct u_l.
+	* m4/input.c (m4_push_wrapup_init, m4_push_wrapup_finish): Use
+	new link type.
+	(composite_peek, composite_read, composite_clean): Handle location
+	link.
+	* m4/macro.c (m4_wrap_args): New function.
+	* modules/m4.c (m4wrap): Use it.
+	* doc/m4.texinfo (M4wrap): Sync with branch and POSIX.
+	(Extensions): Document extension of multiple arguments.
+	(Location, Improved m4wrap): Adjust example to match FIFO order.
+	* tests/builtins.at (wrap): Likewise.
+	* NEWS: Document this change.
+
+2008-03-17  Eric Blake  <[email protected]>
+
+	Stage 20a: reduce unget's in input engine.
+	Now that out-of-range input placeholders like CHAR_BUILTIN are
+	consumed outside of next_char, next_token should always consume
+	rather than peek at the first character.  Fewer peeks results in
+	less ungetc overhead.
+	Memory impact: none.
+	Speed impact: noticeable improvement, from fewer function calls.
+	* m4/input.c (struct input_funcs): Alter read_func prototype.
+	(next_char, file_read, buildin_read, string_read, composite_read):
+	Add allow_argv parameter.
+	(init_builtin_token, init_argv_symbol): Require all prior input to
+	be consumed.
+	(m4_skip_line, match_input, consume_syntax): Adjust callers.
+	(m4__next_token): Consume first byte without peek.
+
+	Update for fresh bootstrap.
+	* ltdl/m4/gnulib-cache.m4: Updated copyright from upstream.
+
 2008-03-15  Eric Blake  <[email protected]>
 
 	Document join, in order to fix bug in m4wrap example.
@@ -6,7 +48,7 @@
 	* Makefile.am (EXTRA_DIST): Add new files.
 	* doc/m4.texinfo (Improved m4wrap): New node.
 	(Defn, Location): Enhance tests.
-	(Shift): Document the composit macro join.
+	(Shift): Document the composite macro join.
 	(Incompatibilities): Move documentation of LIFO vs. FIFO...
 	(M4wrap): ...here, to match improved example.
 
diff --git a/NEWS b/NEWS
index 6e2fa40..eea5287 100644
--- a/NEWS
+++ b/NEWS
@@ -91,8 +91,6 @@ promoted to 2.0.
   - FIXME: POSIX recommends using ${10} instead of $10 for the tenth
   positional argument.  We should deprecate $10.
 
- - FIXME: `m4wrap' semantics need an update to FIFO.
-
 ** Removed builtins
 
 *** The experimental `epatsubst' and `eregexp' builtins have been removed
@@ -216,6 +214,10 @@ promoted to 2.0.
 ** Fix regression introduced in 1.4.10b where using `builtin' or `indir'
    to perform nested `shift' calls triggered an assertion failure.
 
+** Fix the `m4wrap' builtin to accumulate wrapped text in FIFO order, as
+   required by POSIX.  The manual mentions a way to restore the LIFO order
+   present in earlier GNU M4 versions.
+
 ** Enhance the `ifdef', `ifelse', and `shift' builtins, as well as all
    user macros, to transparently handle builtin tokens generated by `defn'.
 
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 175d923..6e836f6 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -5204,10 +5204,18 @@ normal input has been exhausted.  This feature is normally used to
 initiate cleanup actions before normal exit, e.g., deleting temporary
 files.
 
-@deffn {Builtin (m4)} m4wrap (@var{string}, @dots{})
 To save input text, use the builtin @code{m4wrap}:
-which stores @var{string} and the rest of the arguments in a safe place,
-to be reread when end of input is reached.
+
+@deffn {Builtin (m4)} m4wrap (@var{string}, @dots{})
+Stores @var{string} in a safe place, to be reread when end of input is
+reached.  As a @acronym{GNU} extension, additional arguments are
+concatenated with a space to the @var{string}.
+
+Successive invocations of @code{m4wrap} accumulate saved text in
+first-in, first-out order, as required by @acronym{POSIX}.
+
+The expansion of @code{m4wrap} is void.
+The macro @code{m4wrap} is recognized only with parameters.
 @end deffn
 
 @example
@@ -5225,16 +5233,27 @@ This is the first and last normal input line.
 The saved input is only reread when the end of normal input is seen, and
 not if @code{m4exit} is used to exit @code{m4}.
 
-@comment FIXME: this contradicts POSIX, which requires that "If the
-@comment m4wrap macro is used multiple times, the arguments specified
-@comment shall be processed in the order in which the m4wrap macros were
-@comment processed."
-It is safe to call @code{m4wrap} from saved text, but then the order in
-which the saved text is reread is undefined.  If @code{m4wrap} is not used
-recursively, the saved pieces of text are reread in the opposite order
-in which they were saved (LIFO---last in, first out).
+It is safe to call @code{m4wrap} from wrapped text, where all the
+recursively wrapped text is deferred until the current wrapped text is
+exhausted.  As of M4 1.4.11, when @code{m4wrap} is not used recursively,
+the saved pieces of text are reread in the same order in which they were
+saved (FIFO---first in, first out), as required by @acronym{POSIX}.
+
+@example
+m4wrap(`1
+')
+@result{}
+m4wrap(`2', `3
+')
+@result{}
+^D
+@result{}1
+@result{}2 3
+@end example
 
-It is possible to emulate @acronym{POSIX} behavior even
+However, earlier versions had reverse ordering (LIFO---last in, first
+out), as this behavior is more like the semantics of the C function
+@code{atexit}.  It is possible to emulate @acronym{POSIX} behavior even
 with older versions of @acronym{GNU} M4 by including the file
 @file{m4-@value{VERSION}/@/examples/@/wrapfifo.m4} from the
 distribution:
@@ -5310,13 +5329,13 @@ Invocations of @code{m4wrap} at the same recursion level are
 concatenated and rescanned as usual:
 
 @example
-define(`aa', `AA
+define(`ab', `AB
 ')
 @result{}
-m4wrap(`a')m4wrap(`a')
+m4wrap(`a')m4wrap(`b')
 @result{}
 ^D
-@result{}AA
+@result{}AB
 @end example
 
 @noindent
@@ -7778,9 +7797,9 @@ m4wrap(`__line__
 ')
 @result{}
 ^D
-@result{}12
 @result{}6
 @result{}6
+@result{}12
 @end example
 
 The @code{@w{__program__}} macro behaves like @samp{$0} in shell
@@ -8287,6 +8306,15 @@ once, but @acronym{GNU} @code{m4} correctly handles multiple instances
 of @samp{-} on the command line.
 
 @item
+@acronym{POSIX} requires @code{m4wrap} (@pxref{M4wrap}) to act in FIFO
+(first-in, first-out) order, and most other implementations obey this.
+However, versions of @acronym{GNU} @code{m4} earlier than 1.4.11 used
+LIFO order.  Furthermore, @acronym{POSIX} states that only the first
+argument to @code{m4wrap} is saved for later evaluation, but
+@acronym{GNU} @code{m4} saves and processes all arguments, with output
+separated by spaces.
+
+@item
 @acronym{POSIX} states that builtins that require arguments, but are
 called without arguments, have undefined behavior.  Traditional
 implementations simply behave as though empty strings had been passed.
@@ -8943,8 +8971,8 @@ builtin(`m4wrap', ``'define(`bar', ``$0:'-$1-$*-$#-')bar(`a', `b')
 ')
 @result{}
 ^D
-@result{}bar:-a-a,b-2-
 @result{}m4wrap0:---0-
+@result{}bar:-a-a,b-2-
 @end example
 
 Additionally, the computation of @code{_m4wrap_level} and creation of
diff --git a/ltdl/m4/gnulib-cache.m4 b/ltdl/m4/gnulib-cache.m4
index 882db83..958e7b3 100644
--- a/ltdl/m4/gnulib-cache.m4
+++ b/ltdl/m4/gnulib-cache.m4
@@ -1,4 +1,4 @@
-# Copyright (C) 2004-2007 Free Software Foundation, Inc.
+# Copyright (C) 2002-2008 Free Software Foundation, Inc.
 #
 # This file is free software, distributed under the terms of the GNU
 # General Public License.  As a special exception to the GNU General
diff --git a/m4/input.c b/m4/input.c
index 7d27dad..a7f1da9 100644
--- a/m4/input.c
+++ b/m4/input.c
@@ -93,20 +93,24 @@
    between input blocks must update the context accordingly.  */
 
 static	int	file_peek		(m4_input_block *, m4 *, bool);
-static	int	file_read		(m4_input_block *, m4 *, bool, bool);
+static	int	file_read		(m4_input_block *, m4 *, bool, bool,
+					 bool);
 static	void	file_unget		(m4_input_block *, int);
 static	bool	file_clean		(m4_input_block *, m4 *, bool);
 static	void	file_print		(m4_input_block *, m4 *, m4_obstack *);
 static	int	builtin_peek		(m4_input_block *, m4 *, bool);
-static	int	builtin_read		(m4_input_block *, m4 *, bool, bool);
+static	int	builtin_read		(m4_input_block *, m4 *, bool, bool,
+					 bool);
 static	void	builtin_unget		(m4_input_block *, int);
 static	void	builtin_print		(m4_input_block *, m4 *, m4_obstack *);
 static	int	string_peek		(m4_input_block *, m4 *, bool);
-static	int	string_read		(m4_input_block *, m4 *, bool, bool);
+static	int	string_read		(m4_input_block *, m4 *, bool, bool,
+					 bool);
 static	void	string_unget		(m4_input_block *, int);
 static	void	string_print		(m4_input_block *, m4 *, m4_obstack *);
 static	int	composite_peek		(m4_input_block *, m4 *, bool);
-static	int	composite_read		(m4_input_block *, m4 *, bool, bool);
+static	int	composite_read		(m4_input_block *, m4 *, bool, bool,
+					 bool);
 static	void	composite_unget		(m4_input_block *, int);
 static	bool	composite_clean		(m4_input_block *, m4 *, bool);
 static	void	composite_print		(m4_input_block *, m4 *, m4_obstack *);
@@ -115,7 +119,7 @@ static	void	init_builtin_token	(m4 *, m4_symbol_value *);
 static	void	append_quote_token	(m4 *, m4_obstack *,
 					 m4_symbol_value *);
 static	bool	match_input		(m4 *, const char *, bool);
-static	int	next_char		(m4 *, bool, bool);
+static	int	next_char		(m4 *, bool, bool, bool);
 static	int	peek_char		(m4 *, bool);
 static	bool	pop_input		(m4 *, bool);
 static	void	unget_input		(int);
@@ -138,9 +142,11 @@ struct input_funcs
 
   /* Read input, return an unsigned char, CHAR_BUILTIN if it is a
      builtin, or CHAR_RETRY if none available.  If ALLOW_QUOTE, then
-     CHAR_QUOTE may be returned.  If SAFE, then do not alter the
-     current file or line.  */
-  int	(*read_func)	(m4_input_block *, m4 *, bool allow_quote, bool safe);
+     CHAR_QUOTE may be returned.  If ALLOW_ARGV, then CHAR_ARGV may be
+     returned.  If SAFE, then do not alter the current file or
+     line.  */
+  int	(*read_func)	(m4_input_block *, m4 *, bool allow_quote,
+			 bool allow_argv, bool safe);
 
   /* Unread a single unsigned character or CHAR_BUILTIN, must be the
      same character previously read by read_func.  */
@@ -198,11 +204,7 @@ static m4_obstack token_stack;
 /* Obstack for storing input file names.  */
 static m4_obstack file_names;
 
-/* Wrapup input stack.
-
-   FIXME - m4wrap should be FIFO, which implies a queue, not a stack.
-   While fixing this, m4wrap should also remember what the current
-   file and line are for each chunk of wrapped text.  */
+/* Wrapup input stack.  */
 static m4_obstack *wrapup_stack;
 
 /* Current stack, from input or wrapup.  */
@@ -268,7 +270,7 @@ file_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
 
 static int
 file_read (m4_input_block *me, m4 *context, bool allow_quote M4_GNUC_UNUSED,
-	   bool safe M4_GNUC_UNUSED)
+	   bool allow_argv M4_GNUC_UNUSED, bool safe M4_GNUC_UNUSED)
 {
   int ch;
 
@@ -394,7 +396,8 @@ builtin_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
 
 static int
 builtin_read (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
-	      bool allow_quote M4_GNUC_UNUSED, bool safe M4_GNUC_UNUSED)
+	      bool allow_quote M4_GNUC_UNUSED, bool allow_argv M4_GNUC_UNUSED,
+	      bool safe M4_GNUC_UNUSED)
 {
   /* Not consumed here - wait until init_builtin_token.  */
   return me->u.builtin ? CHAR_BUILTIN : CHAR_RETRY;
@@ -453,7 +456,8 @@ string_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
 
 static int
 string_read (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
-	     bool allow_quote M4_GNUC_UNUSED, bool safe M4_GNUC_UNUSED)
+	     bool allow_quote M4_GNUC_UNUSED, bool allow_argv M4_GNUC_UNUSED,
+	     bool safe M4_GNUC_UNUSED)
 {
   if (!me->u.u_s.len)
     return CHAR_RETRY;
@@ -747,6 +751,8 @@ composite_peek (m4_input_block *me, m4 *context, bool allow_argv)
 	  chain->u.u_a.comma = true;
 	  m4_push_string_finish ();
 	  return peek_char (context, allow_argv);
+	case M4__CHAIN_LOC:
+	  break;
 	default:
 	  assert (!"composite_peek");
 	  abort ();
@@ -757,9 +763,11 @@ composite_peek (m4_input_block *me, m4 *context, bool allow_argv)
 }
 
 static int
-composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe)
+composite_read (m4_input_block *me, m4 *context, bool allow_quote,
+		bool allow_argv, bool safe)
 {
   m4__symbol_chain *chain = me->u.u_c.chain;
+  size_t argc;
   while (chain)
     {
       if (allow_quote && chain->quote_age == m4__quote_age (M4SYNTAX))
@@ -782,7 +790,8 @@ composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe)
 	    return CHAR_BUILTIN;
 	  break;
 	case M4__CHAIN_ARGV:
-	  if (chain->u.u_a.index == m4_arg_argc (chain->u.u_a.argv))
+	  argc = m4_arg_argc (chain->u.u_a.argv);
+	  if (chain->u.u_a.index == argc)
 	    {
 	      m4__arg_adjust_refcount (context, chain->u.u_a.argv, false);
 	      break;
@@ -792,6 +801,11 @@ composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe)
 	      chain->u.u_a.comma = false;
 	      return ','; /* FIXME - support M4_SYNTAX_COMMA.  */
 	    }
+	  /* Only return a reference in the quoting is correct and the
+	     reference has more than one argument left.  */
+	  if (allow_argv && chain->quote_age == m4__quote_age (M4SYNTAX)
+	      && chain->u.u_a.quotes && chain->u.u_a.index + 1 < argc)
+	    return CHAR_ARGV;
 	  /* Rather than directly parse argv here, we push another
 	     input block containing the next unparsed argument from
 	     argv.  */
@@ -804,7 +818,13 @@ composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe)
 	  chain->u.u_a.index++;
 	  chain->u.u_a.comma = true;
 	  m4_push_string_finish ();
-	  return next_char (context, allow_quote, !safe);
+	  return next_char (context, allow_quote, allow_argv, !safe);
+	case M4__CHAIN_LOC:
+	  me->file = chain->u.u_l.file;
+	  me->line = chain->u.u_l.line;
+	  input_change = true;
+	  me->u.u_c.chain = chain->next;
+	  return next_char (context, allow_quote, allow_argv, !safe);
 	default:
 	  assert (!"composite_read");
 	  abort ();
@@ -869,6 +889,8 @@ composite_clean (m4_input_block *me, m4 *context, bool cleanup)
 	    }
 	  m4__arg_adjust_refcount (context, chain->u.u_a.argv, false);
 	  break;
+	case M4__CHAIN_LOC:
+	  return false;
 	default:
 	  assert (!"composite_clean");
 	  abort ();
@@ -985,14 +1007,36 @@ m4_obstack *
 m4_push_wrapup_init (m4 *context)
 {
   m4_input_block *i;
+  m4__symbol_chain *chain;
 
-  i = (m4_input_block *) obstack_alloc (wrapup_stack, sizeof *i);
-  i->prev = wsp;
-
-  i->funcs = &string_funcs;
-  i->file = m4_get_current_file (context);
-  i->line = m4_get_current_line (context);
-  wsp = i;
+  assert (obstack_object_size (wrapup_stack) == 0);
+  if (wsp)
+    {
+      i = wsp;
+      assert (i->funcs == &composite_funcs && i->u.u_c.end
+	      && i->u.u_c.end->type != M4__CHAIN_LOC);
+    }
+  else
+    {
+      i = (m4_input_block *) obstack_alloc (wrapup_stack, sizeof *i);
+      i->prev = wsp;
+      i->funcs = &composite_funcs;
+      i->file = m4_get_current_file (context);
+      i->line = m4_get_current_line (context);
+      i->u.u_c.chain = i->u.u_c.end = NULL;
+      wsp = i;
+    }
+  chain = (m4__symbol_chain *) obstack_alloc (wrapup_stack, sizeof *chain);
+  if (i->u.u_c.end)
+    i->u.u_c.end->next = chain;
+  else
+    i->u.u_c.chain = chain;
+  i->u.u_c.end = chain;
+  chain->next = NULL;
+  chain->type = M4__CHAIN_LOC;
+  chain->quote_age = 0;
+  chain->u.u_l.file = m4_get_current_file (context);
+  chain->u.u_l.line = m4_get_current_line (context);
   return wrapup_stack;
 }
 
@@ -1000,17 +1044,8 @@ m4_push_wrapup_init (m4 *context)
 void
 m4_push_wrapup_finish (void)
 {
-  m4_input_block *i = wsp;
-  if (obstack_object_size (wrapup_stack) == 0)
-    {
-      wsp = i->prev;
-      obstack_free (wrapup_stack, i);
-    }
-  else
-    {
-      i->u.u_s.len = obstack_object_size (wrapup_stack);
-      i->u.u_s.str = (char *) obstack_finish (wrapup_stack);
-    }
+  m4__make_text_link (wrapup_stack, &wsp->u.u_c.chain, &wsp->u.u_c.end);
+  assert (wsp->u.u_c.end->type != M4__CHAIN_LOC);
 }
 
 
@@ -1085,9 +1120,6 @@ m4_pop_wrapup (m4 *context)
 static void
 init_builtin_token (m4 *context, m4_symbol_value *token)
 {
-  int ch = next_char (context, false, true);
-  assert (ch == CHAR_BUILTIN);
-
   if (isp->funcs == &builtin_funcs)
     {
       assert (isp->u.builtin);
@@ -1159,11 +1191,10 @@ init_argv_symbol (m4 *context, m4_obstack *obs, m4_symbol_value *value)
 {
   m4__symbol_chain *src_chain;
   m4__symbol_chain *chain;
-  int ch = next_char (context, true, true);
+  int ch;
   const m4_string_pair *comments = m4_get_syntax_comments (M4SYNTAX);
 
-  assert (ch == CHAR_QUOTE && value->type == M4_SYMBOL_VOID
-	  && isp->funcs == &composite_funcs
+  assert (value->type == M4_SYMBOL_VOID && isp->funcs == &composite_funcs
 	  && isp->u.u_c.chain->type == M4__CHAIN_ARGV
 	  && obs && obstack_object_size (obs) == 0);
 
@@ -1201,7 +1232,7 @@ init_argv_symbol (m4 *context, m4_obstack *obs, m4_symbol_value *value)
 	  || (!m4_has_syntax (M4SYNTAX, *comments->str1,
 			      M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE)
 	      && *comments->str1 != *src_chain->u.u_a.quotes->str1));
-  ch = peek_char (context, false);
+  ch = peek_char (context, true);
   if (!m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE))
     {
       isp->u.u_c.chain = src_chain;
@@ -1217,10 +1248,12 @@ init_argv_symbol (m4 *context, m4_obstack *obs, m4_symbol_value *value)
    next_char () is used to read and advance the input to the next
    character.  If ALLOW_QUOTE, and the current input matches the
    current quote age, return CHAR_QUOTE and leave consumption of data
-   for append_quote_token.  If RETRY, then avoid returning CHAR_RETRY
-   by popping input.  */
+   for append_quote_token; otherwise, if ALLOW_ARGV, and the current
+   input matches an argv reference with the correct quoting, return
+   CHAR_ARGV and leave consumption of data for init_argv_symbol.  If
+   RETRY, then avoid returning CHAR_RETRY by popping input.  */
 static int
-next_char (m4 *context, bool allow_quote, bool retry)
+next_char (m4 *context, bool allow_quote, bool allow_argv, bool retry)
 {
   int ch;
 
@@ -1240,7 +1273,8 @@ next_char (m4 *context, bool allow_quote, bool retry)
 	}
 
       assert (isp->funcs->read_func);
-      while (((ch = isp->funcs->read_func (isp, context, allow_quote, !retry))
+      while (((ch = isp->funcs->read_func (isp, context, allow_quote,
+					   allow_argv, !retry))
 	      != CHAR_RETRY)
 	     || !retry)
 	{
@@ -1273,7 +1307,7 @@ peek_char (m4 *context, bool allow_argv)
       if (ch != CHAR_RETRY)
 	{
 /*	  if (IS_IGNORE (ch)) */
-/*	    return next_char (context, false, true); */
+/*	    return next_char (context, false, true, true); */
 	  return ch;
 	}
 
@@ -1283,7 +1317,7 @@ peek_char (m4 *context, bool allow_argv)
 
 /* The function unget_input () puts back a character on the input
    stack, using an existing input_block if possible.  This is not safe
-   to call except immediately after next_char(context, allow, false).  */
+   to call except immediately after next_char(context, aq, aa, false).  */
 static void
 unget_input (int ch)
 {
@@ -1301,7 +1335,8 @@ m4_skip_line (m4 *context, const char *name)
   const char *file = m4_get_current_file (context);
   int line = m4_get_current_line (context);
 
-  while ((ch = next_char (context, false, true)) != CHAR_EOF && ch != '\n')
+  while ((ch = next_char (context, false, false, true)) != CHAR_EOF
+	 && ch != '\n')
     ;
   if (ch == CHAR_EOF)
     /* current_file changed; use the previous value we cached.  */
@@ -1346,14 +1381,14 @@ match_input (m4 *context, const char *s, bool consume)
   if (s[1] == '\0')
     {
       if (consume)
-	next_char (context, false, true);
+	next_char (context, false, false, true);
       return true;			/* short match */
     }
 
-  next_char (context, false, true);
+  next_char (context, false, false, true);
   for (n = 1, t = s++; (ch = peek_char (context, false)) == to_uchar (*s++); )
     {
-      next_char (context, false, true);
+      next_char (context, false, false, true);
       n++;
       if (*s == '\0')		/* long match */
 	{
@@ -1391,29 +1426,29 @@ static bool
 consume_syntax (m4 *context, m4_obstack *obs, unsigned int syntax)
 {
   int ch;
-  bool allow_quote = m4__safe_quotes (M4SYNTAX);
+  bool allow = m4__safe_quotes (M4SYNTAX);
   assert (syntax);
   while (1)
     {
       /* It is safe to call next_char without first checking
 	 peek_char, except at input source boundaries, which we detect
 	 by CHAR_RETRY.  We exploit the fact that CHAR_EOF,
-	 CHAR_BUILTIN, and CHAR_QUOTE do not satisfy any syntax
-	 categories.  */
-      while ((ch = next_char (context, allow_quote, false)) != CHAR_RETRY
+	 CHAR_BUILTIN, CHAR_QUOTE, and CHAR_ARGV do not satisfy any
+	 syntax categories.  */
+      while ((ch = next_char (context, allow, allow, false)) != CHAR_RETRY
 	     && m4_has_syntax (M4SYNTAX, ch, syntax))
 	{
 	  assert (ch < CHAR_EOF);
 	  obstack_1grow (obs, ch);
 	}
-      if (ch == CHAR_RETRY || ch == CHAR_QUOTE)
+      if (ch == CHAR_RETRY || ch == CHAR_QUOTE || ch == CHAR_ARGV)
 	{
 	  ch = peek_char (context, false);
 	  if (m4_has_syntax (M4SYNTAX, ch, syntax))
 	    {
 	      assert (ch < CHAR_EOF);
 	      obstack_1grow (obs, ch);
-	      next_char (context, false, true);
+	      next_char (context, false, false, true);
 	      continue;
 	    }
 	  return ch == CHAR_EOF;
@@ -1499,15 +1534,14 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
   do {
     obstack_free (&token_stack, token_bottom);
 
-    /* Must consume an input character, but not until CHAR_BUILTIN is
-       handled.  */
-    ch = peek_char (context, allow_argv && m4__quote_age (M4SYNTAX));
+    /* Must consume an input character.  */
+    ch = next_char (context, false, allow_argv && m4__quote_age (M4SYNTAX),
+		    true);
     if (ch == CHAR_EOF)			/* EOF */
       {
 #ifdef DEBUG_INPUT
 	xfprintf (stderr, "next_token -> EOF\n");
 #endif
-	next_char (context, false, true);
 	return M4_TOKEN_EOF;
       }
 
@@ -1528,15 +1562,13 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
 	return M4_TOKEN_ARGV;
       }
 
-    /* Consume character we already peeked at.  */
-    next_char (context, false, true);
     file = m4_get_current_file (context);
     *line = m4_get_current_line (context);
 
     if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_ESCAPE))
       {					/* ESCAPED WORD */
 	obstack_1grow (&token_stack, ch);
-	if ((ch = next_char (context, false, true)) < CHAR_EOF)
+	if ((ch = next_char (context, false, false, true)) < CHAR_EOF)
 	  {
 	    obstack_1grow (&token_stack, ch);
 	    if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_ALPHA))
@@ -1564,7 +1596,8 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
 	type = M4_TOKEN_STRING;
 	while (1)
 	  {
-	    ch = next_char (context, obs && m4__quote_age (M4SYNTAX), true);
+	    ch = next_char (context, obs && m4__quote_age (M4SYNTAX), false,
+			    true);
 	    if (ch == CHAR_EOF)
 	      m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
 				_("end of file in string"));
@@ -1581,7 +1614,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
 		    ch = peek_char (context, false);
 		    if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_RQUOTE))
 		      {
-			ch = next_char (context, false, true);
+			ch = next_char (context, false, false, true);
 #ifdef DEBUG_INPUT
 			m4_print_token (context, "next_token", M4_TOKEN_MACDEF,
 					token);
@@ -1623,7 +1656,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
 	assert (!m4__quote_age (M4SYNTAX));
 	while (1)
 	  {
-	    ch = next_char (context, false, true);
+	    ch = next_char (context, false, false, true);
 	    if (ch == CHAR_EOF)
 	      m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
 				_("end of file in string"));
@@ -1641,7 +1674,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
 		    if (MATCH (context, ch, context->syntax->quote.str2,
 			       false))
 		      {
-			ch = next_char (context, false, true);
+			ch = next_char (context, false, false, true);
 			MATCH (context, ch, context->syntax->quote.str2, true);
 #ifdef DEBUG_INPUT
 			m4_print_token (context, "next_token", M4_TOKEN_MACDEF,
@@ -1681,7 +1714,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
 	obstack_1grow (obs_safe, ch);
 	while (1)
 	  {
-	    ch = next_char (context, false, true);
+	    ch = next_char (context, false, false, true);
 	    if (ch == CHAR_EOF)
 	      m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
 				_("end of file in comment"));
@@ -1713,7 +1746,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int *line,
 		      context->syntax->comm.len1);
 	while (1)
 	  {
-	    ch = next_char (context, false, true);
+	    ch = next_char (context, false, false, true);
 	    if (ch == CHAR_EOF)
 	      m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
 				_("end of file in comment"));
diff --git a/m4/m4module.h b/m4/m4module.h
index 6cbe185..357baca 100644
--- a/m4/m4module.h
+++ b/m4/m4module.h
@@ -1,5 +1,4 @@
 /* GNU m4 -- A simple macro processor
-
    Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1999, 2000, 2003,
    2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
@@ -374,6 +373,7 @@ extern void	m4_push_arg		(m4 *, m4_obstack *, m4_macro_args *,
 					 size_t);
 extern void	m4_push_args		(m4 *, m4_obstack *, m4_macro_args *,
 					 bool, bool);
+extern void	m4_wrap_args		(m4 *, m4_macro_args *);
 
 
 /* --- RUNTIME DEBUGGING --- */
diff --git a/m4/m4private.h b/m4/m4private.h
index 5ff7c95..86f18e8 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -1,7 +1,6 @@
 /* GNU m4 -- A simple macro processor
-
-   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1998, 1999, 2004, 2005,
-   2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1998, 1999, 2004,
+   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
    This file is part of GNU M4.
 
@@ -212,7 +211,8 @@ enum m4__symbol_chain_type
 {
   M4__CHAIN_STR,	/* Link contains a string, u.u_s is valid.  */
   M4__CHAIN_FUNC,	/* Link contains builtin token, u.builtin is valid.  */
-  M4__CHAIN_ARGV	/* Link contains a $@ reference, u.u_a is valid.  */
+  M4__CHAIN_ARGV,	/* Link contains a $@ reference, u.u_a is valid.  */
+  M4__CHAIN_LOC		/* Link contains m4wrap location, u.u_l is valid.  */
 };
 
 /* Composite symbols are built of a linked list of chain objects.  */
@@ -240,6 +240,11 @@ struct m4__symbol_chain
       bool_bitfield has_func : 1;	/* True if argv includes func.  */
       const m4_string_pair *quotes;	/* NULL for $*, quotes for $@.  */
     } u_a;			/* M4__CHAIN_ARGV.  */
+    struct
+    {
+      const char *file;	/* File where subsequent links originate.  */
+      int line;		/* Line where subsequent links originate.  */
+    } u_l;			/* M4__CHAIN_LOC.  */
   } u;
 };
 
diff --git a/m4/macro.c b/m4/macro.c
index d03f551..6d1976d 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -1670,6 +1670,74 @@ m4_push_args (m4 *context, m4_obstack *obs, m4_macro_args *argv, bool skip,
     arg_mark (argv);
 }
 
+/* Push arguments from ARGV onto the wrap stack for later rescanning.
+   If GNU extensions are disabled, only the first argument is pushed;
+   otherwise, all arguments are pushed and separated with a space.  */
+void
+m4_wrap_args (m4 *context, m4_macro_args *argv)
+{
+  size_t i;
+  m4_obstack *obs;
+  m4_symbol_value *value;
+  m4__symbol_chain *chain;
+  size_t limit = m4_get_posixly_correct_opt (context) ? 2 : argv->argc;
+
+  if (limit == 2 && m4_arg_empty (argv, 1))
+    return;
+
+  obs = m4_push_wrapup_init (context);
+  for (i = 1; i < limit; i++)
+    {
+      if (i != 1)
+	obstack_1grow (obs, ' ');
+      value = m4_arg_symbol (argv, i);
+      switch (value->type)
+	{
+	case M4_SYMBOL_TEXT:
+	  obstack_grow (obs, m4_get_symbol_value_text (value),
+			m4_get_symbol_value_len (value));
+	  break;
+	case M4_SYMBOL_FUNC:
+	  /* TODO allow builtins.  */
+	  assert (false);
+	  break;
+	case M4_SYMBOL_COMP:
+	  chain = value->u.u_c.chain;
+	  while (chain)
+	    {
+	      switch (chain->type)
+		{
+		case M4__CHAIN_STR:
+		  obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
+		  break;
+		case M4__CHAIN_FUNC:
+		  /* TODO allow builtins.  */
+		  assert (false);
+		  break;
+		case M4__CHAIN_ARGV:
+		  m4_arg_print (context, obs, chain->u.u_a.argv,
+				chain->u.u_a.index,
+				m4__quote_cache (M4SYNTAX, NULL,
+						 chain->quote_age,
+						 chain->u.u_a.quotes),
+				chain->u.u_a.flatten, NULL, NULL, false,
+				false);
+		  break;
+		default:
+		  assert (!"m4_wrap_args");
+		  abort ();
+		}
+	      chain = chain->next;
+	    }
+	  break;
+	default:
+	  assert (!"m4_wrap_args");
+	  abort ();
+	}
+    }
+  m4_push_wrapup_finish ();
+}
+
 
 /* Define these last, so that earlier uses can benefit from the macros
    in m4private.h.  */
diff --git a/modules/m4.c b/modules/m4.c
index 359839b..02ac090 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -833,13 +833,7 @@ M4BUILTIN_HANDLER (m4exit)
    version only the first.  */
 M4BUILTIN_HANDLER (m4wrap)
 {
-  obs = m4_push_wrapup_init (context);
-  if (m4_get_posixly_correct_opt (context))
-    obstack_grow (obs, M4ARG (1), M4ARGLEN (1));
-  else
-    /* TODO allow pushing builtins.  */
-    m4_arg_print (context, obs, argv, 1, NULL, true, " ", NULL, false, false);
-  m4_push_wrapup_finish ();
+  m4_wrap_args (context, argv);
 }
 
 /* Enable tracing of all specified macros, or all, if none is specified.
diff --git a/tests/builtins.at b/tests/builtins.at
index 08c881b..34143a1 100644
--- a/tests/builtins.at
+++ b/tests/builtins.at
@@ -1227,8 +1227,8 @@ No. 33: The End.
 AT_CHECK_M4([wrap.m4], 0,
 [[
 No. 33: The End.
-Wrapper no. 2
 Wrapper no. 1
+Wrapper no. 2
 Wrapper no. 3
 Wrapper no. 4
 ]])


hooks/post-receive
--
GNU M4 source repository
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.