dumpdef a pushdef'd stack

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
As mentioned in the second half of: http://lists.gnu.org/archive/html/m4-
patches/2006-09/msg00027.html

2006-09-26  Eric Blake  <[email protected]>

	* m4/m4module.h (m4_symbol_print): New prototype.
	(M4_DEBUG_TRACE_STACK): New enumerator.
	(m4_is_debug_bit): Allow use without requiring m4private.h.
	* m4/symtab.c (symbol_value_print, m4_symbol_print): New
	functions.
	* modules/m4.c (dump_symbol_CB, m4_dump_symbols): Speed up
	callback.
	(dumpdef): Allow printing pushdef'd stacks.
	* m4/debug.c (m4_debug_decode): Add new 's' debug mode.
	* src/main.c (usage): Document it.
	* doc/m4.texinfo (Dumpdef, Debug Levels): Likewise.
	* NEWS: Likewise.

Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.19
diff -u -r1.19 NEWS
--- NEWS	21 Sep 2006 04:12:55 -0000	1.19
+++ NEWS	26 Sep 2006 20:37:23 -0000
@@ -59,9 +59,10 @@
   standard error are terminals.
 
 * New `m' flag to `-d'/`--debug' option or `debugmode' macro traces
-  actions related to module loading and unloading.  Also, the `--debug'
-  option now understands `-' and `+' modifiers, the way `debugmode' has
-  always done.
+  actions related to module loading and unloading.  New `s' flag shows the
+  entire stack of `pushdef' definitions during `dumpdef'.  Also, the
+  `--debug' option now understands `-' and `+' modifiers, the way
+  `debugmode' has always done.
 
 * The semantics of `traceon' and `traceoff' now match traditional
   implementations: when called without arguments, they affect global state
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.51
diff -u -r1.51 m4.texinfo
--- doc/m4.texinfo	21 Sep 2006 16:40:03 -0000	1.51
+++ doc/m4.texinfo	26 Sep 2006 20:37:23 -0000
@@ -2638,9 +2638,23 @@
 @result{}f1
 @end example
 
