m4-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, master, updated. cvs-readonly-110-gb9738ad
Date: Fri, 09 May 2008 03:12:23 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU M4 source repository".

http://git.sv.gnu.org/gitweb/?p=m4.git;a=commitdiff;h=b9738adbaaf9c8f02c97c6179b9e595a0d28121c

The branch, master has been updated
       via  b9738adbaaf9c8f02c97c6179b9e595a0d28121c (commit)
      from  d74cecd6377345903ba25c9d9b82729324fbbcf8 (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 b9738adbaaf9c8f02c97c6179b9e595a0d28121c
Author: Eric Blake <address@hidden>
Date:   Thu May 8 20:39:16 2008 -0600

    Stage 23: allow tracing of indirect macro calls.
    
    * m4/m4module.h (m4_input_block): Remove.
    (m4_call_info): New opaque type.
    (m4_trace_prepare, m4_arg_info): New prototypes.
    (m4_macro_call, m4_push_string_finish, m4_input_print): Change
    prototypes.
    * m4/m4private.h (struct m4_macro_args): Add info field.
    (struct m4_call_info): New structure.
    (m4_arg_info): New accessor.
    * m4/input.c (m4_input_block): Make typedef local.
    (m4_push_string_init): Initialize length.
    (m4_push_string_finish, m4_input_print): Change signature, so that
    printing can be done before finalization.
    (struct input_funcs): Add parameter to print_func.
    (file_print, string_print, composite_print): Adjust accordingly.
    * m4/macro.c (trace_header, trace_flush, trace_pre, trace_post):
    Change signatures for stacked trace messages, and for using call
    context.
    (trace_prepre): Export and rename...
    (m4_trace_prepare): ...to this, for use by indir.  Alter signature
    to use call context.
    (collect_arguments): Alter signature, to manage new field.
    (expand_macro): Change call context management.  Move tracing...
    (m4_macro_call): ...here.  Remove redundant parameter.
    (m4_arg_argc): New function.
    (m4_make_argv_ref): Replace unused skip parameter with new trace
    parameter; manage new field.
    * modules/gnu.c (builtin, indir): Adjust callers.
    * src/main.c (usage): Update debugmode flag summary.
    * tests/null.m4: Enhance test.
    * tests/null.err: Update expected output.
    * tests/macros.at (Tracing Hanoi Towers): Likewise.
    * doc/m4.texinfo (Trace): Mention more about trace formatting.
    (Debugmode): Enhance description of 'c' and 'x'.  Enhance test to
    cover line numbering details in traces.
    (Debuglen): Enhance test to cover indir tracing.
    * NEWS: Mention these changes.
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog       |   45 +++++++++
 NEWS            |   19 +++-
 doc/m4.texinfo  |   97 +++++++++++++++----
 m4/input.c      |   83 ++++++++--------
 m4/m4module.h   |   20 ++--
 m4/m4private.h  |   19 ++++
 m4/macro.c      |  288 +++++++++++++++++++++++++++++--------------------------
 modules/gnu.c   |   10 +-
 src/main.c      |    6 +-
 tests/macros.at |    2 +-
 tests/null.err  |  Bin 18 -> 51 bytes
 tests/null.m4   |  Bin 6607 -> 6605 bytes
 12 files changed, 373 insertions(+), 216 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2f39b0e..c20ac6e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+2008-05-08  Eric Blake  <address@hidden>
+
+       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.
+       * m4/m4module.h (m4_input_block): Remove.
+       (m4_call_info): New opaque type.
+       (m4_trace_prepare, m4_arg_info): New prototypes.
+       (m4_macro_call, m4_push_string_finish, m4_input_print): Change
+       prototypes.
+       * m4/m4private.h (struct m4_macro_args): Add info field.
+       (struct m4_call_info): New structure.
+       (m4_arg_info): New accessor.
+       * m4/input.c (m4_input_block): Make typedef local.
+       (m4_push_string_init): Initialize length.
+       (m4_push_string_finish, m4_input_print): Change signature, so that
+       printing can be done before finalization.
+       (struct input_funcs): Add parameter to print_func.
+       (file_print, string_print, composite_print): Adjust accordingly.
+       * m4/macro.c (trace_header, trace_flush, trace_pre, trace_post):
+       Change signatures for stacked trace messages, and for using call
+       context.
+       (trace_prepre): Export and rename...
+       (m4_trace_prepare): ...to this, for use by indir.  Alter signature
+       to use call context.
+       (collect_arguments): Alter signature, to manage new field.
+       (expand_macro): Change call context management.  Move tracing...
+       (m4_macro_call): ...here.  Remove redundant parameter.
+       (m4_arg_argc): New function.
+       (m4_make_argv_ref): Replace unused skip parameter with new trace
+       parameter; manage new field.
+       * modules/gnu.c (builtin, indir): Adjust callers.
+       * src/main.c (usage): Update debugmode flag summary.
+       * tests/null.m4: Enhance test.
+       * tests/null.err: Update expected output.
+       * tests/macros.at (Tracing Hanoi Towers): Likewise.
+       * doc/m4.texinfo (Trace): Mention more about trace formatting.
+       (Debugmode): Enhance description of 'c' and 'x'.  Enhance test to
+       cover line numbering details in traces.
+       (Debuglen): Enhance test to cover indir tracing.
+       * NEWS: Mention these changes.
+
 2008-05-07  Eric Blake  <address@hidden>
 
        Test for traceon regression just fixed in branch-1.6.
diff --git a/NEWS b/NEWS
index fd3bb09..ea0385b 100644
--- a/NEWS
+++ b/NEWS
@@ -158,10 +158,8 @@ promoted to 2.0.
     builtin traces actions related to module loading and unloading, and
     affects `dumpdef' and trace output to show where builtins come from.
     New `s' flag shows the entire stack of `pushdef' definitions during
-    `dumpdef'.  The `c' flag has been updated to output two lines instead
-    of three (since the last two had always been paired), and to add
-    information to the first line to show the definition of the macro being
-    expanded.  The 'e' flag has been updated to output non-text expansions.
+    `dumpdef'.  The `c' flag has been updated to add information to the
+    first line to show the definition of the macro being expanded.
 
 *** The `divert' builtin now accepts an optional second argument of text
     that is immediately placed on the new diversion, regardless of whether
@@ -248,6 +246,19 @@ promoted to 2.0.
    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 7bdfa66..8c4c237 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -3958,7 +3958,7 @@ foo # untraced
 @result{}bar # untraced
 @end example
 
-However, @acronym{GNU} M4 1.4.7 and earlier had slightly different
+However, @acronym{GNU} M4 prior to 2.0 had slightly different
 semantics, where @code{traceon} without arguments only affected symbols
 that were defined at that moment, and @code{traceoff} without arguments
 stopped all tracing, even when tracing was requested by macro name.  The
@@ -4006,7 +4006,56 @@ a b
 @end example
 
 @xref{Debugmode}, for information on controlling the details of the
-display.
+display.  The format of the trace output is not specified by
address@hidden, 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{Debugmode}).
+
address@hidden
+$ @kbd{m4 -d}
+define(`my_defn', defn(`defn'))undefine(`defn')
address@hidden
+define(`foo', `bar')traceon(`foo', `defn', `my_defn')
address@hidden
+foo
address@hidden: -1- foo -> `bar'
address@hidden
+indir(`foo')
address@hidden: -1- foo -> `bar'
address@hidden
+my_defn(`foo')
address@hidden: -1- my_defn(`foo') -> ``bar''
address@hidden
+indir(`my_defn', `foo')
address@hidden: -1- my_defn(`foo') -> ``bar''
address@hidden
+builtin(`defn', `foo')
address@hidden
+debugmode(`+cxt')
address@hidden
+builtin(`defn', builtin(`shift', `', `foo'))
address@hidden: -1- id 12: builtin ... = <builtin>
address@hidden: -2- id 13: builtin ... = <builtin>
address@hidden: -2- id 13: builtin(`shift', `', `foo') -> ``foo''
address@hidden: -1- id 12: builtin(`defn', `foo') -> ``bar''
address@hidden
+indir(`my_defn', indir(`shift', `', `foo'))
address@hidden: -1- id 14: indir ... = <indir>
address@hidden: -2- id 15: indir ... = <indir>
address@hidden: -2- id 15: shift ... = <shift>
address@hidden: -2- id 15: shift(`', `foo') -> ``foo''
address@hidden: -2- id 15: indir(`shift', `', `foo') -> ``foo''
address@hidden: -1- id 14: my_defn ... = <defn>
address@hidden: -1- id 14: my_defn(`foo') -> ``bar''
address@hidden: -1- id 14: indir(`my_defn', `foo') -> ``bar''
address@hidden
address@hidden example
 
 @node Debugmode
 @section Controlling debugging options
@@ -4033,10 +4082,13 @@ invoking the macro.  Arguments are subject to length 
truncation
 specified by @code{debuglen} (@pxref{Debuglen}).
 
 @item c
-In trace output, show an additional line for each macro call, prior to
-the arguments being collected, that shows the definition of the macro
-that will be used for the expansion.  The definition is subject to
-length truncation specified by @code{debuglen} (@pxref{Debuglen}).
+In trace output, show an additional line for each macro call, when the
+macro is seen, but before the arguments are collected, and show the
+definition of the macro that will be used for the expansion.  By
+default, only one line is printed, after all arguments are collected and
+the expansion determined.  The definition is subject to length
+truncation specified by @code{debuglen} (@pxref{Debuglen}).  This is
+often used with the @samp{x} flag.
 
 @item e
 In trace output, show the expansion of each macro call.  The expansion
@@ -4082,7 +4134,11 @@ arguments.
 
 @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.
@@ -4128,15 +4184,18 @@ debugmode()
 foo
 @error{}m4trace: -1- foo -> `FOO'
 @result{}FOO
-debugmode(`V')
address@hidden
-foo(`BAR')
address@hidden:stdin:6: -1- id 6: foo ... = `FOO$1'
address@hidden:stdin:6: -1- id 6: foo(`BAR') -> `FOOBAR'
+debugmode(`V')debugmode(`-q')
address@hidden:stdin:5: -1- id 6: debugmode ... = <debugmode>@address@hidden
address@hidden:stdin:5: -1- id 6: debugmode(`-q') -> `'
address@hidden
+foo(
+`BAR')
address@hidden:stdin:6: -1- id 7: foo ... = FOO$1
address@hidden:stdin:6: -1- id 7: foo(BAR) -> FOOBAR
 @result{}FOOBAR
 debugmode
address@hidden:stdin:7: -1- id 7: debugmode ... = <debugmode>@address@hidden
address@hidden:stdin:7: -1- id 7: debugmode ->@w{ }
address@hidden:stdin:8: -1- id 8: debugmode ... = <debugmode>@address@hidden
address@hidden:stdin:8: -1- id 8: debugmode ->@w{ }
 @result{}
 foo
 @error{}m4trace: -1- foo
@@ -4144,10 +4203,10 @@ foo
 debugmode(`+clmx')
 @result{}
 foo(divnum)
address@hidden:10: -1- id 10: foo ... = FOO$1
address@hidden:10: -2- id 11: divnum ... = <divnum>@address@hidden
address@hidden:10: -2- id 11: divnum
address@hidden:10: -1- id 10: foo
address@hidden:11: -1- id 11: foo ... = FOO$1
address@hidden:11: -2- id 12: divnum ... = <divnum>@address@hidden
address@hidden:11: -2- id 12: divnum
address@hidden:11: -1- id 11: foo
 @result{}FOO0
 debugmode(`-m')
 @result{}
@@ -4224,7 +4283,7 @@ define(`echo', `$@@')
 echo(`1', `long string')
 @error{}m4trace: -1- echo(`1', `long s...') -> ``1',`l...'
 @result{}1,long string
-echo(defn(`changequote'))
+indir(`echo', defn(`changequote'))
 @error{}m4trace: -2- defn(`change...') -> `<changequote>'
 @error{}m4trace: -1- echo(<changequote>) -> ``<changequote>''
 @result{}
diff --git a/m4/input.c b/m4/input.c
index 1f89916..a021e70 100644
--- a/m4/input.c
+++ b/m4/input.c
@@ -92,23 +92,28 @@
    maintains its own notion of the current file and line, so swapping
    between input blocks must update the context accordingly.  */
 
+typedef struct m4_input_block m4_input_block;
+
 static int     file_peek               (m4_input_block *, m4 *, 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 void    file_print              (m4_input_block *, m4 *, m4_obstack *,
+                                        int);
 static int     string_peek             (m4_input_block *, m4 *, 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 void    string_print            (m4_input_block *, m4 *, m4_obstack *,
+                                        int);
 static int     composite_peek          (m4_input_block *, m4 *, 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 *);
+static void    composite_print         (m4_input_block *, m4 *, m4_obstack *,
+                                        int);
 static int     eof_peek                (m4_input_block *, m4 *, bool);
 static int     eof_read                (m4_input_block *, m4 *, bool, bool,
                                         bool);
@@ -159,7 +164,7 @@ struct input_funcs
 
   /* Add a representation of the input block to the obstack, for use
      in trace expansion output.  */
-  void (*print_func)   (m4_input_block *, m4 *, m4_obstack *);
+  void (*print_func)   (m4_input_block *, m4 *, m4_obstack *, int);
 };
 
 /* A block of input to be scanned.  */
@@ -337,9 +342,11 @@ file_clean (m4_input_block *me, m4 *context, bool cleanup)
 }
 
 static void
-file_print (m4_input_block *me, m4 *context, m4_obstack *obs)
+file_print (m4_input_block *me, m4 *context M4_GNUC_UNUSED, m4_obstack *obs,
+           int debug_level M4_GNUC_UNUSED)
 {
   const char *text = me->file;
+  assert (obstack_object_size (current_input) == 0);
   obstack_grow (obs, "<file: ", strlen ("<file: "));
   obstack_grow (obs, text, strlen (text));
   obstack_1grow (obs, '>');
@@ -417,12 +424,15 @@ string_unget (m4_input_block *me, int ch)
 }
 
 static void
-string_print (m4_input_block *me, m4 *context, m4_obstack *obs)
+string_print (m4_input_block *me, m4 *context, m4_obstack *obs,
+             int debug_level)
 {
-  bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
+  bool quote = (debug_level & M4_DEBUG_TRACE_QUOTE) != 0;
   size_t arg_length = m4_get_max_debug_arg_length_opt (context);
 
-  m4_shipout_string_trunc (obs, me->u.u_s.str, me->u.u_s.len,
+  assert (!me->u.u_s.len);
+  m4_shipout_string_trunc (obs, (char *) obstack_base (current_input),
+                          obstack_object_size (current_input),
                           quote ? m4_get_syntax_quotes (M4SYNTAX) : NULL,
                           &arg_length);
 }
@@ -442,6 +452,7 @@ m4_push_string_init (m4 *context)
   next->funcs = &string_funcs;
   next->file = m4_get_current_file (context);
   next->line = m4_get_current_line (context);
+  next->u.u_s.len = 0;
 
   return current_input;
 }
@@ -610,24 +621,19 @@ m4__push_symbol (m4 *context, m4_symbol_value *value, 
size_t level, bool inuse)
 }
 
 /* Last half of m4_push_string ().  If next is now NULL, a call to
-   m4_push_file () or m4_push_builtin () has pushed a different input
-   block to the top of the stack.  If the new object is void, we do
-   not push it.  The function m4_push_string_finish () returns the
-   opaque finished object, whether that is still a string or has been
-   replaced by a file or builtin; this object can then be used in
-   m4_input_print () during tracing.  This pointer is only for
-   temporary use, since reading the next token might release the
-   memory used for the object.  */
-m4_input_block *
+   m4_push_file () has pushed a different input block to the top of
+   the stack.  Otherwise, all unfinished text on the obstack returned
+   from push_string_init is collected into the input stack.  If the
+   new object is empty, we do not push it.  */
+void
 m4_push_string_finish (void)
 {
-  m4_input_block *ret = NULL;
   size_t len = obstack_object_size (current_input);
 
   if (next == NULL)
     {
       assert (!len);
-      return isp;
+      return;
     }
 
   if (len || next->funcs == &composite_funcs)
@@ -641,13 +647,12 @@ m4_push_string_finish (void)
        m4__make_text_link (current_input, &next->u.u_c.chain,
                            &next->u.u_c.end);
       next->prev = isp;
-      ret = isp = next;
+      isp = next;
       input_change = true;
     }
   else
     obstack_free (current_input, next);
   next = NULL;
-  return ret;
 }
 
 
@@ -846,14 +851,16 @@ composite_clean (m4_input_block *me, m4 *context, bool 
cleanup)
 }
 
 static void
-composite_print (m4_input_block *me, m4 *context, m4_obstack *obs)
+composite_print (m4_input_block *me, m4 *context, m4_obstack *obs,
+                int debug_level)
 {
-  bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
+  bool quote = (debug_level & M4_DEBUG_TRACE_QUOTE) != 0;
   size_t maxlen = m4_get_max_debug_arg_length_opt (context);
   m4__symbol_chain *chain = me->u.u_c.chain;
   const m4_string_pair *quotes = m4_get_syntax_quotes (M4SYNTAX);
-  bool module = m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE);
+  bool module = (debug_level & M4_DEBUG_TRACE_MODULE) != 0;
   bool done = false;
+  size_t len = obstack_object_size (current_input);
 
   if (quote)
     m4_shipout_string (context, obs, quotes->str1, quotes->len1, false);
@@ -885,6 +892,9 @@ composite_print (m4_input_block *me, m4 *context, 
m4_obstack *obs)
        }
       chain = chain->next;
     }
+  if (len)
+    m4_shipout_string_trunc (obs, (char *) obstack_base (current_input), len,
+                            NULL, &maxlen);
   if (quote)
     m4_shipout_string (context, obs, quotes->str2, quotes->len2, false);
 }
@@ -988,25 +998,16 @@ eof_unget (m4_input_block *me M4_GNUC_UNUSED, int ch)
 
 
 /* When tracing, print a summary of the contents of the input block
-   created by push_string_init/push_string_finish to OBS.  */
+   created by push_string_init/push_string_finish to OBS.  Use
+   DEBUG_LEVEL to determine whether to add quotes or module
+   designations.  */
 void
-m4_input_print (m4 *context, m4_obstack *obs, m4_input_block *input)
+m4_input_print (m4 *context, m4_obstack *obs, int debug_level)
 {
-  assert (context && obs);
-  if (input == NULL)
-    {
-      if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
-       {
-         const m4_string_pair *quotes = m4_get_syntax_quotes (M4SYNTAX);
-         obstack_grow (obs, quotes->str1, quotes->len1);
-         obstack_grow (obs, quotes->str2, quotes->len2);
-       }
-    }
-  else
-    {
-      assert (input->funcs->print_func);
-      input->funcs->print_func (input, context, obs);
-    }
+  m4_input_block *block = next ? next : isp;
+  assert (context && obs && (debug_level & M4_DEBUG_TRACE_EXPANSION));
+  assert (block->funcs->print_func);
+  block->funcs->print_func (block, context, obs, debug_level);
 }
 
 /* Return an obstack ready for direct expansion of wrapup text, and
diff --git a/m4/m4module.h b/m4/m4module.h
index 21a8339..96b76ea 100644
--- a/m4/m4module.h
+++ b/m4/m4module.h
@@ -32,15 +32,14 @@ BEGIN_C_DECLS
 
 typedef struct m4              m4;
 typedef struct m4_builtin      m4_builtin;
+typedef struct m4_call_info    m4_call_info;
 typedef struct m4_macro                m4_macro;
-typedef struct m4_symbol       m4_symbol;
-typedef struct m4_symbol_value m4_symbol_value;
-typedef struct m4_input_block  m4_input_block;
-typedef struct m4_module       m4_module;
 typedef struct m4_macro_args   m4_macro_args;
-typedef struct m4_string_pair  m4_string_pair;
-
+typedef struct m4_module       m4_module;
 typedef struct obstack         m4_obstack;
+typedef struct m4_string_pair  m4_string_pair;
+typedef struct m4_symbol       m4_symbol;
+typedef struct m4_symbol_value m4_symbol_value;
 
 typedef void   m4_builtin_func  (m4 *, m4_obstack *, size_t, m4_macro_args *);
 
@@ -347,8 +346,9 @@ extern m4_symbol_value      *m4_builtin_find_by_func 
(m4_module *,
 
 extern void    m4_macro_expand_input   (m4 *);
 extern void    m4_macro_call           (m4 *, m4_symbol_value *, m4_obstack *,
-                                        size_t, m4_macro_args *);
+                                        m4_macro_args *);
 extern size_t  m4_arg_argc             (m4_macro_args *);
+extern const m4_call_info *m4_arg_info (m4_macro_args *);
 extern m4_symbol_value *m4_arg_symbol  (m4_macro_args *, size_t);
 extern bool    m4_is_arg_text          (m4_macro_args *, size_t);
 extern bool    m4_is_arg_func          (m4_macro_args *, size_t);
@@ -414,6 +414,8 @@ extern void m4_debug_message_prefix (m4 *);
 extern void    m4_debug_message        (m4 *, int, const char *, ...)
   M4_GNUC_PRINTF (3, 4);
 
+extern void    m4_trace_prepare        (m4 *, const m4_call_info *,
+                                        m4_symbol_value *);
 
 
 /* --- REGEXP SYNTAX --- */
@@ -496,9 +498,9 @@ extern      void    m4_skip_line    (m4 *context, const 
char *);
 extern void    m4_push_file    (m4 *, FILE *, const char *, bool);
 extern void    m4_push_builtin (m4 *, m4_obstack *, m4_symbol_value *);
 extern m4_obstack      *m4_push_string_init    (m4 *);
-extern m4_input_block  *m4_push_string_finish  (void);
+extern void    m4_push_string_finish   (void);
 extern bool    m4_pop_wrapup   (m4 *);
-extern void    m4_input_print  (m4 *, m4_obstack *, m4_input_block *);
+extern void    m4_input_print  (m4 *, m4_obstack *, int);
 
 
 
diff --git a/m4/m4private.h b/m4/m4private.h
index 7e1f7a8..526a0ef 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -313,6 +313,9 @@ struct m4_macro_args
      during parsing or any token is potentially unsafe and requires a
      rescan.  */
   unsigned int quote_age;
+  /* The context of the macro call during expansion, and NULL in a
+     back-reference.  */
+  m4_call_info *info;
   size_t level; /* Which obstack owns this argv.  */
   size_t arraylen; /* True length of allocated elements in array.  */
   /* Used as a variable-length array, storing information about each
@@ -332,6 +335,21 @@ struct m4__macro_arg_stacks
   void *argv_base;     /* Location for clearing the argv obstack.  */
 };
 
+/* Opaque structure for managing call context information.  Contains
+   the context used in tracing and error messages that was valid at
+   the start of the macro expansion, even if argument collection
+   changes global context in the meantime.  */
+struct m4_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.  */
+  size_t name_len;     /* The length of name.  */
+};
+
 extern size_t  m4__adjust_refcount     (m4 *, size_t, bool);
 extern bool    m4__arg_adjust_refcount (m4 *, m4_macro_args *, bool);
 extern void    m4__push_arg_quote      (m4 *, m4_obstack *, m4_macro_args *,
@@ -553,6 +571,7 @@ extern      bool            m4__next_token_is_open (m4 *);
    that also have an identically named function exported in m4module.h.  */
 #ifdef NDEBUG
 # define m4_arg_argc(A)                (A)->argc
+# define m4_arg_info(A)                (A)->info
 # define m4_arg_scratch(C)                             \
   ((C)->arg_stacks[(C)->expansion_level - 1].argv)
 #endif /* NDEBUG */
diff --git a/m4/macro.c b/m4/macro.c
index f5bec18..1e88299 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -122,9 +122,8 @@
    memory left on the obstack while waiting for refcounts to drop.
 */
 
-static m4_macro_args *collect_arguments (m4 *, const char *, size_t,
-                                        m4_symbol *, m4_obstack *,
-                                        m4_obstack *);
+static m4_macro_args *collect_arguments (m4 *, m4_call_info *, m4_symbol *,
+                                        m4_obstack *, m4_obstack *);
 static void    expand_macro      (m4 *, const char *, size_t, m4_symbol *);
 static bool    expand_token      (m4 *, m4_obstack *, m4__token_type,
                                  m4_symbol_value *, int, bool);
@@ -133,16 +132,13 @@ static bool    expand_argument   (m4 *, m4_obstack *, 
m4_symbol_value *,
 static void    process_macro    (m4 *, m4_symbol_value *, m4_obstack *, int,
                                  m4_macro_args *);
 
-static void    trace_prepre     (m4 *, const char *, size_t,
-                                 m4_symbol_value *);
-static void    trace_pre        (m4 *, size_t, m4_macro_args *);
-static void    trace_post       (m4 *, size_t, m4_macro_args *,
-                                 m4_input_block *, bool);
+static unsigned int trace_pre   (m4 *, m4_macro_args *);
+static void    trace_post       (m4 *, unsigned int, const m4_call_info *);
 
 static void    trace_format     (m4 *, const char *, ...)
   M4_GNUC_PRINTF (2, 3);
-static void    trace_header     (m4 *, size_t);
-static void    trace_flush      (m4 *);
+static unsigned int trace_header (m4 *, const m4_call_info *);
+static void    trace_flush      (m4 *, unsigned int);
 
 
 /* The number of the current call of expand_macro ().  */
@@ -443,22 +439,12 @@ expand_macro (m4 *context, const char *name, size_t len, 
m4_symbol *symbol)
   void *argv_base;             /* Base of stack->argv on entry.  */
   m4_macro_args *argv;         /* Arguments to the called macro.  */
   m4_obstack *expansion;       /* Collects the macro's expansion.  */
-  m4_input_block *expanded;    /* The resulting expansion, for tracing.  */
-  bool traced;                 /* True if this macro is traced.  */
-  bool trace_expansion = false;        /* True if trace and debugmode(`e').  */
-  size_t my_call_id;           /* Sequence id for this macro.  */
   m4_symbol_value *value;      /* Original value of this macro.  */
   size_t level;                        /* Expansion level of this macro.  */
   m4__macro_arg_stacks *stack; /* Storage for this macro.  */
+  m4_call_info info;           /* Context of this macro call.  */
 
-  /* 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 = m4_get_current_file (context);
-  int loc_open_line = m4_get_current_line (context);
+  /* TODO - use m4_call_info to avoid temporary munging of global state.  */
   const char *loc_close_file;
   int loc_close_line;
 
@@ -496,10 +482,14 @@ expand_macro (m4 *context, const char *name, size_t len, 
m4_symbol *symbol)
      collecting arguments.  Likewise, grab any state needed during
      tracing.  */
   value = m4_get_symbol_value (symbol);
-  traced = (m4_is_debug_bit (context, M4_DEBUG_TRACE_ALL)
-           || m4_get_symbol_traced (symbol));
-  if (traced)
-    trace_expansion = m4_is_debug_bit (context, M4_DEBUG_TRACE_EXPANSION);
+  info.file = m4_get_current_file (context);
+  info.line = m4_get_current_line (context);
+  info.call_id = ++macro_call_id;
+  info.trace = (m4_is_debug_bit (context, M4_DEBUG_TRACE_ALL)
+               || m4_get_symbol_traced (symbol));
+  info.debug_level = m4_get_debug_level_opt (context);
+  info.name = name;
+  info.name_len = len;
 
   /* Prepare for macro expansion.  */
   VALUE_PENDING (value)++;
@@ -507,13 +497,9 @@ expand_macro (m4 *context, const char *name, size_t len, 
m4_symbol *symbol)
     m4_error (context, EXIT_FAILURE, 0, NULL, _("\
 recursion limit of %zu exceeded, use -L<N> to change it"),
              m4_get_nesting_limit_opt (context));
-  my_call_id = ++macro_call_id;
 
-  if (traced && m4_is_debug_bit (context, M4_DEBUG_TRACE_CALL))
-    trace_prepre (context, name, my_call_id, value);
-
-  argv = collect_arguments (context, name, len, symbol, stack->args,
-                           stack->argv);
+  m4_trace_prepare (context, &info, value);
+  argv = collect_arguments (context, &info, symbol, stack->args, stack->argv);
   /* Since collect_arguments can invalidate stack by reallocating
      context->arg_stacks during a recursive expand_macro call, we must
      reset it here.  */
@@ -523,22 +509,16 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
   /* The actual macro call.  */
   loc_close_file = m4_get_current_file (context);
   loc_close_line = m4_get_current_line (context);
-  m4_set_current_file (context, loc_open_file);
-  m4_set_current_line (context, loc_open_line);
-
-  if (traced)
-    trace_pre (context, my_call_id, argv);
-
+  m4_set_current_file (context, info.file);
+  m4_set_current_line (context, info.line);
   expansion = m4_push_string_init (context);
-  m4_macro_call (context, value, expansion, argv->argc, argv);
-  expanded = m4_push_string_finish ();
-
-  if (traced)
-    trace_post (context, my_call_id, argv, expanded, trace_expansion);
+  m4_macro_call (context, value, expansion, argv);
+  m4_push_string_finish ();
 
   /* Cleanup.  */
   m4_set_current_file (context, loc_close_file);
   m4_set_current_line (context, loc_close_line);
+  argv->info = NULL;
 
   --context->expansion_level;
   --VALUE_PENDING (value);
@@ -558,8 +538,8 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
          obstack_free (stack->args, args_scratch);
          if (debug_macro_level & PRINT_ARGCOUNT_CHANGES)
            xfprintf (stderr, "m4debug: -%d- `%s' in use, level=%d, "
-                     "refcount=%zu, argcount=%zu\n", my_call_id, argv->argv0,
-                     level, stack->refcount, stack->argcount);
+                     "refcount=%zu, argcount=%zu\n", info.call_id,
+                     argv->argv0, level, stack->refcount, stack->argcount);
        }
       else
        {
@@ -570,15 +550,13 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
     }
 }
 
-/* Collect all the arguments to a call of the macro SYMBOL (called
-   NAME, with length LEN).  The arguments are stored on the obstack
-   ARGUMENTS and a table of pointers to the arguments on the obstack
-   argv_stack.  Return the object describing all of the macro
-   arguments.  */
+/* Collect all the arguments to a call of the macro SYMBOL, with call
+   context INFO.  The arguments are stored on the obstack ARGUMENTS
+   and a table of pointers to the arguments on ARGV_STACK.  Return the
+   object describing all of the macro arguments.  */
 static m4_macro_args *
-collect_arguments (m4 *context, const char *name, size_t len,
-                  m4_symbol *symbol, m4_obstack *arguments,
-                  m4_obstack *argv_stack)
+collect_arguments (m4 *context, m4_call_info *info, m4_symbol *symbol,
+                  m4_obstack *arguments, m4_obstack *argv_stack)
 {
   m4_symbol_value token;
   m4_symbol_value *tokenp;
@@ -594,23 +572,24 @@ collect_arguments (m4 *context, const char *name, size_t 
len,
   args.has_func = false;
   /* Must copy here, since we are consuming tokens, and since symbol
      table can be changed during argument collection.  */
-  args.argv0 = (char *) obstack_copy0 (arguments, name, len);
-  args.argv0_len = len;
+  args.argv0 = (char *) obstack_copy0 (arguments, info->name, info->name_len);
+  args.argv0_len = info->name_len;
   args.quote_age = m4__quote_age (M4SYNTAX);
+  args.info = info;
   args.level = context->expansion_level - 1;
   args.arraylen = 0;
   obstack_grow (argv_stack, &args, offsetof (m4_macro_args, array));
-  name = args.argv0;
+  info->name = args.argv0;
 
   if (m4__next_token_is_open (context))
     {
       /* Gobble parenthesis, then collect arguments.  */
-      m4__next_token (context, &token, NULL, NULL, false, name);
+      m4__next_token (context, &token, NULL, NULL, false, info->name);
       do
        {
          tokenp = (m4_symbol_value *) obstack_alloc (arguments,
                                                      sizeof *tokenp);
-         more_args = expand_argument (context, arguments, tokenp, name);
+         more_args = expand_argument (context, arguments, tokenp, info->name);
 
          if ((m4_is_symbol_value_text (tokenp)
               && !m4_get_symbol_value_len (tokenp))
@@ -669,33 +648,41 @@ collect_arguments (m4 *context, const char *name, size_t 
len,
 
 
 /* The actual call of a macro is handled by m4_macro_call ().
-   m4_macro_call () is passed a SYMBOL, whose type is used to
+   m4_macro_call () is passed a symbol VALUE, whose type is used to
    call either a builtin function, or the user macro expansion
-   function process_macro ().  There are ARGC arguments to
-   the call, stored in the ARGV table.  The expansion is left on
-   the obstack EXPANSION.  Macro tracing is also handled here.  */
+   function process_macro ().  The arguments are provided by the ARGV
+   table.  The expansion is left on the obstack EXPANSION.  Macro
+   tracing is also handled here.  */
 void
 m4_macro_call (m4 *context, m4_symbol_value *value, m4_obstack *expansion,
-              size_t argc, m4_macro_args *argv)
+              m4_macro_args *argv)
 {
-  if (m4_bad_argc (context, argc, argv->argv0,
-                  VALUE_MIN_ARGS (value), VALUE_MAX_ARGS (value),
-                  BIT_TEST (VALUE_FLAGS (value),
-                            VALUE_SIDE_EFFECT_ARGS_BIT)))
-    return;
-  if (m4_is_symbol_value_text (value))
-    process_macro (context, value, expansion, argc, argv);
-  else if (m4_is_symbol_value_func (value))
-    m4_get_symbol_value_func (value) (context, expansion, argc, argv);
-  else if (m4_is_symbol_value_placeholder (value))
-    m4_warn (context, 0, M4ARG (0),
-            _("builtin `%s' requested by frozen file not found"),
-            m4_get_symbol_value_placeholder (value));
-  else
+  unsigned int trace_start = 0;
+
+  if (argv->info->trace)
+    trace_start = trace_pre (context, argv);
+  if (!m4_bad_argc (context, argv->argc, argv->argv0,
+                   VALUE_MIN_ARGS (value), VALUE_MAX_ARGS (value),
+                   BIT_TEST (VALUE_FLAGS (value),
+                             VALUE_SIDE_EFFECT_ARGS_BIT)))
     {
-      assert (!"m4_macro_call");
-      abort ();
+      if (m4_is_symbol_value_text (value))
+       process_macro (context, value, expansion, argv->argc, argv);
+      else if (m4_is_symbol_value_func (value))
+       m4_get_symbol_value_func (value) (context, expansion, argv->argc,
+                                         argv);
+      else if (m4_is_symbol_value_placeholder (value))
+       m4_warn (context, 0, M4ARG (0),
+                _("builtin `%s' requested by frozen file not found"),
+                m4_get_symbol_value_placeholder (value));
+      else
+       {
+         assert (!"m4_macro_call");
+         abort ();
+       }
     }
+  if (argv->info->trace)
+    trace_post (context, trace_start, argv->info);
 }
 
 /* This function handles all expansion of user defined and predefined
@@ -881,91 +868,106 @@ trace_format (m4 *context, const char *fmt, ...)
   va_end (args);
 }
 
-/* Format the standard header attached to all tracing output lines.  */
-static void
-trace_header (m4 *context, size_t 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 unsigned int
+trace_header (m4 *context, const m4_call_info *info)
 {
+  unsigned int result = obstack_object_size (&context->trace_messages);
   trace_format (context, "m4trace:");
-  if (m4_get_current_line (context))
-    {
-      if (m4_is_debug_bit (context, M4_DEBUG_TRACE_FILE))
-       trace_format (context, "%s:", m4_get_current_file (context));
-      if (m4_is_debug_bit (context, M4_DEBUG_TRACE_LINE))
-       trace_format (context, "%d:", m4_get_current_line (context));
-    }
+  if (info->debug_level & M4_DEBUG_TRACE_FILE)
+    trace_format (context, "%s:", info->file);
+  if (info->debug_level & M4_DEBUG_TRACE_LINE)
+    trace_format (context, "%d:", info->line);
   trace_format (context, " -%zu- ", context->expansion_level);
-  if (m4_is_debug_bit (context, M4_DEBUG_TRACE_CALLID))
-    trace_format (context, "id %zu: ", id);
+  if (info->debug_level & M4_DEBUG_TRACE_CALLID)
+    trace_format (context, "id %zu: ", 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 (m4 *context)
+trace_flush (m4 *context, unsigned int start)
 {
-  char *line;
-
-  obstack_1grow (&context->trace_messages, '\n');
-  obstack_1grow (&context->trace_messages, '\0');
-  line = obstack_finish (&context->trace_messages);
-  if (m4_get_debug_file (context))
-    fputs (line, m4_get_debug_file (context));
-  obstack_free (&context->trace_messages, line);
+  char *str;
+  FILE *file = m4_get_debug_file (context);
+
+  if (file)
+    {
+      obstack_1grow (&context->trace_messages, '\0');
+      str = (char *) obstack_base (&context->trace_messages);
+      fprintf (file, "%s\n", &str[start]);
+    }
+  start -= obstack_object_size (&context->trace_messages);
+  obstack_blank (&context->trace_messages, start);
 }
 
-/* Do pre-argument-collection tracing for macro NAME.  Used from
-   expand_macro ().  */
-static void
-trace_prepre (m4 *context, const char *name, size_t id, m4_symbol_value *value)
+/* Do pre-argument-collection tracing for the macro described in INFO.
+   Should be called prior to m4_macro_call().  */
+void
+m4_trace_prepare (m4 *context, const m4_call_info *info,
+                 m4_symbol_value *value)
 {
   const m4_string_pair *quotes = NULL;
   size_t arg_length = m4_get_max_debug_arg_length_opt (context);
-  bool module = m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE);
+  bool module = (info->debug_level & M4_DEBUG_TRACE_MODULE) != 0;
 
-  if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
+  if (info->debug_level & M4_DEBUG_TRACE_QUOTE)
     quotes = m4_get_syntax_quotes (M4SYNTAX);
-  trace_header (context, id);
-  trace_format (context, "%s ... = ", name);
-  m4__symbol_value_print (context, value, &context->trace_messages, quotes,
-                         false, NULL, &arg_length, module);
-  trace_flush (context);
+  if (info->trace && (info->debug_level & M4_DEBUG_TRACE_CALL))
+    {
+      unsigned int start = trace_header (context, info);
+      trace_format (context, "%s ... = ", info->name);
+      m4__symbol_value_print (context, value, &context->trace_messages, quotes,
+                             false, NULL, &arg_length, module);
+      trace_flush (context, start);
+    }
 }
 
-/* Format the parts of a trace line, that can be made before the macro is
-   actually expanded.  Used from expand_macro ().  */
-static void
-trace_pre (m4 *context, size_t id, m4_macro_args *argv)
+/* Format the parts of a trace line that are known via ARGV before the
+   macro is actually expanded.  Used from m4_macro_call().  Return the
+   start of the current trace, in case other traces are printed before
+   this trace completes trace_post.  */
+static unsigned int
+trace_pre (m4 *context, m4_macro_args *argv)
 {
-  trace_header (context, id);
+  int trace_level = argv->info->debug_level;
+  unsigned int start = trace_header (context, argv->info);
+
+  assert (argv->info->trace);
   trace_format (context, "%s", M4ARG (0));
 
-  if (1 < m4_arg_argc (argv) && m4_is_debug_bit (context, M4_DEBUG_TRACE_ARGS))
+  if (1 < m4_arg_argc (argv) && (trace_level & M4_DEBUG_TRACE_ARGS))
     {
       const m4_string_pair *quotes = NULL;
       size_t arg_length = m4_get_max_debug_arg_length_opt (context);
-      bool module = m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE);
+      bool module = (trace_level & M4_DEBUG_TRACE_MODULE) != 0;
 
-      if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
+      if (trace_level & M4_DEBUG_TRACE_QUOTE)
        quotes = m4_get_syntax_quotes (M4SYNTAX);
       trace_format (context, "(");
       m4__arg_print (context, &context->trace_messages, argv, 1, quotes, false,
                     NULL, ", ", &arg_length, true, module);
       trace_format (context, ")");
     }
+  return start;
 }
 
-/* Format the final part of a trace line and print it all.  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 m4_macro_call ().  */
 static void
-trace_post (m4 *context, size_t id, m4_macro_args *argv,
-           m4_input_block *expanded, bool trace_expansion)
+trace_post (m4 *context, unsigned int start, const m4_call_info *info)
 {
-  if (trace_expansion)
+  assert (info->trace);
+  if (info->debug_level & M4_DEBUG_TRACE_EXPANSION)
     {
       trace_format (context, " -> ");
-      m4_input_print (context, &context->trace_messages, expanded);
+      m4_input_print (context, &context->trace_messages, info->debug_level);
     }
-
-  trace_flush (context);
+  trace_flush (context, start);
 }
 
 
@@ -1586,23 +1588,24 @@ m4__arg_print (m4 *context, m4_obstack *obs, 
m4_macro_args *argv, size_t arg,
 /* 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 builtins in ARGV are 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.  */
 m4_macro_args *
 m4_make_argv_ref (m4 *context, m4_macro_args *argv, const char *argv0,
-                 size_t argv0_len, bool skip, bool flatten)
+                 size_t argv0_len, bool flatten, bool trace)
 {
   m4_macro_args *new_argv;
   m4_symbol_value *value;
   m4_symbol_value *new_value;
-  size_t arg = skip ? 2 : 1;
   m4_obstack *obs = m4_arg_scratch (context);
+  m4_call_info *info;
 
+  info = (m4_call_info *) obstack_copy (obs, argv->info, sizeof *info);
   new_value = (m4_symbol_value *) obstack_alloc (obs, sizeof *value);
   value = make_argv_ref (context, new_value, obs, context->expansion_level - 1,
-                        argv, arg, flatten, NULL);
+                        argv, 2, flatten, NULL);
   if (!value)
     {
       obstack_free (obs, new_value);
@@ -1626,11 +1629,15 @@ m4_make_argv_ref (m4 *context, m4_macro_args *argv, 
const char *argv0,
       new_argv->flatten = flatten;
       new_argv->has_func = argv->has_func;
     }
-  new_argv->argc = argv->argc - (arg - 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 & M4_DEBUG_TRACE_ALL) || trace;
+  info->name = argv0;
+  info->name_len = argv0_len;
   new_argv->level = argv->level;
   return new_argv;
 }
@@ -1780,6 +1787,17 @@ m4_arg_argc (m4_macro_args *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.  */
+#undef m4_arg_info
+const m4_call_info *
+m4_arg_info (m4_macro_args *argv)
+{
+  assert (argv->info);
+  return argv->info;
+}
+
 /* Return an obstack useful for scratch calculations, and which will
    not interfere with macro expansion.  The obstack will be reset when
    expand_macro completes.  */
diff --git a/modules/gnu.c b/modules/gnu.c
index f0d3a44..c28a100 100644
--- a/modules/gnu.c
+++ b/modules/gnu.c
@@ -447,7 +447,7 @@ M4BUILTIN_HANDLER (builtin)
              m4_macro_args *new_argv;
              bool flatten = (bp->flags & M4_BUILTIN_FLATTEN_ARGS) != 0;
              new_argv = m4_make_argv_ref (context, argv, name, M4ARGLEN (1),
-                                          true, flatten);
+                                          flatten, false);
              bp->func (context, obs, argc - 1, new_argv);
            }
          free (value);
@@ -680,10 +680,12 @@ M4BUILTIN_HANDLER (indir)
       else
        {
          m4_macro_args *new_argv;
+         m4_symbol_value *value = m4_get_symbol_value (symbol);
          new_argv = m4_make_argv_ref (context, argv, name, M4ARGLEN (1),
-                                      true, m4_symbol_flatten_args (symbol));
-         m4_macro_call (context, m4_get_symbol_value (symbol), obs,
-                        argc - 1, new_argv);
+                                      m4_symbol_flatten_args (symbol),
+                                      m4_get_symbol_traced (symbol));
+         m4_trace_prepare (context, m4_arg_info (new_argv), value);
+         m4_macro_call (context, value, obs, new_argv);
        }
     }
 }
diff --git a/src/main.c b/src/main.c
index 7c3b9cc..e500046 100644
--- a/src/main.c
+++ b/src/main.c
@@ -156,7 +156,7 @@ Debugging:\n\
       fputs (_("\
 FLAGS is any of:\n\
   a   show actual arguments in trace\n\
-  c   show definition line 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\
@@ -165,9 +165,9 @@ FLAGS is any of:\n\
       fputs (_("\
   m   show module information in trace, debug, and dumpdef\n\
   p   show results of path searches in debug\n\
-  q   quote values as necessary in dumpdef and trace, useful with a or e\n\
+  q   quote values in dumpdef and trace, useful with a or e\n\
   s   show full stack of pushdef values in dumpdef\n\
-  t   trace all macro calls, regardless of named traceon state\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);
diff --git a/tests/macros.at b/tests/macros.at
index c4db9e6..fe42518 100644
--- a/tests/macros.at
+++ b/tests/macros.at
@@ -356,7 +356,7 @@ m4trace: -2- eval(`1<=1') -> `1'
 m4trace: -1- ifelse(`1', `1', `move(auxilliary, destination)', 
`_hanoi(decr(1), auxilliary, source, destination)move(auxilliary, 
destination)_hanoi(decr(1), source, destination, auxilliary)') -> 
`move(auxilliary, destination)'
 m4trace: -1- move(`auxilliary', `destination') -> `Move one disk from 
`auxilliary' to `destination'.
 '
-m4trace: -1- debugmode -> @&t@
+m4trace: -1- debugmode -> `'
 m4trace: -1- _hanoi(2, source, destination, auxilliary) -> 
ifelse(eval(`2'<=1), 1, `move(source, destination)',
 `_hanoi(decr(2), source, auxilliary, destination)move(source, 
destination)_hanoi(decr(2), auxilliary, destination, source)')
 m4trace: -1- _hanoi(1, source, auxilliary, destination) -> 
ifelse(eval(`1'<=1), 1, `move(source, auxilliary)',
diff --git a/tests/null.err b/tests/null.err
index 61518e8..d825818 100644
Binary files a/tests/null.err and b/tests/null.err differ
diff --git a/tests/null.m4 b/tests/null.m4
index 90e339f..851d665 100644
Binary files a/tests/null.m4 and b/tests/null.m4 differ


hooks/post-receive
--
GNU M4 source repository




reply via email to

[Prev in Thread] Current Thread [Next in Thread]