[SCM] GNU M4 source repository branch, branch-1.6, updated. v1.5.89a-18-g50fabc4

"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=50fabc46c235da6682f1bd76b1b43151e147c7bc

The branch, branch-1.6 has been updated
       via  50fabc46c235da6682f1bd76b1b43151e147c7bc (commit)
      from  26b3c17ceb4f4155ff5dd13bcd9cc63039b3f242 (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 50fabc46c235da6682f1bd76b1b43151e147c7bc
Author: Eric Blake <[email protected]>
Date:   Thu Dec 6 14:47:26 2007 -0700

    Stage 22: allow builtin token concatenation outside $@.
    
    * src/m4.h (arg_text): Add parameter.
    (ARG): Adjust callers.
    * src/input.c (init_macro_token): Add parameter.
    (next_token): Support concatenating builtins.
    * src/macro.c (warn_builtin_concat): Delete warning.
    (expand_argument, arg_adjust_refcount): Handle builtin tokens.
    (arg_text): Add parameter.
    (arg_print): Adjust caller.
    * src/builtin.c (define_macro): Flatten builtins, rather than
    doing nothing.
    (defn): Warn on undefined macro name.
    * src/m4.c (main): Avoid atoi.
    * src/output.c: Whitespace fixes.
    * doc/m4.texinfo (Defn): Document the new semantics.
    (Ifelse, Debug Levels, M4wrap): Enhance tests.
    * NEWS: Document this change.
    
    (cherry picked from commit 8a47a2029b7eb60ac61abb1b6423d4a67b371281)
    
    Signed-off-by: Eric Blake <[email protected]>

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

Summary of changes:
 ChangeLog      |   25 ++++++++++++++++
 NEWS           |   10 ++++++
 doc/m4.texinfo |   80 ++++++++++++++++++++++++++++------------------------
 src/builtin.c  |   21 ++++++-------
 src/input.c    |   84 +++++++++++++++++++++++--------------------------------
 src/m4.c       |    2 +-
 src/m4.h       |    6 ++--
 src/macro.c    |   76 ++++++++++++++++++++------------------------------
 src/output.c   |    4 +-
 9 files changed, 159 insertions(+), 149 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 6362809..91c1845 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2008-05-05  Eric Blake  <[email protected]>
+
+	Stage 22: allow builtin token concatenation outside $@.
+	Adjust the input and argument parsing engines to append builtins
+	alongside text.  Make define warn when builtins must be
+	flattened.
+	Memory impact: slight penalty, with fewer builtins flattened.
+	Speed impact: slight penalty, from more bookkeeping.
+	* src/m4.h (arg_text): Add parameter.
+	(ARG): Adjust callers.
+	* src/input.c (init_macro_token): Add parameter.
+	(next_token): Support concatenating builtins.
+	* src/macro.c (warn_builtin_concat): Delete warning.
+	(expand_argument, arg_adjust_refcount): Handle builtin tokens.
+	(arg_text): Add parameter.
+	(arg_print): Adjust caller.
+	* src/builtin.c (define_macro): Flatten builtins, rather than
+	doing nothing.
+	(defn): Warn on undefined macro name.
+	* src/m4.c (main): Avoid atoi.
+	* src/output.c: Whitespace fixes.
+	* doc/m4.texinfo (Defn): Document the new semantics.
+	(Ifelse, Debug Levels, M4wrap): Enhance tests.
+	* NEWS: Document this change.
+
 2008-05-03  Eric Blake  <[email protected]>
 
 	Document define_blind.
diff --git a/NEWS b/NEWS
index 0ca3094..052cbbc 100644
--- a/NEWS
+++ b/NEWS
@@ -33,9 +33,19 @@ Foundation, Inc.
    then apply this patch:
      http://git.sv.gnu.org/gitweb/?p=autoconf.git;a=commitdiff;h=56d42fa71
 
+** The `defn' builtin now warns when operating on an undefined macro name.
+   To simulate 1.4.x behavior, use:
+     pushdef(`defn', `ifdef(`$1', `builtin(`defn', `$1')')')
+
 ** Enhance the `ifdef', `ifelse', and `shift' builtins, as well as all
    user macros, to transparently handle builtin tokens generated by `defn'.
 
+** Allow the concatenation of builtin macros with arbitrary text in
+   several contexts, via the `defn' builtin or argument expansion, rather
+   than warning and converting the builtin token to an empty string.
+   However, it is still not possible to use a concatenated builtin when
+   defining a macro.
+
 ** Enhance the `defn', `dumpdef', `ifdef', `popdef', `traceon', `traceoff',
    and `undefine' macros to warn when encountering a builtin token in the
    context of a macro name, rather than acting on the empty string.  This
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 4781567..fd04622 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -2112,17 +2112,14 @@ the builtin @code{defn}:
 @deffn Builtin defn (@var{name}@dots{})
 Expands to the @emph{quoted definition} of each @var{name}.  If an
 argument is not a defined macro, the expansion for that argument is
-empty.
+empty and triggers a warning.
 
 If @var{name} is a user-defined macro, the quoted definition is simply
-the quoted expansion text.  If, instead, there is only one @var{name}
-and it is a builtin, the
+the quoted expansion text.  If, instead, @var{name} is a builtin, the
 expansion is a special token, which points to the builtin's internal
-definition.  This token is only meaningful as the second argument to
+definition.  This token meaningful primarily as the second argument to
 @code{define} (and @code{pushdef}), and is silently converted to an
-empty string in most other contexts.  Using multiple @var{name} to
-combine a builtin with anything else is not supported; a warning is
-issued and the builtin is omitted from the final expansion.
+empty string in many other contexts.
 
 The macro @code{defn} is recognized only with parameters.
 @end deffn
@@ -2281,14 +2278,18 @@ bar
 @result{}0
 @end example
 
-Also note that as of M4 1.6, @code{defn} with multiple arguments can
-join text with builtin tokens.  However, when collecting macro
-arguments, a builtin token is preserved only when it occurs in
-isolation.  A future version of @acronym{GNU} M4 may lift this
-restriction.
+A warning is issued if @var{name} is undefined.  Also note that as of M4
+1.6, @code{defn} with multiple arguments can join text with builtin
+tokens.  However, when defining a macro via @code{define} or
+@code{pushdef}, a warning is issued and the builtin token ignored if the
+builtin token does not occur in isolation.  A future version of
+@acronym{GNU} M4 may lift this restriction.
 
 @example
 $ @kbd{m4 -d}
+defn(`foo')
+@error{}m4:stdin:1: Warning: defn: undefined macro `foo'
+@result{}
 define(`a', `A')define(`AA', `b')
 @result{}
 traceon(`defn', `define')
@@ -2298,29 +2299,28 @@ defn(`a', `divnum', `a')
 @result{}AA
 define(`mydivnum', defn(`divnum', `divnum'))mydivnum
 @error{}m4trace: -2- defn(`divnum', `divnum') -> `<divnum><divnum>'
-@error{}m4:stdin:4: Warning: define: cannot concatenate builtin `divnum'
-@error{}m4:stdin:4: Warning: define: cannot concatenate builtin `divnum'
-@error{}m4trace: -1- define(`mydivnum', `')
+@error{}m4:stdin:5: Warning: define: cannot concatenate builtins
+@error{}m4trace: -1- define(`mydivnum', `<divnum><divnum>')
 @result{}
-traceoff(`defn', `define')
+traceoff(`defn', `define')dumpdef(`mydivnum')
+@error{}mydivnum:@tabchar{}`'
 @result{}
 define(`mydivnum', defn(`divnum')defn(`divnum'))mydivnum
-@error{}m4:stdin:6: Warning: define: cannot concatenate builtin `divnum'
-@error{}m4:stdin:6: Warning: define: cannot concatenate builtin `divnum'
+@error{}m4:stdin:7: Warning: define: cannot concatenate builtins
 @result{}
 define(`mydivnum', defn(`divnum')`a')mydivnum
-@error{}m4:stdin:7: Warning: define: cannot concatenate builtin `divnum'
+@error{}m4:stdin:8: Warning: define: cannot concatenate builtins
 @result{}A
 define(`mydivnum', `a'defn(`divnum'))mydivnum
-@error{}m4:stdin:8: Warning: define: cannot concatenate builtin `divnum'
+@error{}m4:stdin:9: Warning: define: cannot concatenate builtins
 @result{}A
 define(`q', ``$@@'')
 @result{}
 define(`foo', q(`a', defn(`divnum')))foo
-@error{}m4:stdin:10: Warning: define: cannot concatenate builtins
-@result{}foo
+@error{}m4:stdin:11: Warning: define: cannot concatenate builtins
+@result{}a,
 ifdef(`foo', `yes', `no')
-@result{}no
+@result{}yes
 @end example
 
 @node Pushdef
@@ -2853,6 +2853,8 @@ ifelse(defn(`defn'), defn(`divnum'), `yes', `no')
 @result{}no
 ifelse(defn(`defn'), defn(`defn'), `yes', `no')
 @result{}yes
+ifelse(defn(`defn', `divnum'), defn(`defn')defn(`divnum'), `yes', `no')
+@result{}yes
 define(`foo', ifelse(`', `', defn(`divnum')))
 @result{}
 foo
@@ -2917,8 +2919,6 @@ ifelse(`-01234567890123456789', `-'e(long)`-', `yes', `no')
 @result{}no
 @end example
 
-@comment It would be nice to allow concatenation of builtins without
-@comment using $@ handling.
 @example
 define(`e', `$@@')define(`q', ``$@@'')define(`u', `$*')
 @result{}
@@ -2928,16 +2928,12 @@ cmp(`defn(`defn')', `defn(`d')')
 @result{}yes
 cmp(`defn(`defn')', ``<defn>'')
 @result{}no
-cmp(`q(defn(`defn'))', `q(defn(`d'))')-fixme
-@error{}m4:stdin:5: Warning: ifelse: cannot quote builtin
-@error{}m4:stdin:5: Warning: ifelse: cannot quote builtin
-@result{}yes-fixme
-cmp(`q(defn(`defn'))', `q(`<defn>')')-fixme
-@error{}m4:stdin:6: Warning: ifelse: cannot quote builtin
-@result{}no-fixme
-cmp(`q(defn(`defn'))', ``'')-fixme
-@error{}m4:stdin:7: Warning: ifelse: cannot quote builtin
-@result{}no-fixme
+cmp(`q(defn(`defn'))', `q(defn(`d'))')
+@result{}yes
+cmp(`q(defn(`defn'))', `q(`<defn>')')
+@result{}no
+cmp(`q(defn(`defn'))', ``'')
+@result{}no
 cmp(`q(`1', `2', defn(`defn'))', `q(`1', `2', defn(`d'))')
 @result{}yes
 cmp(`q(`1', `2', defn(`defn'))', `q(`1', `2', `<defn>')')
@@ -3834,7 +3830,17 @@ debugmode()
 foo
 @error{}m4trace: -1- foo -> `FOO'
 @result{}FOO
+debugmode(`V')
+@result{}
+foo(`ignored')
+@error{}m4trace:stdin:6: -1- id 6: foo ...
+@error{}m4trace:stdin:6: -1- id 6: foo(`ignored') -> ???
+@error{}m4trace:stdin:6: -1- id 6: foo(...) -> `FOO'
+@result{}FOO
 debugmode
+@error{}m4trace:stdin:7: -1- id 7: debugmode ...
+@error{}m4trace:stdin:7: -1- id 7: debugmode -> ???
+@error{}
 @result{}
 foo
 @error{}m4trace: -1- foo
@@ -3842,7 +3848,7 @@ foo
 debugmode(`+l')
 @result{}
 foo
-@error{}m4trace:8: -1- foo
+@error{}m4trace:10: -1- foo
 @result{}FOO
 @end example
 
@@ -4799,7 +4805,7 @@ than computing the builtin token up front, as is done for @code{bar}.
 m4wrap(`define(`foo', defn(`divnum'))foo
 ')
 @result{}
-m4wrap(`define(`bar', ')m4wrap(defn(`divnum'))m4wrap(`)bar
+m4wrap(`define(`bar', 'defn(`divnum')`)bar
 ')
 @result{}
 ^D
diff --git a/src/builtin.c b/src/builtin.c
index 2e963e3..8ce6cf7 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -678,13 +678,9 @@ define_macro (int argc, macro_arguments *argv, symbol_lookup mode)
     {
     case TOKEN_COMP:
       m4_warn (0, me, _("cannot concatenate builtins"));
-      /* TODO fall through instead.  */
-      break;
-
+      /* fallthru */
     case TOKEN_TEXT:
-      /* TODO flatten TOKEN_COMP value, or support concatenation of
-	 builtins in definitions.  */
-      define_user_macro (ARG (1), ARG_LEN (1), ARG (2), mode);
+      define_user_macro (ARG (1), ARG_LEN (1), arg_text (argv, 2, true), mode);
       break;
 
     case TOKEN_FUNC:
@@ -1012,7 +1008,10 @@ m4_defn (struct obstack *obs, int argc, macro_arguments *argv)
 	}
       s = lookup_symbol (ARG (i), SYMBOL_LOOKUP);
       if (s == NULL)
-	continue;
+	{
+	  m4_warn (0, me, _("undefined macro `%s'"), ARG (i));
+	  continue;
+	}
 
       switch (SYMBOL_TYPE (s))
 	{
@@ -1046,10 +1045,10 @@ m4_defn (struct obstack *obs, int argc, macro_arguments *argv)
 
 /* Helper macros for readability.  */
 #if UNIX || defined WEXITSTATUS
-# define M4SYSVAL_EXITBITS(status)                       \
-   (WIFEXITED (status) ? WEXITSTATUS (status) : 0)
-# define M4SYSVAL_TERMSIGBITS(status)                    \
-   (WIFSIGNALED (status) ? WTERMSIG (status) << 8 : 0)
+# define M4SYSVAL_EXITBITS(status)			 \
+  (WIFEXITED (status) ? WEXITSTATUS (status) : 0)
+# define M4SYSVAL_TERMSIGBITS(status)			 \
+  (WIFSIGNALED (status) ? WTERMSIG (status) << 8 : 0)
 
 #else /* !UNIX && !defined WEXITSTATUS */
 /* Platforms such as mingw do not support the notion of reporting
diff --git a/src/input.c b/src/input.c
index aacab61..df5a791 100644
--- a/src/input.c
+++ b/src/input.c
@@ -340,18 +340,18 @@ push_string_init (void)
 | rather than copying everything consecutively onto the input stack.  |
 | Must be called between push_string_init and push_string_finish.     |
 |                                                                     |
-| If TOKEN contains text, then convert the current input block into   |
-| a chain if it is not one already, and add the contents of TOKEN as  |
-| a new link in the chain.  LEVEL describes the current expansion     |
-| level, or -1 if TOKEN is composite, its contents reside entirely    |
-| on the current_input stack, and TOKEN lives in temporary storage.   |
-| If TOKEN is a simple string, then it belongs to the current macro   |
-| expansion.  If TOKEN is composite, then each text link has a level  |
-| of -1 if it belongs to the current macro expansion, otherwise it    |
-| is a back-reference where level tracks which stack it came from.    |
-| The resulting input block chain contains links with a level of -1   |
-| if the text belongs to the input stack, otherwise the level where   |
-| the back-reference comes from.				      |
+| Convert the current input block into a chain if it is not one	      |
+| already, and add the contents of TOKEN as a new link in the chain.  |
+| LEVEL describes the current expansion level, or -1 if TOKEN is      |
+| composite, its contents reside entirely on the current_input	      |
+| stack, and TOKEN lives in temporary storage.  If TOKEN is a simple  |
+| string, then it belongs to the current macro expansion.  If TOKEN   |
+| is composite, then each text link has a level of -1 if it belongs   |
+| to the current macro expansion, otherwise it is a back-reference    |
+| where level tracks which stack it came from.  The resulting input   |
+| block chain contains links with a level of -1 if the text belongs   |
+| to the input stack, otherwise the level where the back-reference    |
+| comes from.							      |
 |                                                                     |
 | Return true only if a reference was created to the contents of      |
 | TOKEN, in which case, LEVEL was non-negative and the lifetime of    |
@@ -1062,19 +1062,35 @@ skip_line (const char *name)
 | When next_token() sees a builtin token with peek_input, this	    |
 | retrieves the value of the function pointer, stores it in TD, and |
 | consumes the input so the caller does not need to do next_char.   |
-| If TD is NULL, discard the token instead.			    |
+| If OBS, TD will be converted to a composite token using storage   |
+| from OBS as necessary; otherwise, if TD is NULL, the builtin is   |
+| discarded.                                                        |
 `------------------------------------------------------------------*/
 
 static void
-init_macro_token (token_data *td)
+init_macro_token (struct obstack *obs, token_data *td)
 {
   token_chain *chain;
 
   assert (isp->type == INPUT_CHAIN);
   chain = isp->u.u_c.chain;
   assert (!chain->quote_age && chain->type == CHAIN_FUNC && chain->u.func);
-  if (td)
+  if (obs)
     {
+      assert (td);
+      if (TOKEN_DATA_TYPE (td) == TOKEN_VOID)
+	{
+	  TOKEN_DATA_TYPE (td) = TOKEN_COMP;
+	  td->u.u_c.chain = td->u.u_c.end = NULL;
+	  td->u.u_c.wrapper = false;
+	  td->u.u_c.has_func = true;
+	}
+      assert (TOKEN_DATA_TYPE (td) == TOKEN_COMP);
+      append_macro (obs, chain->u.func, &td->u.u_c.chain, &td->u.u_c.end);
+    }
+  else if (td)
+    {
+      assert (TOKEN_DATA_TYPE (td) == TOKEN_VOID);
       TOKEN_DATA_TYPE (td) = TOKEN_FUNC;
       TOKEN_DATA_FUNC (td) = chain->u.func;
     }
@@ -1597,7 +1613,7 @@ next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv,
     }
   if (ch == CHAR_MACRO)
     {
-      init_macro_token (td);
+      init_macro_token (obs, td);
 #ifdef DEBUG_INPUT
       xfprintf (stderr, "next_token -> MACDEF (%s)\n",
 		find_builtin_by_addr (TOKEN_DATA_FUNC (td))->name);
@@ -1633,10 +1649,7 @@ next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv,
 			      _("end of file in comment"));
 	  if (ch == CHAR_MACRO)
 	    {
-	      /* TODO support concatenation of builtins.  */
-	      m4_warn_at_line (0, file, *line, caller,
-			       _("cannot comment builtin"));
-	      init_macro_token (NULL);
+	      init_macro_token (obs, obs ? td : NULL);
 	      continue;
 	    }
 	  if (MATCH (ch, curr_comm.str2, true))
@@ -1732,35 +1745,8 @@ next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv,
 			      _("end of file in string"));
 
 	  if (ch == CHAR_MACRO)
-	    {
-	      /* TODO support concatenation of builtins.  */
-	      if (obstack_object_size (obs_td) == 0
-		  && TOKEN_DATA_TYPE (td) == TOKEN_VOID)
-		{
-		  assert (quote_level == 1);
-		  init_macro_token (td);
-		  ch = peek_input (false);
-		  if (MATCH (ch, curr_quote.str2, false))
-		    {
-#ifdef DEBUG_INPUT
-		      const builtin *bp
-			= find_builtin_by_addr (TOKEN_DATA_FUNC (td));
-		      xfprintf (stderr, "next_token -> MACDEF (%s)\n",
-				bp->name);
-#endif
-		      ch = next_char (false, false);
-		      MATCH (ch, curr_quote.str2, true);
-		      return TOKEN_MACDEF;
-		    }
-		  TOKEN_DATA_TYPE (td) = TOKEN_VOID;
-		}
-	      else
-		init_macro_token (NULL);
-	      m4_warn_at_line (0, file, *line, caller,
-			       _("cannot quote builtin"));
-	      continue;
-	    }
-	  if (ch == CHAR_QUOTE)
+	    init_macro_token (obs, obs ? td : NULL);
+	  else if (ch == CHAR_QUOTE)
 	    append_quote_token (obs, td);
 	  else if (MATCH (ch, curr_quote.str2, true))
 	    {
diff --git a/src/m4.c b/src/m4.c
index fe8c548..2ad82c2 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -573,7 +573,7 @@ main (int argc, char *const *argv, char *const *envp)
 
       case 'l':
 	{
-	  int tmp = atoi (optarg);
+	  long tmp = strtol (optarg, NULL, 10);
 	  max_debug_argument_length = tmp <= 0 ? SIZE_MAX : (size_t) tmp;
 	}
 	break;
diff --git a/src/m4.h b/src/m4.h
index 59d9be3..b3cb7e1 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -266,7 +266,7 @@ enum token_type
   TOKEN_COMMA,	/* Active character `,', TOKEN_TEXT.  */
   TOKEN_CLOSE,	/* Active character `)', TOKEN_TEXT.  */
   TOKEN_SIMPLE,	/* Any other single character, TOKEN_TEXT.  */
-  TOKEN_MACDEF,	/* A macro's definition (see "defn"), TOKEN_FUNC.  */
+  TOKEN_MACDEF,	/* A builtin macro, TOKEN_FUNC or TOKEN_COMP.  */
   TOKEN_ARGV	/* A series of parameters, TOKEN_COMP.  */
 };
 
@@ -504,7 +504,7 @@ size_t adjust_refcount (int, bool);
 bool arg_adjust_refcount (macro_arguments *, bool);
 unsigned int arg_argc (macro_arguments *);
 token_data_type arg_type (macro_arguments *, unsigned int);
-const char *arg_text (macro_arguments *, unsigned int);
+const char *arg_text (macro_arguments *, unsigned int, bool);
 bool arg_equal (macro_arguments *, unsigned int, unsigned int);
 bool arg_empty (macro_arguments *, unsigned int);
 size_t arg_len (macro_arguments *, unsigned int);
@@ -523,7 +523,7 @@ void wrap_args (macro_arguments *);
 
 /* Grab the text at argv index I.  Assumes macro_argument *argv is in
    scope, and aborts if the argument is not text.  */
-#define ARG(i) arg_text (argv, i)
+#define ARG(i) arg_text (argv, i, false)
 
 /* Grab the text length at argv index I.  Assumes macro_argument *argv
    is in scope, and aborts if the argument is not text.  */
diff --git a/src/macro.c b/src/macro.c
index d871fc2..8290818 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -329,18 +329,6 @@ expand_token (struct obstack *obs, token_type t, token_data *td, int line,
 }
 
 
-/*---------------------------------------------------------------.
-| Helper function to print warning about concatenating FUNC with |
-| text.                                                          |
-`---------------------------------------------------------------*/
-static void
-warn_builtin_concat (const char *caller, builtin_func *func)
-{
-  const builtin *bp = find_builtin_by_addr (func);
-  assert (bp);
-  m4_warn (0, caller, _("cannot concatenate builtin `%s'"), bp->name);
-}
-
 /*-------------------------------------------------------------------.
 | This function parses one argument to a macro call.  It expects the |
 | first left parenthesis or the separating comma to have been read   |
@@ -383,15 +371,10 @@ expand_argument (struct obstack *obs, token_data *argp, const char *caller)
 	case TOKEN_CLOSE:
 	  if (paren_level == 0)
 	    {
-	      size_t len = obstack_object_size (obs);
-	      if (TOKEN_DATA_TYPE (argp) == TOKEN_FUNC)
-		{
-		  if (!len)
-		    return t == TOKEN_COMMA;
-		  warn_builtin_concat (caller, TOKEN_DATA_FUNC (argp));
-		}
+	      assert (TOKEN_DATA_TYPE (argp) != TOKEN_FUNC);
 	      if (TOKEN_DATA_TYPE (argp) != TOKEN_COMP)
 		{
+		  size_t len = obstack_object_size (obs);
 		  TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
 		  if (len)
 		    {
@@ -404,7 +387,16 @@ expand_argument (struct obstack *obs, token_data *argp, const char *caller)
 		  TOKEN_DATA_QUOTE_AGE (argp) = age;
 		}
 	      else
-		make_text_link (obs, NULL, &argp->u.u_c.end);
+		{
+		  make_text_link (obs, NULL, &argp->u.u_c.end);
+		  if (argp->u.u_c.chain == argp->u.u_c.end
+		      && argp->u.u_c.chain->type == CHAIN_FUNC)
+		    {
+		      builtin_func *func = argp->u.u_c.chain->u.func;
+		      TOKEN_DATA_TYPE (argp) = TOKEN_FUNC;
+		      TOKEN_DATA_FUNC (argp) = func;
+		    }
+		}
 	      return t == TOKEN_COMMA;
 	    }
 	  /* fallthru */
@@ -427,14 +419,13 @@ expand_argument (struct obstack *obs, token_data *argp, const char *caller)
 
 	case TOKEN_WORD:
 	case TOKEN_STRING:
+	case TOKEN_MACDEF:
 	  if (!expand_token (obs, t, &td, line, first))
 	    age = 0;
 	  if (TOKEN_DATA_TYPE (&td) == TOKEN_COMP)
 	    {
 	      if (TOKEN_DATA_TYPE (argp) != TOKEN_COMP)
 		{
-		  if (TOKEN_DATA_TYPE (argp) == TOKEN_FUNC)
-		    warn_builtin_concat (caller, TOKEN_DATA_FUNC (argp));
 		  TOKEN_DATA_TYPE (argp) = TOKEN_COMP;
 		  argp->u.u_c.chain = td.u.u_c.chain;
 		  argp->u.u_c.wrapper = argp->u.u_c.has_func = false;
@@ -450,22 +441,6 @@ expand_argument (struct obstack *obs, token_data *argp, const char *caller)
 	    }
 	  break;
 
-	case TOKEN_MACDEF:
-	  if (TOKEN_DATA_TYPE (argp) == TOKEN_VOID
-	      && obstack_object_size (obs) == 0)
-	    {
-	      TOKEN_DATA_TYPE (argp) = TOKEN_FUNC;
-	      TOKEN_DATA_FUNC (argp) = TOKEN_DATA_FUNC (&td);
-	    }
-	  else
-	    {
-	      if (TOKEN_DATA_TYPE (argp) == TOKEN_FUNC)
-		warn_builtin_concat (caller, TOKEN_DATA_FUNC (argp));
-	      warn_builtin_concat (caller, TOKEN_DATA_FUNC (&td));
-	      TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
-	    }
-	  break;
-
 	case TOKEN_ARGV:
 	  assert (paren_level == 0 && TOKEN_DATA_TYPE (argp) == TOKEN_VOID
 		  && obstack_object_size (obs) == 0
@@ -798,6 +773,8 @@ arg_adjust_refcount (macro_arguments *argv, bool increase)
 		  if (chain->u.u_s.level >= 0)
 		    adjust_refcount (chain->u.u_s.level, increase);
 		  break;
+		case CHAIN_FUNC:
+		  break;
 		case CHAIN_ARGV:
 		  assert (chain->u.u_a.argv->inuse);
 		  arg_adjust_refcount (chain->u.u_a.argv, increase);
@@ -914,10 +891,11 @@ arg_type (macro_arguments *argv, unsigned int arg)
 
 /* Given ARGV, return the text at argument ARG.  Abort if the argument
    is not text.  Arg 0 is always text, and indices beyond argc return
-   the empty string.  The result is always NUL-terminated, even if it
-   includes embedded NUL characters.  */
+   the empty string.  If FLATTEN, builtins are ignored.  The result is
+   always NUL-terminated, even if it includes embedded NUL
+   characters.  */
 const char *
-arg_text (macro_arguments *argv, unsigned int arg)
+arg_text (macro_arguments *argv, unsigned int arg, bool flatten)
 {
   token_data *token;
   token_chain *chain;
@@ -927,7 +905,7 @@ arg_text (macro_arguments *argv, unsigned int arg)
     return argv->argv0;
   if (arg >= argv->argc)
     return "";
-  token = arg_token (argv, arg, NULL, false);
+  token = arg_token (argv, arg, NULL, flatten);
   switch (TOKEN_DATA_TYPE (token))
     {
     case TOKEN_TEXT:
@@ -942,13 +920,18 @@ arg_text (macro_arguments *argv, unsigned int arg)
 	    case CHAIN_STR:
 	      obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
 	      break;
+	    case CHAIN_FUNC:
+	      if (flatten)
+		break;
+	      assert (!"arg_text");
+	      abort ();
 	    case CHAIN_ARGV:
-	      assert (!chain->u.u_a.has_func || argv->flatten);
+	      assert (!chain->u.u_a.has_func || flatten || argv->flatten);
 	      arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
 			 quote_cache (NULL, chain->quote_age,
 				      chain->u.u_a.quotes),
-			 argv->flatten || chain->u.u_a.flatten, NULL, NULL,
-			 NULL, false);
+			 flatten || argv->flatten || chain->u.u_a.flatten,
+			 NULL, NULL, NULL, false);
 	      break;
 	    default:
 	      assert (!"arg_text");
@@ -969,7 +952,7 @@ arg_text (macro_arguments *argv, unsigned int arg)
 /* Given ARGV, compare text arguments INDEXA and INDEXB for equality.
    Both indices must be non-zero and less than argc.  Return true if
    the arguments contain the same contents; often more efficient than
-   strcmp (arg_text (argv, indexa), arg_text (argv, indexb)) == 0.  */
+   strcmp (arg_text (argv, a, 1), arg_text (argv, b, 1)) == 0.  */
 bool
 arg_equal (macro_arguments *argv, unsigned int indexa, unsigned int indexb)
 {
@@ -1249,6 +1232,7 @@ arg_print (struct obstack *obs, macro_arguments *argv, unsigned int arg,
   size_t sep_len;
   size_t *plen = quote_each ? NULL : &len;
 
+  flatten |= argv->flatten;
   if (chainp)
     assert (!max_len && *chainp);
   if (!sep)
diff --git a/src/output.c b/src/output.c
index d7f8570..ee1907b 100644
--- a/src/output.c
+++ b/src/output.c
@@ -199,7 +199,7 @@ m4_tmpname (int divnum)
       obstack_1grow (&diversion_storage, '-');
       offset = obstack_object_size (&diversion_storage);
       buffer = (char *) obstack_alloc (&diversion_storage,
-                                       INT_BUFSIZE_BOUND (divnum));
+				       INT_BUFSIZE_BOUND (divnum));
     }
   if (snprintf (&buffer[offset], INT_BUFSIZE_BOUND (divnum), "%d", divnum) < 0)
     m4_error (EXIT_FAILURE, errno, NULL,
@@ -387,7 +387,7 @@ make_room_for (int length)
 
       /* The current buffer may be safely reallocated.  */
       output_diversion->u.buffer = xrealloc (output_diversion->u.buffer,
-                                             (size_t) wanted_size);
+					     (size_t) wanted_size);
 
       total_buffer_size += wanted_size - output_diversion->size;
       output_diversion->size = wanted_size;


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.