-@xref{Debug Levels}, for information on controlling the details of the
-display; in particular, the @samp{q} flag, implied by @option{-d} in the
-example command line, has an impact.
+@xref{Debug Levels}, for information on how the @samp{q} and @samp{s}
+flags affect the details of the display.  Remember, the @samp{q} flag is
+implied when @option{-d} is used in the command line without arguments.
+
+@comment options: -ds
+@example
+$ @kbd{m4 -ds}
+pushdef(`foo', `1')
+@result{}
+pushdef(`foo', defn(`divnum'))
+@result{}
+pushdef(`foo', `3')
+@result{}
+dumpdef(`foo')
+@error{}foo:@tabchar{}3, <divnum>, 1
+@result{}
+@end example
 
 @node Trace
 @section Tracing macro calls
@@ -2900,6 +2914,10 @@
 current quotes.  This affects traced macros, as well as @code{dumpdef}
 output.
 
+@item s
+Show the entire stack of definitions associated with a symbol via
+@code{pushdef}.  This affects @code{dumpdef} output.
+
 @item t
 Trace all macro calls made in this invocation of @code{m4}.  This is
 equivalent to using @code{traceon} without arguments.
Index: m4/debug.c
===================================================================
RCS file: /sources/m4/m4/m4/debug.c,v
retrieving revision 1.25
diff -u -r1.25 debug.c
--- m4/debug.c	19 Sep 2006 13:16:08 -0000	1.25
+++ m4/debug.c	26 Sep 2006 20:37:23 -0000
@@ -89,6 +89,10 @@
 	      level |= M4_DEBUG_TRACE_MODULE;
 	      break;
 
+	    case 's':
+	      level |= M4_DEBUG_TRACE_STACK;
+	      break;
+
 	    case 'V':
 	      level |= M4_DEBUG_TRACE_VERBOSE;
 	      break;
Index: m4/m4module.h
===================================================================
RCS file: /sources/m4/m4/m4/m4module.h,v
retrieving revision 1.86
diff -u -r1.86 m4module.h
--- m4/m4module.h	18 Sep 2006 13:16:44 -0000	1.86
+++ m4/m4module.h	26 Sep 2006 20:37:23 -0000
@@ -113,10 +113,10 @@
 /* Error handling.  */
 extern void m4_error (m4 *, int, int, const char *, ...) M4_GNUC_PRINTF (4, 5);
 extern void m4_error_at_line (m4 *, int, int, const char *, int,
-			      const char *, ...)         M4_GNUC_PRINTF (6, 7);
-extern void m4_warn  (m4 *, int, const char *, ...)      M4_GNUC_PRINTF (3, 4);
+			      const char *, ...)	 M4_GNUC_PRINTF (6, 7);
+extern void m4_warn  (m4 *, int, const char *, ...)	 M4_GNUC_PRINTF (3, 4);
 extern void m4_warn_at_line  (m4 *, int, const char *, int,
-			      const char *, ...)         M4_GNUC_PRINTF (5, 6);
+			      const char *, ...)	 M4_GNUC_PRINTF (5, 6);
 
 
 /* --- CONTEXT MANAGEMENT --- */
@@ -216,6 +216,8 @@
 extern bool		m4_get_symbol_traced	  (m4_symbol*);
 extern bool		m4_set_symbol_name_traced (m4_symbol_table*,
 						   const char *, bool);
+extern void		m4_symbol_print	  (m4_symbol *, m4_obstack *, bool,
+					   const char *, const char *, bool);
 
 #define m4_is_symbol_void(symbol)					\
 	(m4_is_symbol_value_void (m4_get_symbol_value (symbol)))
@@ -294,16 +296,18 @@
   M4_DEBUG_TRACE_CALLID		= (1 << 9),
   /* m: trace module actions */
   M4_DEBUG_TRACE_MODULE		= (1 << 10),
+  /* s: trace pushdef stacks */
+  M4_DEBUG_TRACE_STACK		= (1 << 11),
 
   /* V: very verbose --  print everything */
-  M4_DEBUG_TRACE_VERBOSE	= ((1 << 11) - 1)
+  M4_DEBUG_TRACE_VERBOSE	= ((1 << 12) - 1)
 };
 
 /* default flags -- equiv: aeq */
 #define M4_DEBUG_TRACE_DEFAULT		\
-	(M4_DEBUG_TRACE_ARGS|M4_DEBUG_TRACE_EXPANSION|M4_DEBUG_TRACE_QUOTE)
+	(M4_DEBUG_TRACE_ARGS | M4_DEBUG_TRACE_EXPANSION | M4_DEBUG_TRACE_QUOTE)
 
-#define m4_is_debug_bit(C,B)	(BIT_TEST (m4_get_debug_level_opt (C), (B)))
+#define m4_is_debug_bit(C,B)	((m4_get_debug_level_opt (C) & (B)) != 0)
 
 extern int	m4_debug_decode		(m4 *, int, const char *);
 extern bool	m4_debug_set_output	(m4 *, const char *);
Index: m4/symtab.c
===================================================================
RCS file: /sources/m4/m4/m4/symtab.c,v
retrieving revision 1.60
diff -u -r1.60 symtab.c
--- m4/symtab.c	18 Sep 2006 13:16:44 -0000	1.60
+++ m4/symtab.c	26 Sep 2006 20:37:23 -0000
@@ -57,7 +57,8 @@
 					 void *arg, void *ignored);
 static void *	  arg_copy_CB		(m4_hash *src, const void *name,
 					 void *arg, m4_hash *dest);
-
+static void	  symbol_value_print	(m4_symbol_value *, m4_obstack *, bool,
+					 const char *, const char *);
 
 
 /* -- SYMBOL TABLE MANAGEMENT --
@@ -461,6 +462,76 @@
   return result;
 }
 
+/* Grow OBS with a text representation of VALUE.  If QUOTE, then
+   surround a text definition by LQUOTE and RQUOTE.  */
+static void
+symbol_value_print (m4_symbol_value *value, m4_obstack *obs, bool quote,
+		    const char *lquote, const char *rquote)
+{
+  if (m4_is_symbol_value_text (value))
+    {
+      if (quote)
+	{
+	  obstack_grow (obs, lquote, strlen (lquote));
+	  obstack_grow (obs, m4_get_symbol_value_text (value),
+			strlen (m4_get_symbol_value_text (value)));
+	  obstack_grow (obs, rquote, strlen (rquote));
+	}
+      else
+	obstack_grow (obs, m4_get_symbol_value_text (value),
+		      strlen (m4_get_symbol_value_text (value)));
+    }
+  else if (m4_is_symbol_value_func (value))
+    {
+      const m4_builtin *bp;
+      bp = m4_builtin_find_by_func (NULL, m4_get_symbol_value_func (value));
+      assert (bp);
+      obstack_1grow (obs, '<');
+      obstack_grow (obs, bp->name, strlen (bp->name));
+      obstack_1grow (obs, '>');
+    }
+  else if (m4_is_symbol_value_placeholder (value))
+    {
+      /* FIXME - is it worth translating "placeholder for "?  */
+      obstack_grow (obs, "<placeholder for ", strlen ("<placeholder for "));
+      obstack_grow (obs, m4_get_symbol_value_placeholder (value),
+		    strlen (m4_get_symbol_value_placeholder (value)));
+      obstack_1grow (obs, '>');
+    }
+  else
+    {
+      assert (!"invalid token in symbol_value_print");
+      abort ();
+    }
+}
+
+/* Grow OBS with a text representation of SYMBOL.  If QUOTE, then
+   surround each definition by LQUOTE and RQUOTE.  If STACK, then
+   append all pushdef'd values, rather than just the top.  */
+void
+m4_symbol_print (m4_symbol *symbol, m4_obstack *obs, bool quote,
+		 const char *lquote, const char *rquote, bool stack)
+{
+  m4_symbol_value *value;
+
+  assert (symbol);
+  assert (obs);
+
+  value = m4_get_symbol_value (symbol);
+  symbol_value_print (value, obs, quote, lquote, rquote);
+  if (stack)
+    {
+      value = VALUE_NEXT (value);
+      while (value)
+	{
+	  obstack_1grow (obs, ',');
+	  obstack_1grow (obs, ' ');
+	  symbol_value_print (value, obs, quote, lquote, rquote);
+	  value = VALUE_NEXT (value);
+	}
+    }
+}
+
 
 /* Define these functions at the end, so that calls in the file use the
    faster macro version from m4module.h.  */
Index: modules/m4.c
===================================================================
RCS file: /sources/m4/m4/modules/m4.c,v
retrieving revision 1.72
diff -u -r1.72 m4.c
--- modules/m4.c	26 Sep 2006 13:19:26 -0000	1.72
+++ modules/m4.c	26 Sep 2006 20:37:23 -0000
@@ -305,16 +305,22 @@
 dump_symbol_CB (m4_symbol_table *ignored, const char *name, m4_symbol *symbol,
 		void *userdata)
 {
+  m4_dump_symbol_data *symbol_data = (m4_dump_symbol_data *) userdata;
+
   assert (name);
   assert (symbol);
+  assert (!m4_is_symbol_value_void (m4_get_symbol_value (symbol)));
 
-  if (!m4_is_symbol_value_void (m4_get_symbol_value (symbol)))
+  if (symbol_data->size == 0)
     {
-      m4_dump_symbol_data *symbol_data = (m4_dump_symbol_data *) userdata;
-
-      obstack_blank (symbol_data->obs, sizeof (const char *));
-      symbol_data->base = (const char **) obstack_base (symbol_data->obs);
-      symbol_data->base[symbol_data->size++] = (const char *) name;
+      obstack_ptr_grow (symbol_data->obs, name);
+      symbol_data->size = (obstack_room (symbol_data->obs)
+			   / sizeof (const char *));
+    }
+  else
+    {
+      obstack_ptr_grow_fast (symbol_data->obs, name);
+      symbol_data->size--;
     }
 
   return NULL;
@@ -326,8 +332,7 @@
 m4_dump_symbols (m4 *context, m4_dump_symbol_data *data, int argc,
 		 m4_symbol_value **argv, bool complain)
 {
-  data->base = (const char **) obstack_base (data->obs);
-  data->size = 0;
+  data->size = obstack_room (data->obs) / sizeof (const char *);
 
   if (argc == 1)
     {
@@ -341,19 +346,17 @@
       for (i = 1; i < argc; i++)
 	{
 	  symbol = m4_symbol_lookup (M4SYMTAB, M4ARG (i));
-	  if (symbol != NULL
-	      && !m4_is_symbol_value_void (m4_get_symbol_value (symbol)))
-	    {
-	      dump_symbol_CB (NULL, M4ARG (i), symbol, data);
-	    }
+	  if (symbol != NULL)
+	    dump_symbol_CB (NULL, M4ARG (i), symbol, data);
 	  else if (complain)
 	    m4_warn (context, 0, _("%s: undefined macro `%s'"),
 		     M4ARG (0), M4ARG (i));
 	}
     }
 
-  obstack_finish (data->obs);
-  qsort ((void*) data->base, data->size, sizeof (const char*), dumpdef_cmp_CB);
+  data->size = obstack_object_size (data->obs) / sizeof (const char *);
+  data->base = (const char **) obstack_finish (data->obs);
+  qsort (data->base, data->size, sizeof (const char *), dumpdef_cmp_CB);
 }
 
 
