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

"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=bc4cf0aa6f3aa46da1cb46c25ded92362f6dba22

The branch, branch-1.6 has been updated
       via  bc4cf0aa6f3aa46da1cb46c25ded92362f6dba22 (commit)
      from  c8a2c296df00c2e8b1b3b0372cea10d0d0a0b621 (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 bc4cf0aa6f3aa46da1cb46c25ded92362f6dba22
Author: Eric Blake <[email protected]>
Date:   Thu Dec 13 10:37:51 2007 -0700

    Stage 23: allow tracing of indirect macro calls.
    
    * src/m4.h (struct call_info): New struct.
    (trace_prepre, trace_pre, trace_post, push_string_finish)
    (input_print, call_macro): Alter signatures.
    (arg_info): New prototype.
    (input_block): Delete...
    * src/input.c (input_block): ...and make typedef local again.
    (push_string_init): Initialize length.
    (push_string_finish, input_print): Change signature, so that
    printing can be done before finalization.
    * src/macro.c (struct macro_arguments): Add info member.
    (collect_arguments, make_argv_ref): Manage new field.
    (expand_macro): Change call context management.  Move tracing...
    (call_macro): ...here, and remove redundant parameter.
    (arg_info): New function.
    * src/debug.c (trace_format): Delete unused modifiers.
    (trace_header, trace_flush, trace_prepre, trace_pre, trace_post):
    Change signatures for stacked trace messages, and for using call
    context.
    * src/builtin.c (m4_builtin, m4_indir): Update callers.
    * src/m4.c (usage): Update debugmode flag summary.
    * doc/m4.texinfo (Defn): Update examples to match new behavior.
    (Trace): Mention new capability of indir.
    (Debug Levels): Enhance text for 'c' and 'x', update examples.
    (Incompatibilities): Mention risk of parsing trace output.
    * examples/null.m4: Enhance test.
    * examples/null.err: Update expected output.
    * NEWS: Mention these changes.
    Reported by Akim Demaille in the autoconf TODO file in 2000.
    
    (cherry picked from commit ec804cba9ceeef7ca863d163eeae3fca669ccd16)
    
    Signed-off-by: Eric Blake <[email protected]>

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

Summary of changes:
 ChangeLog         |   37 ++++++++++++
 NEWS              |   13 ++++
 doc/m4.texinfo    |  110 +++++++++++++++++++++++++++-------
 examples/null.err |  Bin 18 -> 51 bytes
 examples/null.m4  |  Bin 5863 -> 5876 bytes
 src/builtin.c     |    8 ++-
 src/debug.c       |  168 ++++++++++++++++++++++++-----------------------------
 src/input.c       |   42 +++++++------
 src/m4.c          |   95 ++++++++++++++++--------------
 src/m4.h          |   30 +++++++---
 src/macro.c       |  120 ++++++++++++++++++++++----------------
 11 files changed, 385 insertions(+), 238 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d5b23b6..0a40526 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2008-05-09  Eric Blake  <[email protected]>
+
+	Stage 23: allow tracing of indirect macro calls.
+	Track all trace information as part of the argv struct, rather
+	than temporarily resetting global state.  Teach indir to trace
+	macros that it invokes.
+	Memory impact: slight penalty, due to larger argv struct.
+	Speed impact: none noticed.
+	* src/m4.h (struct call_info): New struct.
+	(trace_prepre, trace_pre, trace_post, push_string_finish)
+	(input_print, call_macro): Alter signatures.
+	(arg_info): New prototype.
+	(input_block): Delete...
+	* src/input.c (input_block): ...and make typedef local again.
+	(push_string_init): Initialize length.
+	(push_string_finish, input_print): Change signature, so that
+	printing can be done before finalization.
+	* src/macro.c (struct macro_arguments): Add info member.
+	(collect_arguments, make_argv_ref): Manage new field.
+	(expand_macro): Change call context management.  Move tracing...
+	(call_macro): ...here, and remove redundant parameter.
+	(arg_info): New function.
+	* src/debug.c (trace_format): Delete unused modifiers.
+	(trace_header, trace_flush, trace_prepre, trace_pre, trace_post):
+	Change signatures for stacked trace messages, and for using call
+	context.
+	* src/builtin.c (m4_builtin, m4_indir): Update callers.
+	* src/m4.c (usage): Update debugmode flag summary.
+	* doc/m4.texinfo (Defn): Update examples to match new behavior.
+	(Trace): Mention new capability of indir.
+	(Debug Levels): Enhance text for 'c' and 'x', update examples.
+	(Incompatibilities): Mention risk of parsing trace output.
+	* examples/null.m4: Enhance test.
+	* examples/null.err: Update expected output.
+	* NEWS: Mention these changes.
+	Reported by Akim Demaille in the autoconf TODO file in 2000.
+
 2008-05-07  Eric Blake  <[email protected]>
 
 	Fix traceon regression introduced 2006-06-06.
diff --git a/NEWS b/NEWS
index 9bde89c..bdb7665 100644
--- a/NEWS
+++ b/NEWS
@@ -41,6 +41,19 @@ Foundation, Inc.
    To simulate 1.4.x behavior, use:
      pushdef(`defn', `ifdef(`$1', `builtin(`defn', `$1')')')
 
+** Enhance the `indir' builtin to trace indirect macros, where the trace
+   is requested via `traceon' or the command-line option `-t'.  Previously,
+   it was impossible to trace macro names such as `foo-bar' which could
+   only be invoked indirectly, without relying on global tracing (such as
+   with `debugmode(`t')') or the experimental `changeword'.
+
+** Aspects of tracing output that were previously undocumented have been
+   slightly altered, and the effect of the builtin `debugmode' on trace
+   output is more fully documented.  As POSIX does not specify trace output
+   format, parsing such output is inherently fragile in the first place.
+   The intent is that future M4 versions will not change documented trace
+   output without adding additional `debugmode' flags.
+
 ** 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 30db58a..3131e9a 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -2300,7 +2300,7 @@ defn(`a', `divnum', `a')
 define(`mydivnum', defn(`divnum', `divnum'))mydivnum
 @error{}m4trace: -2- defn(`divnum', `divnum') -> `<divnum><divnum>'
 @error{}m4:stdin:5: Warning: define: cannot concatenate builtins
-@error{}m4trace: -1- define(`mydivnum', `<divnum><divnum>')
+@error{}m4trace: -1- define(`mydivnum', `<divnum><divnum>') -> `'
 @result{}
 traceoff(`defn', `define')dumpdef(`mydivnum')
 @error{}mydivnum:@tabchar{}`'
@@ -3711,10 +3711,10 @@ $ @kbd{m4 -d}
 traceon(`traceon')
 @result{}
 traceon(`traceoff')
-@error{}m4trace: -1- traceon(`traceoff')
+@error{}m4trace: -1- traceon(`traceoff') -> `'
 @result{}
 traceoff(`traceoff')
-@error{}m4trace: -1- traceoff(`traceoff')
+@error{}m4trace: -1- traceoff(`traceoff') -> `'
 @result{}
 traceoff(`traceon')
 @result{}
@@ -3733,7 +3733,56 @@ m4_eval(m4_divnum)
 @end example
 
 @xref{Debug Levels}, for information on controlling the details of the
-display.
+display.  The format of the trace output is not specified by
+@acronym{POSIX}, and varies between implementations of @code{m4}.
+
+Starting with M4 1.6, tracing also works via @code{indir}
+(@pxref{Indir}).  However, since tracing is an attribute tracked by
+macro names, and @code{builtin} bypasses macro names (@pxref{Builtin}),
+it is not possible for @code{builtin} to trace which subsidiary builtin
+it invokes.  If you are worried about tracking all invocations of a
+given builtin, you should also trace @code{builtin}, or enable global
+tracing (the @samp{t} debug level, @pxref{Debug Levels}).
+
+@example
+$ @kbd{m4 -d}
+define(`my_defn', defn(`defn'))undefine(`defn')
+@result{}
+define(`foo', `bar')traceon(`foo', `defn', `my_defn')
+@result{}
+foo
+@error{}m4trace: -1- foo -> `bar'
+@result{}bar
+indir(`foo')
+@error{}m4trace: -1- foo -> `bar'
+@result{}bar
+my_defn(`foo')
+@error{}m4trace: -1- my_defn(`foo') -> ``bar''
+@result{}bar
+indir(`my_defn', `foo')
+@error{}m4trace: -1- my_defn(`foo') -> ``bar''
+@result{}bar
+builtin(`defn', `foo')
+@result{}bar
+debugmode(`+cxt')
+@result{}
+builtin(`defn', builtin(`shift', `', `foo'))
+@error{}m4trace: -1- id 12: builtin ...
+@error{}m4trace: -2- id 13: builtin ...
+@error{}m4trace: -2- id 13: builtin(`shift', `', `foo') -> ``foo''
+@error{}m4trace: -1- id 12: builtin(`defn', `foo') -> ``bar''
+@result{}bar
+indir(`my_defn', indir(`shift', `', `foo'))
+@error{}m4trace: -1- id 14: indir ...
+@error{}m4trace: -2- id 15: indir ...
+@error{}m4trace: -2- id 15: shift ...
+@error{}m4trace: -2- id 15: shift(`', `foo') -> ``foo''
+@error{}m4trace: -2- id 15: indir(`shift', `', `foo') -> ``foo''
+@error{}m4trace: -1- id 14: my_defn ...
+@error{}m4trace: -1- id 14: my_defn(`foo') -> ``bar''
+@error{}m4trace: -1- id 14: indir(`my_defn', `foo') -> ``bar''
+@result{}bar
+@end example
 
 @node Debug Levels
 @section Controlling debugging output
@@ -3761,11 +3810,14 @@ flag is used, otherwise only the macros covered by calls of
 @code{traceon}.  Arguments are subject to length truncation specified by
 the command line option @option{--arglength} (or @option{-l}).
 
+@comment FIXME - is it worth adding @item b, which turns on backslash
+@comment escaping of all trace output, to guarantee single-line traces?
+
 @item c
-In trace output, show several trace lines for each macro call.  A line
-is shown when the macro is seen, but before the arguments are collected;
-a second line when the arguments have been collected and a third line
-after the call has completed.
+In trace output, show an additional trace line for each macro call, when
+the macro is seen, but before the arguments are collected.  By default,
+only one line is printed, after all arguments are collected and the
+expansion determined.  This is often used with the @samp{x} flag.
 
 @item e
 In trace output, show the expansion of each macro call, if it is not
@@ -3802,7 +3854,11 @@ In trace output, trace all macro calls made in this invocation of
 
 @item x
 In trace output, add a unique `macro call id' to each line of the trace
-output.  This is useful in connection with the @samp{c} flag above.
+output.  This is useful in connection with the @samp{c} flag above, to
+match where a macro is first recognized with where it is finally
+expanded, in spite of intermediate expansions that occur while
+collecting arguments.  It can also be used in isolation to determine how
+many macros have been expanded.
 
 @item V
 A shorthand for all of the above flags.
@@ -3840,17 +3896,18 @@ 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'
+debugmode(`V')debugmode(`-q')
+@error{}m4trace:stdin:5: -1- id 6: debugmode ...
+@error{}m4trace:stdin:5: -1- id 6: debugmode(`-q') -> `'
+@result{}
+foo(
+`ignored')
+@error{}m4trace:stdin:6: -1- id 7: foo ...
+@error{}m4trace:stdin:6: -1- id 7: foo(ignored) -> FOO
 @result{}FOO
 debugmode
-@error{}m4trace:stdin:7: -1- id 7: debugmode ...
-@error{}m4trace:stdin:7: -1- id 7: debugmode -> ???
-@error{}
+@error{}m4trace:stdin:8: -1- id 8: debugmode ...
+@error{}m4trace:stdin:8: -1- id 8: debugmode ->@w{ }
 @result{}
 foo
 @error{}m4trace: -1- foo
@@ -3858,7 +3915,7 @@ foo
 debugmode(`+l')
 @result{}
 foo
-@error{}m4trace:10: -1- foo
+@error{}m4trace:11: -1- foo
 @result{}FOO
 @end example
 
@@ -3867,17 +3924,17 @@ when specified on the command line.  Note that each argument and the
 final result are individually truncated.  Also, the special tokens for
 builtin functions are not truncated.
 
-@comment options: -l6
+@comment options: -l6 -tdefn -techo
 @example
-$ @kbd{m4 -d -l 6}
-define(`echo', `$@@')debugmode(`+t')
+$ @kbd{m4 -d -l 6 -t defn -t echo}
+define(`echo', `$@@')
 @result{}
 echo(`1', `long string')
 @error{}m4trace: -1- echo(`1', `long s...') -> ``1',`l...'
 @result{}1,long string
 indir(`echo', defn(`changequote'))
 @error{}m4trace: -2- defn(`change...') -> `<changequote>'
-@error{}m4trace: -1- indir(`echo', <changequote>) -> ``<changequote>''
+@error{}m4trace: -1- echo(<changequote>) -> ``<changequote>''
 @result{}
 @end example
 
@@ -7277,6 +7334,13 @@ also traced by name; and tracing by name, such as with @option{-tfoo} at
 the command line or @code{traceon(`foo')} in the input, is an attribute
 that is preserved even if the macro is currently undefined.
 
+Additionally, while @acronym{POSIX} requires trace output, it makes no
+demands on the formatting of that output.  Parsing trace output is not
+guaranteed to be reliable, even between different releases of
+@acronym{GNU} M4; however, the intent is that any future changes in
+trace output will only occur under the direction of additional
+@code{debugmode} flags (@pxref{Debug Levels}).
+
 @item
 @acronym{POSIX} requires @code{eval} (@pxref{Eval}) to treat all
 operators with the same precedence as C@.  However, earlier versions of
diff --git a/examples/null.err b/examples/null.err
index 61518e8..d825818 100644
Binary files a/examples/null.err and b/examples/null.err differ
diff --git a/examples/null.m4 b/examples/null.m4
index 7cf123f..10d15ae 100644
Binary files a/examples/null.m4 and b/examples/null.m4 differ
diff --git a/src/builtin.c b/src/builtin.c
index 0549745..830d4a2 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -943,7 +943,7 @@ m4_builtin (struct obstack *obs, int argc, macro_arguments *argv)
   else
     {
       macro_arguments *new_argv = make_argv_ref (argv, name, ARG_LEN (1),
-						 true, !bp->groks_macro_args);
+						 !bp->groks_macro_args, false);
       bp->func (obs, argc - 1, new_argv);
     }
 }
@@ -977,8 +977,10 @@ m4_indir (struct obstack *obs, int argc, macro_arguments *argv)
   else
     {
       macro_arguments *new_argv = make_argv_ref (argv, name, ARG_LEN (1),
-						 true, !SYMBOL_MACRO_ARGS (s));
-      call_macro (s, argc - 1, new_argv, obs);
+						 !SYMBOL_MACRO_ARGS (s),
+						 SYMBOL_TRACED (s));
+      trace_prepre (arg_info (new_argv));
+      call_macro (s, new_argv, obs);
     }
 }
 
diff --git a/src/debug.c b/src/debug.c
index fde6c49..0298fc8 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -33,7 +33,7 @@ static struct obstack trace;
 static void debug_set_file (const char *, FILE *);
 
 /*----------------------------------.
-| Initialise the debugging module.  |
+| Initialize the debugging module.  |
 `----------------------------------*/
 
 void
@@ -113,11 +113,12 @@ debug_decode (const char *opts)
   return level;
 }
 
-/*------------------------------------------------------------------------.
-| Change the debug output stream to FP.  If the underlying file is the	  |
-| same as stdout, use stdout instead so that debug messages appear in the |
-| correct relative position.						  |
-`------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------.
+| Change the debug output stream to FP.  If the underlying file is |
+| the same as stdout, use stdout instead so that debug messages    |
+| appear in the correct relative position.  Report any failure on  |
+| behalf of CALLER.                                                |
+`-----------------------------------------------------------------*/
 
 static void
 debug_set_file (const char *caller, FILE *fp)
@@ -210,7 +211,7 @@ debug_set_output (const char *caller, const char *name)
 }
 
 /*-----------------------------------------------------------------------.
-| Print the header of a one-line debug message, starting by "m4 debug".	 |
+| Print the header of a one-line debug message, starting by "m4debug:".	 |
 `-----------------------------------------------------------------------*/
 
 void
@@ -235,10 +236,8 @@ debug_message_prefix (void)
 
 /*-------------------------------------------------------------------.
 | Tracing output to the obstack is formatted here, by a simplified   |
-| printf-like function trace_format ().  Understands only %B (1 arg: |
-| input block), %S (1 arg: length-limited text), %s (1 arg: text),   |
-| %d (1 arg: integer), %l (0 args: optional left quote) and %r (0    |
-| args: optional right quote).                                       |
+| printf-like function trace_format ().  Understands only %s (1 arg: |
+| text), %d (1 arg: integer).                                        |
 `-------------------------------------------------------------------*/
 
 static void
@@ -263,27 +262,10 @@ trace_format (const char *fmt, ...)
       maxlen = SIZE_MAX;
       switch (*fmt++)
 	{
-	case 'B':
-	  s = "";
-	  input_print (&trace, va_arg (args, input_block *));
-	  break;
-
-	case 'S':
-	  maxlen = max_debug_argument_length;
-	  /* fall through */
-
 	case 's':
 	  s = va_arg (args, const char *);
 	  break;
 
-	case 'l':
-	  s = (debug_level & DEBUG_TRACE_QUOTE) ? curr_quote.str1 : "";
-	  break;
-
-	case 'r':
-	  s = (debug_level & DEBUG_TRACE_QUOTE) ? curr_quote.str2 : "";
-	  break;
-
 	case 'd':
 	  d = va_arg (args, int);
 	  s = ntoa (d, 10);
@@ -302,102 +284,106 @@ trace_format (const char *fmt, ...)
 }
 
 /*------------------------------------------------------------------.
-| Format the standard header attached to all tracing output lines.  |
-| ID is the current macro id.                                       |
+| Format the standard header attached to all tracing output lines,  |
+| using the context in INFO as appropriate.  Return the offset into |
+| the trace obstack where this particular trace begins.             |
 `------------------------------------------------------------------*/
 
-static void
-trace_header (int id)
+static unsigned int
+trace_header (const call_info *info)
 {
+  int trace_level = info->debug_level;
+  unsigned int result = obstack_object_size (&trace);
   trace_format ("m4trace:");
-  if (current_line)
-    {
-      if (debug_level & DEBUG_TRACE_FILE)
-	trace_format ("%s:", current_file);
-      if (debug_level & DEBUG_TRACE_LINE)
-	trace_format ("%d:", current_line);
-    }
+  if (trace_level & DEBUG_TRACE_FILE)
+    trace_format ("%s:", info->file);
+  if (trace_level & DEBUG_TRACE_LINE)
+    trace_format ("%d:", info->line);
   trace_format (" -%d- ", expansion_level);
-  if (debug_level & DEBUG_TRACE_CALLID)
-    trace_format ("id %d: ", id);
+  if (trace_level & DEBUG_TRACE_CALLID)
+    trace_format ("id %d: ", info->call_id);
+  return result;
 }
 
-/*----------------------------------------------------.
-| Print current tracing line, and clear the obstack.  |
-`----------------------------------------------------*/
+/*-----------------------------------------------------------------.
+| Print current tracing line starting at offset START, as returned |
+| from an earlier trace_header(), then clear the obstack.          |
+`-----------------------------------------------------------------*/
 
 static void
-trace_flush (void)
+trace_flush (unsigned int start)
 {
   char *line;
 
   obstack_1grow (&trace, '\0');
-  line = (char *) obstack_finish (&trace);
-  DEBUG_PRINT1 ("%s\n", line);
-  obstack_free (&trace, line);
+  line = (char *) obstack_base (&trace);
+  DEBUG_PRINT1 ("%s\n", &line[start]);
+  start -= obstack_object_size (&trace);
+  obstack_blank (&trace, start);
 }
 
-/*----------------------------------------------------------------.
-| Do pre-argument-collection tracing for macro NAME, with a given |
-| ID.  Used from expand_macro ().                                 |
-`----------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| Do pre-argument-collection tracing for the macro call described in |
+| INFO.  Used from expand_macro ().                                  |
+`-------------------------------------------------------------------*/
 
 void
-trace_prepre (const char *name, int id)
+trace_prepre (const call_info *info)
 {
-  trace_header (id);
-  trace_format ("%s ...", name);
-  trace_flush ();
+  if (info->trace && (info->debug_level & DEBUG_TRACE_CALL))
+    {
+      unsigned int start = trace_header (info);
+      trace_format ("%s ...", info->name);
+      trace_flush (start);
+    }
 }
 
-/*-----------------------------------------------------------------.
-| Format the parts of a trace line that are known before the macro |
-| is actually expanded.  Called for the macro NAME with ID, and    |
-| arguments ARGV.  Used from expand_macro ().                      |
-`-----------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| Format the parts of a trace line that are known via ARGV before   |
+| the macro is actually expanded.  Used from call_macro ().  Return |
+| the start of the current trace, in case other traces are printed  |
+| before this trace completes trace_post.                           |
+`------------------------------------------------------------------*/
 
-void
-trace_pre (const char *name, int id, macro_arguments *argv)
+unsigned int
+trace_pre (macro_arguments *argv)
 {
-  trace_header (id);
-  trace_format ("%s", name);
+  const call_info *info = arg_info (argv);
+  int trace_level = info->debug_level;
+  unsigned int start = trace_header (info);
 
-  if (arg_argc (argv) > 1 && (debug_level & DEBUG_TRACE_ARGS))
+  assert (info->trace);
+  trace_format ("%s", info->name);
+  if (1 < arg_argc (argv) && (trace_level & DEBUG_TRACE_ARGS))
     {
       size_t len = max_debug_argument_length;
-      trace_format ("(");
+      obstack_1grow (&trace, '(');
       arg_print (&trace, argv, 1,
-		 (debug_level & DEBUG_TRACE_QUOTE) ? &curr_quote : NULL,
+		 (trace_level & DEBUG_TRACE_QUOTE) ? &curr_quote : NULL,
 		 false, NULL, ", ", &len, true);
-      trace_format (")");
-    }
-
-  if (debug_level & DEBUG_TRACE_CALL)
-    {
-      trace_format (" -> ???");
-      trace_flush ();
+      obstack_1grow (&trace, ')');
     }
+  return start;
 }
 
-/*-------------------------------------------------------------------.
-| Format the final part of a trace line and print it all.  Print     |
-| details for macro NAME with ID, given arguemnts ARGV and expansion |
-| EXPANDED.  Used from expand_macro ().                              |
-`-------------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| If requested by the trace state in INFO, format the final part of |
+| a trace line.  Then print all collected information from START,   |
+| returned from a prior trace_pre().  Used from call_macro ().      |
+`------------------------------------------------------------------*/
 
 void
-trace_post (const char *name, int id, macro_arguments *argv,
-	    const input_block *expanded)
+trace_post (unsigned int start, const call_info *info)
 {
-  int argc = arg_argc (argv);
-
-  if (debug_level & DEBUG_TRACE_CALL)
+  assert (info->trace);
+  if (info->debug_level & DEBUG_TRACE_EXPANSION)
     {
-      trace_header (id);
-      trace_format ("%s%s", name, (argc > 1) ? "(...)" : "");
+      obstack_grow (&trace, " -> ", 4);
+      if (info->debug_level & DEBUG_TRACE_QUOTE)
+	obstack_grow (&trace, curr_quote.str1, curr_quote.len1);
+      input_print (&trace);
+      if (info->debug_level & DEBUG_TRACE_QUOTE)
+	obstack_grow (&trace, curr_quote.str2, curr_quote.len2);
     }
-
-  if (expanded && (debug_level & DEBUG_TRACE_EXPANSION))
-    trace_format (" -> %l%B%r", expanded);
-  trace_flush ();
+  trace_flush (start);
 }
diff --git a/src/input.c b/src/input.c
index df5a791..c1f609b 100644
--- a/src/input.c
+++ b/src/input.c
@@ -80,6 +80,8 @@ enum input_type
 
 typedef enum input_type input_type;
 
+typedef struct input_block input_block;
+
 /* A block of input to be scanned.  */
 struct input_block
 {
@@ -331,6 +333,7 @@ push_string_init (void)
   next->type = INPUT_STRING;
   next->file = current_file;
   next->line = current_line;
+  next->u.u_s.len = 0;
 
   return current_input;
 }
@@ -500,26 +503,20 @@ push_token (token_data *token, int level, bool inuse)
 }
 
 /*-------------------------------------------------------------------.
-| Last half of push_string ().  If next is now NULL, a call to       |
-| push_file () or push_macro () has invalidated the previous call to |
-| push_string_init (), so we just give up.  If the new object is     |
-| void, we do not push it.  The function push_string_finish ()       |
-| returns an opaque pointer to the finished object, which can then   |
-| be printed with input_print when tracing is enabled.  This pointer |
-| is only for temporary use, since reading the next token will       |
-| invalidate the object.                                             |
+| Last half of push_string ().  All remaining unfinished text on the |
+| obstack returned from push_string_init is collected into the input |
+| stack.                                                             |
 `-------------------------------------------------------------------*/
 
-const input_block *
+void
 push_string_finish (void)
 {
-  input_block *ret = NULL;
   size_t len = obstack_object_size (current_input);
 
   if (next == NULL)
     {
       assert (!len);
-      return NULL;
+      return;
     }
 
   if (len || next->type == INPUT_CHAIN)
@@ -534,12 +531,10 @@ push_string_finish (void)
       next->prev = isp;
       isp = next;
       input_change = true;
-      ret = isp;
     }
   else
     obstack_free (current_input, next);
   next = NULL;
-  return ret;
 }
 
 /*--------------------------------------------------------------.
@@ -735,24 +730,30 @@ pop_wrapup (void)
 | tracing.                                                      |
 `--------------------------------------------------------------*/
 void
-input_print (struct obstack *obs, const input_block *input)
+input_print (struct obstack *obs)
 {
+  size_t len = obstack_object_size (current_input);
   size_t maxlen = max_debug_argument_length;
   token_chain *chain;
 
-  assert (input);
-  switch (input->type)
+  if (!next)
+    {
+      assert (!len);
+      return;
+    }
+  switch (next->type)
     {
     case INPUT_STRING:
-      shipout_string_trunc (obs, input->u.u_s.str, input->u.u_s.len, &maxlen);
+      assert (!next->u.u_s.len);
       break;
     case INPUT_FILE:
+      assert (!len);
       obstack_grow (obs, "<file: ", strlen ("<file: "));
-      obstack_grow (obs, input->file, strlen (input->file));
+      obstack_grow (obs, next->file, strlen (next->file));
       obstack_1grow (obs, '>');
       break;
     case INPUT_CHAIN:
-      chain = input->u.u_c.chain;
+      chain = next->u.u_c.chain;
       while (chain)
 	{
 	  switch (chain->type)
@@ -785,6 +786,9 @@ input_print (struct obstack *obs, const input_block *input)
       assert (!"input_print");
       abort ();
     }
+  if (len)
+    shipout_string_trunc (obs, (char *) obstack_base (current_input), len,
+			  &maxlen);
 }
 
 
diff --git a/src/m4.c b/src/m4.c
index 2ad82c2..84cb8e0 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -238,24 +238,25 @@ static void
 usage (int status)
 {
   if (status != EXIT_SUCCESS)
-    xfprintf (stderr, "Try `%s --help' for more information.\n", program_name);
+    xfprintf (stderr, _("Try `%s --help' for more information.\n"),
+              program_name);
   else
     {
-      xprintf ("Usage: %s [OPTION]... [FILE]...\n", program_name);
-      fputs ("\
+      xprintf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
+      fputs (_("\
 Process macros in FILEs.  If no FILE or if FILE is `-', standard input\n\
 is read.\n\
-", stdout);
-      fputs ("\
-\n\
+"), stdout);
+      puts ("");
+      fputs (_("\
 Mandatory or optional arguments to long options are mandatory or optional\n\
 for short options too.\n\
 \n\
 Operation modes:\n\
       --help                   display this help and exit\n\
       --version                output version information and exit\n\
-", stdout);
-      xprintf ("\
+"), stdout);
+      xprintf (_("\
   -E, --fatal-warnings         once: warnings become errors, twice: stop\n\
                                execution at first error\n\
   -i, --interactive            unbuffer output, ignore interrupts\n\
@@ -264,67 +265,75 @@ Operation modes:\n\
       --warn-macro-sequence[=REGEXP]\n\
                                warn if macro definition matches REGEXP,\n\
                                default %s\n\
-", DEFAULT_MACRO_SEQUENCE);
+"), DEFAULT_MACRO_SEQUENCE);
 #ifdef ENABLE_CHANGEWORD
-      fputs ("\
+      fputs (_("\
   -W, --word-regexp=REGEXP     use REGEXP for macro name syntax\n\
-", stdout);
+"), stdout);
 #endif
-      fputs ("\
-\n\
+      puts ("");
+      fputs (_("\
 Preprocessor features:\n\
   -D, --define=NAME[=VALUE]    define NAME as having VALUE, or empty\n\
   -I, --include=DIRECTORY      append DIRECTORY to include path\n\
   -s, --synclines              generate `#line NUM \"FILE\"' lines\n\
   -U, --undefine=NAME          undefine NAME\n\
-", stdout);
-      fputs ("\
-\n\
+"), stdout);
+      puts ("");
+      fputs (_("\
 Limits control:\n\
   -G, --traditional            suppress all GNU extensions\n\
   -H, --hashsize=PRIME         set symbol lookup hash table size [509]\n\
   -L, --nesting-limit=NUMBER   change artificial nesting limit [1024]\n\
-", stdout);
-      fputs ("\
-\n\
+"), stdout);
+      puts ("");
+      fputs (_("\
 Frozen state files:\n\
   -F, --freeze-state=FILE      produce a frozen state on FILE at end\n\
   -R, --reload-state=FILE      reload a frozen state from FILE at start\n\
-", stdout);
-      fputs ("\
-\n\
+"), stdout);
+      puts ("");
+      fputs (_("\
 Debugging:\n\
   -d, --debug[=FLAGS]          set debug level (no FLAGS implies `aeq')\n\
       --debugfile=FILE         redirect debug and trace output\n\
   -l, --arglength=NUM          restrict macro tracing size\n\
   -t, --trace=NAME             trace NAME when it is defined\n\
-", stdout);
-      fputs ("\
-\n\
+"), stdout);
+      puts ("");
+      fputs (_("\
 FLAGS is any of:\n\
-  a   show actual arguments\n\
-  c   show before collect, after collect and after call\n\
-  e   show expansion\n\
-  f   say current input file name\n\
-  i   show changes in input files\n\
-  l   say current input line number\n\
-  p   show results of path searches\n\
-  q   quote values as necessary, with a or e flag\n\
-  t   trace for all macro calls, not only traceon'ed\n\
-  x   add a unique macro call id, useful with c flag\n\
+  a   show actual arguments in trace\n\
+  c   show collection line in trace\n\
+  e   show expansion in trace\n\
+  f   include current input file name in trace and debug\n\
+  i   show changes in input files in debug\n\
+  l   include current input line number in trace and debug\n\
+"), stdout);
+      fputs (_("\
+  p   show results of path searches in debug\n\
+  q   quote values in dumpdef and trace, useful with a or e\n\
+  t   trace all macro calls, regardless of per-macro traceon state\n\
+  x   include unique macro call id in trace, useful with c\n\
   V   shorthand for all of the above flags\n\
-", stdout);
-      fputs ("\
-\n\
+"), stdout);
+      puts ("");
+      fputs (_("\
 If defined, the environment variable `M4PATH' is a colon-separated list\n\
 of directories included after any specified by `-I'.\n\
-", stdout);
-      fputs ("\
-\n\
+"), stdout);
+      puts ("");
+      fputs (_("\
 Exit status is 0 for success, 1 for failure, 63 for frozen file version\n\
 mismatch, or whatever value was passed to the m4exit macro.\n\
-", stdout);
-      xprintf ("\nReport bugs to <%s>.\n", PACKAGE_BUGREPORT);
+"), stdout);
+      puts ("");
+      /* TRANSLATORS: the placeholder indicates the bug-reporting
+	 address for this application.  Please add _another line_
+	 saying "Report translation bugs to <...>\n" with the address
+	 for translation bugs (typically your translation team's web
+	 or email address).  */
+      xprintf (_("Report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     }
   exit (status);
 }
diff --git a/src/m4.h b/src/m4.h
index b3cb7e1..b2e55e5 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -96,7 +96,6 @@ typedef struct string_pair string_pair;
 #define obstack_chunk_free	free
 
 /* These must come first.  */
-typedef struct input_block input_block;
 typedef struct token_data token_data;
 typedef struct macro_arguments macro_arguments;
 typedef void builtin_func (struct obstack *, int, macro_arguments *);
@@ -139,6 +138,21 @@ extern const char *user_word_regexp;	/* -W */
 #endif
 
 /* Error handling.  */
+
+/* A structure containing context that was valid when a macro call
+   started collecting arguments; used for tracing and error messages
+   even when the global context changes in the meantime.  */
+struct call_info
+{
+  const char *file;	/* The file containing the macro invocation.  */
+  int line;		/* The line the macro was called on.  */
+  int call_id;		/* The unique sequence call id of the macro.  */
+  int trace : 1;	/* True to trace this macro.  */
+  int debug_level : 31;	/* The debug level for tracing the macro call.  */
+  const char *name;	/* The macro name.  */
+};
+typedef struct call_info call_info;
+
 extern int retcode;
 extern const char *program_name;
 
@@ -245,10 +259,9 @@ void debug_flush_files (void);
 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, macro_arguments *);
-void trace_post (const char *, int, macro_arguments *,
-		 const input_block *);
+void trace_prepre (const call_info *);
+unsigned int trace_pre (macro_arguments *);
+void trace_post (unsigned int, const call_info *);
 
 
 /* File: input.c  --- lexical definitions.  */
@@ -398,11 +411,11 @@ void append_macro (struct obstack *, builtin_func *, token_chain **,
 void push_macro (struct obstack *, builtin_func *);
 struct obstack *push_string_init (void);
 bool push_token (token_data *, int, bool);
-const input_block *push_string_finish (void);
+void push_string_finish (void);
 struct obstack *push_wrapup_init (token_chain ***);
 void push_wrapup_finish (void);
 bool pop_wrapup (void);
-void input_print (struct obstack *, const input_block *);
+void input_print (struct obstack *);
 
 /* current input file, and line */
 extern const char *current_file;
@@ -498,11 +511,12 @@ void hack_all_symbols (hack_symbol *, void *);
 extern int expansion_level;
 
 void expand_input (void);
-void call_macro (symbol *, int, macro_arguments *, struct obstack *);
+void call_macro (symbol *, macro_arguments *, struct obstack *);
 size_t adjust_refcount (int, bool);
 
 bool arg_adjust_refcount (macro_arguments *, bool);
 unsigned int arg_argc (macro_arguments *);
+const call_info *arg_info (macro_arguments *);
 token_data_type arg_type (macro_arguments *, unsigned int);
 const char *arg_text (macro_arguments *, unsigned int, bool);
 bool arg_equal (macro_arguments *, unsigned int, unsigned int);
diff --git a/src/macro.c b/src/macro.c
index 8290818..2a5b52a 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -59,6 +59,9 @@ struct macro_arguments
      object, or 0 if quote_age changed during parsing or if any of the
      arguments might contain content that can affect rescan.  */
   unsigned int quote_age;
+  /* The context of this macro call during expansion, and NULL in a
+     back-reference.  */
+  call_info *info;
   int level; /* Which obstack owns this argv.  */
   unsigned int arraylen; /* True length of allocated elements in array.  */
   /* Used as a variable-length array, storing information about each
@@ -176,7 +179,7 @@ static size_t stacks_count;
 int expansion_level = 0;
 
 /* The number of the current call of expand_macro ().  */
-static int macro_call_id = 0;
+static int macro_call_id;
 
 /* The empty string token.  */
 static token_data empty_token;
@@ -476,7 +479,7 @@ expand_argument (struct obstack *obs, token_data *argp, const char *caller)
 `-------------------------------------------------------------------------*/
 
 static macro_arguments *
-collect_arguments (symbol *sym, struct obstack *arguments,
+collect_arguments (symbol *sym, call_info *info, struct obstack *arguments,
 		   struct obstack *argv_stack)
 {
   token_data td;
@@ -495,6 +498,7 @@ collect_arguments (symbol *sym, struct obstack *arguments,
   args.argv0 = SYMBOL_NAME (sym);
   args.argv0_len = strlen (args.argv0);
   args.quote_age = quote_age ();
+  args.info = info;
   args.level = expansion_level - 1;
   args.arraylen = 0;
   obstack_grow (argv_stack, &args, offsetof (macro_arguments, array));
@@ -564,31 +568,37 @@ collect_arguments (symbol *sym, struct obstack *arguments,
 }
 
 
-/*-----------------------------------------------------------------.
-| Call the macro SYM, which is either a builtin function or a user |
-| macro (via the expansion function expand_user_macro () in        |
-| builtin.c).  There are ARGC arguments to the call, stored in the |
-| ARGV table.  The expansion is left on the obstack EXPANSION.     |
-`-----------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| Call the macro SYM, which is either a builtin function or a user   |
+| macro (via the expansion function expand_user_macro () in          |
+| builtin.c).  The arguments are provided by ARGV.  The expansion is |
+| left on the obstack EXPANSION.  Macro tracing is also handled      |
+| here.                                                              |
+`-------------------------------------------------------------------*/
 
 void
-call_macro (symbol *sym, int argc, macro_arguments *argv,
-	    struct obstack *expansion)
+call_macro (symbol *sym, macro_arguments *argv, struct obstack *expansion)
 {
+  unsigned int trace_start = 0;
+
+  if (argv->info->trace)
+    trace_start = trace_pre (argv);
   switch (SYMBOL_TYPE (sym))
     {
     case TOKEN_FUNC:
-      SYMBOL_FUNC (sym) (expansion, argc, argv);
+      SYMBOL_FUNC (sym) (expansion, argv->argc, argv);
       break;
 
     case TOKEN_TEXT:
-      expand_user_macro (expansion, sym, argc, argv);
+      expand_user_macro (expansion, sym, argv->argc, argv);
       break;
 
     default:
       assert (!"call_macro");
       abort ();
     }
+  if (argv->info->trace)
+    trace_post (trace_start, argv->info);
 }
 
 /*-------------------------------------------------------------------------.
@@ -609,19 +619,10 @@ expand_macro (symbol *sym)
   void *argv_base;		/* Base of stacks[i].argv on entry.  */
   macro_arguments *argv;	/* Arguments to the called macro.  */
   struct obstack *expansion;	/* Collects the macro's expansion.  */
-  const input_block *expanded;	/* The resulting expansion, for tracing.  */
-  bool traced;			/* True if this macro is traced.  */
-  int my_call_id;		/* Sequence id for this macro.  */
   int level = expansion_level;	/* Expansion level of this macro.  */
+  call_info my_call_info;	/* Context of this macro.  */
 
-  /* Report errors at the location where the open parenthesis (if any)
-     was found, but after expansion, restore global state back to the
-     location of the close parenthesis.  This is safe since we
-     guarantee that macro expansion does not alter the state of
-     current_file/current_line (dnl, include, and sinclude are special
-     cased in the input engine to ensure this fact).  */
-  const char *loc_open_file = current_file;
-  int loc_open_line = current_line;
+  /* TODO - make m4_warn use optional call_info, so we don't need these.  */
   const char *loc_close_file;
   int loc_close_line;
 
@@ -661,35 +662,37 @@ expand_macro (symbol *sym)
 	      _("recursion limit of %d exceeded, use -L<N> to change it"),
 	      nesting_limit);
 
-  macro_call_id++;
-  my_call_id = macro_call_id;
-
-  traced = (debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym);
-  if (traced && (debug_level & DEBUG_TRACE_CALL))
-    trace_prepre (SYMBOL_NAME (sym), my_call_id);
-
-  argv = collect_arguments (sym, stacks[level].args, stacks[level].argv);
+  /* Collect context in effect at start of macro, even if global state
+     changes in the meantime.  */
+  my_call_info.file = current_file;
+  my_call_info.line = current_line;
+  my_call_info.call_id = ++macro_call_id;
+  my_call_info.trace = (debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym);
+  my_call_info.debug_level = debug_level;
+  my_call_info.name = SYMBOL_NAME (sym);
+  trace_prepre (&my_call_info);
+
+  /* Collect the arguments.  */
+  argv = collect_arguments (sym, &my_call_info, stacks[level].args,
+			    stacks[level].argv);
   args_scratch = obstack_finish (stacks[level].args);
 
-  /* The actual macro call.  */
+  /*  Temporarily reset the location so that error messages are
+      tracked to the macro name.  */
   loc_close_file = current_file;
   loc_close_line = current_line;
-  current_file = loc_open_file;
-  current_line = loc_open_line;
-
-  if (traced)
-    trace_pre (SYMBOL_NAME (sym), my_call_id, argv);
+  current_file = my_call_info.file;
+  current_line = my_call_info.line;
 
+  /* The actual macro call.  */
   expansion = push_string_init ();
-  call_macro (sym, argv->argc, argv, expansion);
-  expanded = push_string_finish ();
-
-  if (traced)
-    trace_post (SYMBOL_NAME (sym), my_call_id, argv, expanded);
+  call_macro (sym, argv, expansion);
+  push_string_finish ();
 
   /* Cleanup.  */
   current_file = loc_close_file;
   current_line = loc_close_line;
+  argv->info = NULL;
 
   --expansion_level;
   --SYMBOL_PENDING_EXPANSIONS (sym);
@@ -710,8 +713,9 @@ expand_macro (symbol *sym)
 	  obstack_free (stacks[level].args, args_scratch);
 	  if (debug_macro_level & PRINT_ARGCOUNT_CHANGES)
 	    xfprintf (debug, "m4debug: -%d- `%s' in use, level=%d, "
-		      "refcount=%zu, argcount=%zu\n", my_call_id, argv->argv0,
-		      level, stacks[level].refcount, stacks[level].argcount);
+		      "refcount=%zu, argcount=%zu\n", my_call_info.call_id,
+		      argv->argv0, level, stacks[level].refcount,
+		      stacks[level].argcount);
 	}
       else
 	{
@@ -870,6 +874,16 @@ arg_argc (macro_arguments *argv)
   return argv->argc;
 }
 
+/* Given ARGV, return the call context in effect when argument
+   collection began.  Only safe to call while the macro is being
+   expanded.  */
+const call_info *
+arg_info (macro_arguments *argv)
+{
+  assert (argv->info);
+  return argv->info;
+}
+
 /* Given ARGV, return the type of argument ARG.  Arg 0 is always text,
    and indices beyond argc are likewise treated as text.  */
 token_data_type
@@ -1394,22 +1408,23 @@ make_argv_ref_token (token_data *token, struct obstack *obs, int level,
 /* Create a new argument object using the same obstack as ARGV; thus,
    the new object will automatically be freed when the original is
    freed.  Explicitly set the macro name (argv[0]) from ARGV0 with
-   length ARGV0_LEN.  If SKIP, set argv[1] of the new object to
-   argv[2] of the old, otherwise the objects share all arguments.  If
+   length ARGV0_LEN, and discard argv[1] of the wrapped ARGV.  If
    FLATTEN, any non-text in ARGV is flattened to an empty string when
-   referenced through the new object.  */
+   referenced through the new object.  If TRACE, then trace the macro,
+   regardless of global trace state.  */
 macro_arguments *
 make_argv_ref (macro_arguments *argv, const char *argv0, size_t argv0_len,
-	       bool skip, bool flatten)
+	       bool flatten, bool trace)
 {
   macro_arguments *new_argv;
   token_data *token;
   token_data *new_token;
-  unsigned int i = skip ? 2 : 1;
   struct obstack *obs = arg_scratch ();
+  call_info *info;
 
+  info = (call_info *) obstack_copy (obs, argv->info, sizeof *info);
   new_token = (token_data *) obstack_alloc (obs, sizeof *token);
-  token = make_argv_ref_token (new_token, obs, expansion_level - 1, argv, i,
+  token = make_argv_ref_token (new_token, obs, expansion_level - 1, argv, 2,
 			       flatten, NULL);
   if (!token)
     {
@@ -1433,11 +1448,14 @@ make_argv_ref (macro_arguments *argv, const char *argv0, size_t argv0_len,
       new_argv->flatten = flatten;
       new_argv->has_func = argv->has_func;
     }
-  new_argv->argc = argv->argc - (i - 1);
+  new_argv->argc = argv->argc - 1;
   new_argv->inuse = false;
   new_argv->argv0 = argv0;
   new_argv->argv0_len = argv0_len;
   new_argv->quote_age = argv->quote_age;
+  new_argv->info = info;
+  info->trace = (argv->info->debug_level & DEBUG_TRACE_ALL) || trace;
+  info->name = argv0;
   new_argv->level = argv->level;
   return new_argv;
 }


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.