m4-commit
[Top][All Lists]
Advanced

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

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


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, branch-1.6, updated. v1.5.89a-20-gbc4cf0a
Date: Fri, 09 May 2008 12:16:50 +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=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 <address@hidden>
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 <address@hidden>

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

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  <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.
+       * 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  <address@hidden>
 
        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
address@hidden: -1- define(`mydivnum', `<divnum><divnum>')
address@hidden: -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')
address@hidden: -1- traceon(`traceoff')
address@hidden: -1- traceon(`traceoff') -> `'
 @result{}
 traceoff(`traceoff')
address@hidden: -1- traceoff(`traceoff')
address@hidden: -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
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{Debug Levels}).
+
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 ...
address@hidden: -2- id 13: 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 ...
address@hidden: -2- id 15: indir ...
address@hidden: -2- id 15: 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 ...
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 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}).
 
address@hidden FIXME - is it worth adding @item b, which turns on backslash
address@hidden 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')
address@hidden
-foo(`ignored')
address@hidden:stdin:6: -1- id 6: foo ...
address@hidden:stdin:6: -1- id 6: foo(`ignored') -> ???
address@hidden:stdin:6: -1- id 6: foo(...) -> `FOO'
+debugmode(`V')debugmode(`-q')
address@hidden:stdin:5: -1- id 6: debugmode ...
address@hidden:stdin:5: -1- id 6: debugmode(`-q') -> `'
address@hidden
+foo(
+`ignored')
address@hidden:stdin:6: -1- id 7: foo ...
address@hidden:stdin:6: -1- id 7: foo(ignored) -> FOO
 @result{}FOO
 debugmode
address@hidden:stdin:7: -1- id 7: debugmode ...
address@hidden:stdin:7: -1- id 7: debugmode -> ???
address@hidden
address@hidden:stdin:8: -1- id 8: debugmode ...
address@hidden:stdin:8: -1- id 8: debugmode ->@w{ }
 @result{}
 foo
 @error{}m4trace: -1- foo
@@ -3858,7 +3915,7 @@ foo
 debugmode(`+l')
 @result{}
 foo
address@hidden:10: -1- foo
address@hidden: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.
 
address@hidden options: -l6
address@hidden 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>'
address@hidden: -1- indir(`echo', <changequote>) -> ``<changequote>''
address@hidden: -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
address@hidden M4; however, the intent is that any future changes in
+trace output will only occur under the direction of additional
address@hidden flags (@pxref{Debug Levels}).
+
 @item
 @acronym{POSIX} requires @code{eval} (@pxref{Eval}) to treat all
 operators with the same precedence as address@hidden  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




reply via email to

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