@@ -362,7 +365,10 @@
 M4BUILTIN_HANDLER (dumpdef)
 {
   m4_dump_symbol_data data;
-  const m4_builtin *bp;
+  bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
+  bool stack = m4_is_debug_bit (context, M4_DEBUG_TRACE_STACK);
+  const char *lquote = m4_get_syntax_lquote (M4SYNTAX);
+  const char *rquote = m4_get_syntax_rquote (M4SYNTAX);
 
   data.obs = obs;
   m4_dump_symbols (context, &data, argc, argv, true);
@@ -370,37 +376,18 @@
   for (; data.size > 0; --data.size, data.base++)
     {
       m4_symbol *symbol = m4_symbol_lookup (M4SYMTAB, data.base[0]);
+      assert (symbol);
 
-      fprintf (stderr, "%s:\t", data.base[0]);
-
-      if (m4_is_symbol_text (symbol))
-	{
-	  if (m4_get_debug_level_opt (context) & M4_DEBUG_TRACE_QUOTE)
-	    fprintf (stderr, "%s%s%s\n",
-		     m4_get_syntax_lquote (M4SYNTAX),
-		     m4_get_symbol_text (symbol),
-		     m4_get_syntax_rquote (M4SYNTAX));
-	  else
-	    fprintf (stderr, "%s\n", m4_get_symbol_text (symbol));
-	}
-      else if (m4_is_symbol_func (symbol))
-	{
-	  bp = m4_builtin_find_by_func (NULL,
-					m4_get_symbol_func (symbol));
-	  assert (bp);
-	  fprintf (stderr, "<%s>\n", bp->name);
-	}
-      else if (m4_is_symbol_placeholder (symbol))
-	{
-	  fprintf (stderr, "<placeholder for %s>\n",
-		   m4_get_symbol_placeholder (symbol));
-	}
-      else
-	{
-	  assert (!"invalid token in builtin_dumpdef");
-	  abort ();
-	}
+      obstack_grow (obs, data.base[0], strlen (data.base[0]));
+      obstack_1grow (obs, ':');
+      obstack_1grow (obs, '\t');
+      m4_symbol_print (symbol, obs, quote, lquote, rquote, stack);
+      obstack_1grow (obs, '\n');
     }
+
+  obstack_1grow (obs, '\0');
+  m4_sysval_flush (context);
+  fputs ((char *) obstack_finish (obs), stderr);
 }
 
 /* The macro "defn" returns the quoted definition of the macro named by
@@ -445,9 +432,9 @@
 
 /* Helper macros for readability.  */
 #if UNIX || defined WEXITSTATUS
-# define M4_SYSVAL_EXITBITS(status)                       \
+# define M4_SYSVAL_EXITBITS(status)			\
    (WIFEXITED (status) ? WEXITSTATUS (status) : 0)
-# define M4_SYSVAL_TERMSIGBITS(status)                    \
+# define M4_SYSVAL_TERMSIGBITS(status)			\
    (WIFSIGNALED (status) ? WTERMSIG (status) << 8 : 0)
 
 #else /* ! UNIX && ! defined WEXITSTATUS */
Index: src/main.c
===================================================================
RCS file: /sources/m4/m4/src/main.c,v
retrieving revision 1.87
diff -u -r1.87 main.c
--- src/main.c	21 Sep 2006 04:12:55 -0000	1.87
+++ src/main.c	26 Sep 2006 20:37:23 -0000
@@ -137,19 +137,20 @@
       fputs (_("\
 \n\
 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\
+  a   show actual arguments in trace\n\
+  c   show before collect, after collect and after call 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 (_("\
-  m   show actions related to modules\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\
+  m   show actions related to modules in debug\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\
+  s   show full stack of pushdef values in dumpdef\n\
+  t   trace all macro calls, regardless of traceon state\n\
+  x   add a unique macro call id in trace, useful with c\n\
   V   shorthand for all of the above flags\n\
 "), stdout);
       fputs (_("\
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.