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-71-


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, master, updated. cvs-readonly-71-gdef1f82
Date: Thu, 21 Feb 2008 14:08:31 +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=def1f82375ed7f310bdd8d8e1ce0c2cd9c64e2c6

The branch, master has been updated
       via  def1f82375ed7f310bdd8d8e1ce0c2cd9c64e2c6 (commit)
      from  50fe32db83b154f2dae2f03a71a1049050a43ebe (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 def1f82375ed7f310bdd8d8e1ce0c2cd9c64e2c6
Author: Eric Blake <address@hidden>
Date:   Wed Feb 20 21:37:30 2008 -0700

    Stage 16: cache quotes and improve m4_arg_print.
    
    * m4/m4module.h (m4_symbol_value_print, m4_symbol_print)
    (m4_arg_print): Adjust prototypes.
    (m4_dump_args): Delete.
    (m4_push_wrapup): Split...
    (m4_push_wrapup_init, m4_push_wrapup_finish): ...into these
    prototypes.
    * m4/m4private.h (struct m4_syntax_table): Add cached_quote
    member.
    (m4__quote_cache, m4__quote_uncache): New prototypes.
    * m4/syntax.c (m4_syntax_create): Initialize the cache.
    (m4__quote_cache): New function.
    (m4_set_syntax): Update caller.
    * m4/symtab.c (m4_symbol_value_print): Add parameter.
    (m4_symbol_print, dump_symbol_CB): Adjust all callers.
    * m4/utility.c (m4_dump_args): Delete; callers should use
    m4_arg_print instead.
    * m4/input.c (m4_push_wrapup_init, m4_push_wrapup_finish): Split
    implementation, and allow embedded NUL.
    (m4_print_token, pop_input, composite_print, composite_peek):
    (composite_read, append_quote_token): Adjust all callers.
    * m4/macro.c (trace_prepre, m4_arg_text, make_argv_ref):
    Likewise.
    (m4_arg_print): Add parameters.
    (trace_pre): Rewrite in terms of m4_arg_print.
    * modules/m4.c (errprint): Likewise.
    (m4wrap): Rewrite to allow embedded NUL.
    (dumpdef): Adjust caller.
    * doc/m4.texinfo (Debuglen): Enhance debuglen test.
    * tests/null.m4: Test for NUL in m4wrap.
    * tests/null.out: Update expected output.
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog      |   37 +++++++++++++++++++++
 doc/m4.texinfo |   18 +++++++---
 m4/input.c     |   77 +++++++++++++++++++++++++++++--------------
 m4/m4module.h  |   19 +++++------
 m4/m4private.h |   16 +++++++++
 m4/macro.c     |   99 +++++++++++++++++++++++++++-----------------------------
 m4/symtab.c    |   78 +++++++++++++++++++++++++++++++-------------
 m4/syntax.c    |   49 +++++++++++++++++++++++++++
 m4/utility.c   |   25 --------------
 modules/m4.c   |   15 ++++----
 tests/null.m4  |  Bin 6508 -> 6491 bytes
 tests/null.out |  Bin 400 -> 402 bytes
 12 files changed, 287 insertions(+), 146 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d0f4e27..b5ae203 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,42 @@
 2008-02-20  Eric Blake  <address@hidden>
 
+       Stage 16: cache quotes and improve m4_arg_print.
+       Cache rather than always copying quotes when pushing $@ refs; in
+       particular, reconstruct single-byte quotes on the fly.  Allow NUL
+       through m4wrap.  Improve sharing of code that prints arguments.
+       Memory impact: slight improvement, due to cached quotes.
+       Speed impact: slight improvement, due to less copying.
+       * m4/m4module.h (m4_symbol_value_print, m4_symbol_print)
+       (m4_arg_print): Adjust prototypes.
+       (m4_dump_args): Delete.
+       (m4_push_wrapup): Split...
+       (m4_push_wrapup_init, m4_push_wrapup_finish): ...into these
+       prototypes.
+       * m4/m4private.h (struct m4_syntax_table): Add cached_quote
+       member.
+       (m4__quote_cache, m4__quote_uncache): New prototypes.
+       * m4/syntax.c (m4_syntax_create): Initialize the cache.
+       (m4__quote_cache): New function.
+       (m4_set_syntax): Update caller.
+       * m4/symtab.c (m4_symbol_value_print): Add parameter.
+       (m4_symbol_print, dump_symbol_CB): Adjust all callers.
+       * m4/utility.c (m4_dump_args): Delete; callers should use
+       m4_arg_print instead.
+       * m4/input.c (m4_push_wrapup_init, m4_push_wrapup_finish): Split
+       implementation, and allow embedded NUL.
+       (m4_print_token, pop_input, composite_print, composite_peek):
+       (composite_read, append_quote_token): Adjust all callers.
+       * m4/macro.c (trace_prepre, m4_arg_text, make_argv_ref):
+       Likewise.
+       (m4_arg_print): Add parameters.
+       (trace_pre): Rewrite in terms of m4_arg_print.
+       * modules/m4.c (errprint): Likewise.
+       (m4wrap): Rewrite to allow embedded NUL.
+       (dumpdef): Adjust caller.
+       * doc/m4.texinfo (Debuglen): Enhance debuglen test.
+       * tests/null.m4: Test for NUL in m4wrap.
+       * tests/null.out: Update expected output.
+
        Fix out-of-bounds read for sanitized macro names, from 2008-02-06.
        * m4/utility.c (m4_verror_at_line): Properly terminate the string.
        Reported by Ralf Wildenhues.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 5ed20ea..ffc1949 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -3860,17 +3860,25 @@ parsed as an integer.
 The macro @code{debuglen} is recognized only with parameters.
 @end deffn
 
address@hidden options: -l4 -techo
+The following example demonstrates the behavior of length truncation.
+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 -techo -tdefn
 @example
-$ @kbd{m4 -d -l 4 -t echo}
+$ @kbd{m4 -d -l 6 -t echo -t defn}
 debuglen(`oops')
 @error{}m4:stdin:1: Warning: debuglen: non-numeric argument `oops'
 @result{}
 define(`echo', `$@@')
 @result{}
-echo(`long string')
address@hidden: -1- echo(`long...') -> ``lon...'
address@hidden string
+echo(`1', `long string')
address@hidden: -1- echo(`1', `long s...') -> ``1',`l...'
address@hidden,long string
+echo(defn(`changequote'))
address@hidden: -2- defn(`change...') -> <changequote>
address@hidden: -1- echo(`') -> ``''
address@hidden
 debuglen
 @result{}debuglen
 debuglen(`0')
diff --git a/m4/input.c b/m4/input.c
index b5d50a1..381f38d 100644
--- a/m4/input.c
+++ b/m4/input.c
@@ -60,7 +60,7 @@
    "wrapup_stack" to "current_input" can continue indefinitely, even
    generating infinite loops (e.g. "define(`f',`m4wrap(`f')')f"),
    without memory leaks.  Adding wrapped data is done through
-   m4_push_wrapup().
+   m4_push_wrapup_init/m4_push_wrapup_finish().
 
    Pushing new input on the input stack is done by m4_push_file(), the
    conceptual m4_push_string(), and m4_push_builtin() (for builtin
@@ -124,7 +124,8 @@ static      bool    consume_syntax          (m4 *, 
m4_obstack *, unsigned int);
 #ifdef DEBUG_INPUT
 # include "quotearg.h"
 
-static int m4_print_token (const char *, m4__token_type, m4_symbol_value *);
+static int m4_print_token (m4 *, const char *, m4__token_type,
+                          m4_symbol_value *);
 #endif
 
 /* Vtable of callbacks for each input method.  */
@@ -753,7 +754,10 @@ composite_peek (m4_input_block *me, m4 *context, bool 
allow_argv)
             argv.  */
          m4_push_string_init (context);
          m4__push_arg_quote (context, current_input, chain->u.u_a.argv,
-                             chain->u.u_a.index, chain->u.u_a.quotes);
+                             chain->u.u_a.index,
+                             m4__quote_cache (M4SYNTAX, NULL,
+                                              chain->quote_age,
+                                              chain->u.u_a.quotes));
          chain->u.u_a.index++;
          chain->u.u_a.comma = true;
          m4_push_string_finish ();
@@ -804,7 +808,10 @@ composite_read (m4_input_block *me, m4 *context, bool 
allow_quote, bool safe)
             argv.  */
          m4_push_string_init (context);
          m4__push_arg_quote (context, current_input, chain->u.u_a.argv,
-                             chain->u.u_a.index, chain->u.u_a.quotes);
+                             chain->u.u_a.index,
+                             m4__quote_cache (M4SYNTAX, NULL,
+                                              chain->quote_age,
+                                              chain->u.u_a.quotes));
          chain->u.u_a.index++;
          chain->u.u_a.comma = true;
          m4_push_string_finish ();
@@ -898,8 +905,12 @@ composite_print (m4_input_block *me, m4 *context, 
m4_obstack *obs)
          break;
        case M4__CHAIN_ARGV:
          assert (!chain->u.u_a.comma);
-         if (m4_arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
-                           chain->u.u_a.quotes, &maxlen, module))
+         if (m4_arg_print (context, obs, chain->u.u_a.argv,
+                           chain->u.u_a.index,
+                           m4__quote_cache (M4SYNTAX, NULL, chain->quote_age,
+                                            chain->u.u_a.quotes),
+                           chain->u.u_a.flatten, NULL, &maxlen, false,
+                           module))
            done = true;
          break;
        default:
@@ -965,16 +976,13 @@ m4_input_print (m4 *context, m4_obstack *obs, 
m4_input_block *input)
     }
 }
 
-/* The function m4_push_wrapup () pushes a string on the wrapup stack.
-   When the normal input stack gets empty, the wrapup stack will become
-   the input stack, and m4_push_string () and m4_push_file () will
-   operate on wrapup_stack.  M4_push_wrapup should be done as
-   m4_push_string (), but this will suffice, as long as arguments to
-   m4_m4wrap () are moderate in size.
+/* The function m4_push_wrapup_init () returns an obstack ready for
+   direct expansion of wrapup text, and should be followed by
+   m4_push_wrapup_finish ().
 
    FIXME - we should allow pushing builtins as well as text.  */
-void
-m4_push_wrapup (m4 *context, const char *s)
+m4_obstack *
+m4_push_wrapup_init (m4 *context)
 {
   m4_input_block *i;
 
@@ -984,11 +992,25 @@ m4_push_wrapup (m4 *context, const char *s)
   i->funcs = &string_funcs;
   i->file = m4_get_current_file (context);
   i->line = m4_get_current_line (context);
-
-  i->u.u_s.len = strlen (s);
-  i->u.u_s.str = obstack_copy (wrapup_stack, s, i->u.u_s.len);
-
   wsp = i;
+  return wrapup_stack;
+}
+
+/* After pushing wrapup text, this completes the bookkeeping.  */
+void
+m4_push_wrapup_finish (void)
+{
+  m4_input_block *i = wsp;
+  if (obstack_object_size (wrapup_stack) == 0)
+    {
+      wsp = i->prev;
+      obstack_free (wrapup_stack, i);
+    }
+  else
+    {
+      i->u.u_s.len = obstack_object_size (wrapup_stack);
+      i->u.u_s.str = (char *) obstack_finish (wrapup_stack);
+    }
 }
 
 
@@ -1010,6 +1032,7 @@ pop_input (m4 *context, bool cleanup)
   if (tmp != NULL)
     {
       obstack_free (current_input, isp);
+      m4__quote_uncache (M4SYNTAX);
       next = NULL;     /* might be set in m4_push_string_init () */
     }
 
@@ -1099,8 +1122,11 @@ append_quote_token (m4 *context, m4_obstack *obs, 
m4_symbol_value *value)
   /* TODO preserve $@ through quotes.  */
   if (src_chain->type == M4__CHAIN_ARGV)
     {
-      m4_arg_print (obs, src_chain->u.u_a.argv, src_chain->u.u_a.index,
-                   src_chain->u.u_a.quotes, NULL, false);
+      m4_arg_print (context, obs, src_chain->u.u_a.argv,
+                   src_chain->u.u_a.index,
+                   m4__quote_cache (M4SYNTAX, NULL, src_chain->quote_age,
+                                    src_chain->u.u_a.quotes),
+                   src_chain->u.u_a.flatten, NULL, NULL, false, false);
       m4__arg_adjust_refcount (context, src_chain->u.u_a.argv, false);
       return;
     }
@@ -1484,7 +1510,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
        init_builtin_token (context, token);
        next_char (context, false, true);
 #ifdef DEBUG_INPUT
-       m4_print_token ("next_token", M4_TOKEN_MACDEF, token);
+       m4_print_token (context, "next_token", M4_TOKEN_MACDEF, token);
 #endif
        return M4_TOKEN_MACDEF;
       }
@@ -1492,7 +1518,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
       {
        init_argv_symbol (context, obs, token);
 #ifdef DEBUG_INPUT
-       m4_print_token ("next_token", M4_TOKEN_ARGV, token);
+       m4_print_token (context, "next_token", M4_TOKEN_ARGV, token);
 #endif
        return M4_TOKEN_ARGV;
       }
@@ -1720,7 +1746,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
   VALUE_MAX_ARGS (token) = -1;
 
 #ifdef DEBUG_INPUT
-  m4_print_token ("next_token", type, token);
+  m4_print_token (context, "next_token", type, token);
 #endif
 
   return type;
@@ -1751,7 +1777,8 @@ m4__next_token_is_open (m4 *context)
 #ifdef DEBUG_INPUT
 
 int
-m4_print_token (const char *s, m4__token_type type, m4_symbol_value *token)
+m4_print_token (m4 *context, const char *s, m4__token_type type,
+               m4_symbol_value *token)
 {
   m4_obstack obs;
   size_t len;
@@ -1802,7 +1829,7 @@ m4_print_token (const char *s, m4__token_type type, 
m4_symbol_value *token)
   if (token)
     {
       obstack_init (&obs);
-      m4_symbol_value_print (token, &obs, NULL, NULL, true);
+      m4_symbol_value_print (context, token, &obs, NULL, false, NULL, true);
       len = obstack_object_size (&obs);
       xfprintf (stderr, "%s\n", quotearg_style_mem (c_maybe_quoting_style,
                                                    obstack_finish (&obs),
diff --git a/m4/m4module.h b/m4/m4module.h
index a807e70..13f5b4b 100644
--- a/m4/m4module.h
+++ b/m4/m4module.h
@@ -126,8 +126,6 @@ struct m4_string_pair
 extern bool    m4_bad_argc        (m4 *, int, const char *, size_t, size_t,
                                    bool);
 extern bool    m4_numeric_arg     (m4 *, const char *, const char *, int *);
-extern void    m4_dump_args       (m4 *, m4_obstack *, size_t,
-                                   m4_macro_args *, const char *, bool);
 extern bool    m4_parse_truth_arg (m4 *, const char *, const char *, bool);
 
 /* Error handling.  */
@@ -248,10 +246,10 @@ extern m4_symbol_value *m4_get_symbol_value         
(m4_symbol*);
 extern bool            m4_get_symbol_traced      (m4_symbol*);
 extern bool            m4_set_symbol_name_traced (m4_symbol_table*,
                                                   const char *, bool);
-extern bool    m4_symbol_value_print   (m4_symbol_value *, m4_obstack *,
-                                        const m4_string_pair *, size_t *,
-                                        bool);
-extern void    m4_symbol_print         (m4_symbol *, m4_obstack *,
+extern bool    m4_symbol_value_print   (m4 *, m4_symbol_value *, m4_obstack *,
+                                        const m4_string_pair *, bool,
+                                        size_t *, bool);
+extern void    m4_symbol_print         (m4 *, m4_symbol *, m4_obstack *,
                                         const m4_string_pair *, bool, size_t,
                                         bool);
 extern bool    m4_symbol_value_groks_macro     (m4_symbol_value *);
@@ -327,9 +325,9 @@ extern bool m4_arg_empty            (m4_macro_args *, 
size_t);
 extern size_t  m4_arg_len              (m4_macro_args *, size_t);
 extern m4_builtin_func *m4_arg_func    (m4_macro_args *, size_t);
 extern m4_obstack *m4_arg_scratch      (m4 *);
-extern bool    m4_arg_print            (m4_obstack *, m4_macro_args *,
-                                        size_t, const m4_string_pair *,
-                                        size_t *, bool);
+extern bool    m4_arg_print            (m4 *, m4_obstack *, m4_macro_args *,
+                                        size_t, const m4_string_pair *, bool,
+                                        const char *, size_t *, bool, bool);
 extern m4_macro_args *m4_make_argv_ref (m4 *, m4_macro_args *, const char *,
                                         size_t, bool, bool);
 extern void    m4_push_arg             (m4 *, m4_obstack *, m4_macro_args *,
@@ -466,7 +464,8 @@ extern      void    m4_push_file    (m4 *, FILE *, const 
char *, bool);
 extern void    m4_push_builtin (m4 *, m4_symbol_value *);
 extern m4_obstack      *m4_push_string_init    (m4 *);
 extern m4_input_block  *m4_push_string_finish  (void);
-extern void    m4_push_wrapup  (m4 *, const char *);
+extern m4_obstack      *m4_push_wrapup_init    (m4 *);
+extern void    m4_push_wrapup_finish           (void);
 extern bool    m4_pop_wrapup   (m4 *);
 extern void    m4_input_print  (m4 *, m4_obstack *, m4_input_block *);
 
diff --git a/m4/m4private.h b/m4/m4private.h
index 2201703..ee6dc6a 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -437,6 +437,14 @@ struct m4_syntax_table {
      these can alter the rescan of a prior parameter in a quoted
      context.  */
   unsigned int quote_age;
+
+  /* Track a cached quote pair on the input obstack.  */
+  m4_string_pair *cached_quote;
+
+  /* Storage for a simple cached quote that can be recreated on the fly.  */
+  char cached_lquote[2];
+  char cached_rquote[2];
+  m4_string_pair cached_simple;
 };
 
 /* Fast macro versions of syntax table accessor functions,
@@ -462,6 +470,14 @@ struct m4_syntax_table {
    age will give the same parse.  */
 #define m4__safe_quotes(S)             (((S)->quote_age & 0xffff) != 0)
 
+/* Set or refresh the cached quote.  */
+extern const m4_string_pair *m4__quote_cache (m4_syntax_table *,
+                                             m4_obstack *obs, unsigned int,
+                                             const m4_string_pair *);
+
+/* Clear the cached quote.  */
+#define m4__quote_uncache(S)           ((S)->cached_quote = NULL)
+
 
 /* --- MACRO MANAGEMENT --- */
 
diff --git a/m4/macro.c b/m4/macro.c
index d6f81d8..2288dea 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -903,8 +903,8 @@ trace_prepre (m4 *context, const char *name, size_t id, 
m4_symbol_value *value)
     quotes = m4_get_syntax_quotes (M4SYNTAX);
   trace_header (context, id);
   trace_format (context, "%s ... = ", name);
-  m4_symbol_value_print (value, &context->trace_messages, quotes, &arg_length,
-                        module);
+  m4_symbol_value_print (context, value, &context->trace_messages, quotes,
+                        false, &arg_length, module);
   trace_flush (context);
 }
 
@@ -913,13 +913,10 @@ trace_prepre (m4 *context, const char *name, size_t id, 
m4_symbol_value *value)
 static void
 trace_pre (m4 *context, size_t id, m4_macro_args *argv)
 {
-  size_t i;
-  size_t argc = m4_arg_argc (argv);
-
   trace_header (context, id);
   trace_format (context, "%s", M4ARG (0));
 
-  if (1 < argc && m4_is_debug_bit (context, M4_DEBUG_TRACE_ARGS))
+  if (1 < m4_arg_argc (argv) && m4_is_debug_bit (context, M4_DEBUG_TRACE_ARGS))
     {
       const m4_string_pair *quotes = NULL;
       size_t arg_length = m4_get_max_debug_arg_length_opt (context);
@@ -928,16 +925,8 @@ trace_pre (m4 *context, size_t id, m4_macro_args *argv)
       if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
        quotes = m4_get_syntax_quotes (M4SYNTAX);
       trace_format (context, "(");
-      for (i = 1; i < argc; i++)
-       {
-         size_t len = arg_length;
-         if (i != 1)
-           trace_format (context, ", ");
-
-         m4_symbol_value_print (m4_arg_symbol (argv, i),
-                                &context->trace_messages, quotes, &len,
-                                module);
-       }
+      m4_arg_print (context, &context->trace_messages, argv, 1, quotes, false,
+                   ", ", &arg_length, true, module);
       trace_format (context, ")");
     }
 }
@@ -1062,8 +1051,8 @@ arg_mark (m4_macro_args *argv)
    Return TOKEN when successful, NULL when wrapping ARGV is trivially
    empty.  */
 static m4_symbol_value *
-make_argv_ref (m4_symbol_value *value, m4_obstack *obs, size_t level,
-              m4_macro_args *argv, size_t index, bool flatten,
+make_argv_ref (m4 *context, m4_symbol_value *value, m4_obstack *obs,
+              size_t level, m4_macro_args *argv, size_t index, bool flatten,
               const m4_string_pair *quotes)
 {
   m4__symbol_chain *chain;
@@ -1093,19 +1082,8 @@ make_argv_ref (m4_symbol_value *value, m4_obstack *obs, 
size_t level,
   chain->u.u_a.flatten = flatten;
   chain->u.u_a.comma = false;
   chain->u.u_a.skip_last = false;
-  if (quotes)
-    {
-      /* Clone the quotes into the obstack, since changequote can
-        occur before this $@ is rescanned.  */
-      /* TODO - optimize when quote_age is nonzero?  */
-      m4_string_pair *tmp = (m4_string_pair *) obstack_copy (obs, quotes,
-                                                            sizeof *quotes);
-      tmp->str1 = (char *) obstack_copy0 (obs, quotes->str1, quotes->len1);
-      tmp->str2 = (char *) obstack_copy0 (obs, quotes->str2, quotes->len2);
-      chain->u.u_a.quotes = tmp;
-    }
-  else
-    chain->u.u_a.quotes = NULL;
+  chain->u.u_a.quotes = m4__quote_cache (M4SYNTAX, obs, chain->quote_age,
+                                        quotes);
   return value;
 }
 
@@ -1218,8 +1196,10 @@ m4_arg_text (m4 *context, m4_macro_args *argv, size_t 
index)
          obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
          break;
        case M4__CHAIN_ARGV:
-         m4_arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
-                       chain->u.u_a.quotes, NULL, false);
+         m4_arg_print (context, obs, chain->u.u_a.argv, chain->u.u_a.index,
+                       m4__quote_cache (M4SYNTAX, NULL, chain->quote_age,
+                                        chain->u.u_a.quotes),
+                       chain->u.u_a.flatten, NULL, NULL, false, false);
          break;
        default:
          assert (!"m4_arg_text");
@@ -1373,32 +1353,48 @@ m4_arg_func (m4_macro_args *argv, size_t index)
 
 /* Dump a representation of ARGV to the obstack OBS, starting with
    argument INDEX.  If QUOTES is non-NULL, each argument is displayed
-   with those quotes.  If MAX_LEN is non-NULL, truncate the output
-   after *MAX_LEN bytes are output and return true; otherwise, return
-   false, and reduce *MAX_LEN by the number of bytes output.  If
-   MODULE, print any details about originating modules.  QUOTES count
-   against the truncation length, but not module names.  */
+   with those quotes.  If FLATTEN, builtins are ignored.  Separate
+   arguments with SEP, which defaults to a comma.  If MAX_LEN is
+   non-NULL, truncate the output after *MAX_LEN bytes are output and
+   return true; otherwise, return false, and reduce *MAX_LEN by the
+   number of bytes output.  If QUOTE_EACH, the truncation length is
+   reset for each argument, quotes do not count against length, and
+   all arguments are printed; otherwise, quotes count against the
+   length and trailing arguments may be discarded.  If MODULE, print
+   any details about originating modules; modules do not count against
+   truncation length.  */
 bool
-m4_arg_print (m4_obstack *obs, m4_macro_args *argv, size_t index,
-             const m4_string_pair *quotes, size_t *max_len, bool module)
+m4_arg_print (m4 *context, m4_obstack *obs, m4_macro_args *argv, size_t index,
+             const m4_string_pair *quotes, bool flatten, const char *sep,
+             size_t *max_len, bool quote_each, bool module)
 {
   size_t len = max_len ? *max_len : SIZE_MAX;
   size_t i;
-  bool comma = false;
+  bool use_sep = false;
+  size_t sep_len;
+  size_t *plen = quote_each ? NULL : &len;
 
+  if (!sep)
+    sep = ",";
+  sep_len = strlen (sep);
   for (i = index; i < argv->argc; i++)
     {
-      if (comma && m4_shipout_string_trunc (obs, ",", 1, NULL, &len))
+      if (quote_each && max_len)
+       len = *max_len;
+      if (use_sep && m4_shipout_string_trunc (obs, sep, sep_len, NULL, plen))
        return true;
-      comma = true;
-      if (quotes && m4_shipout_string_trunc (obs, quotes->str1, quotes->len1,
-                                            NULL, &len))
+      use_sep = true;
+      if (quotes && !quote_each
+         && m4_shipout_string_trunc (obs, quotes->str1, quotes->len1, NULL,
+                                     plen))
        return true;
-      if (m4_symbol_value_print (m4_arg_symbol (argv, i), obs, NULL, &len,
+      if (m4_symbol_value_print (context, m4_arg_symbol (argv, i), obs,
+                                quote_each ? quotes : NULL, flatten, &len,
                                 module))
        return true;
-      if (quotes && m4_shipout_string_trunc (obs, quotes->str2, quotes->len2,
-                                            NULL, &len))
+      if (quotes && !quote_each
+         && m4_shipout_string_trunc (obs, quotes->str2, quotes->len2, NULL,
+                                     plen))
        return true;
     }
   if (max_len)
@@ -1424,8 +1420,8 @@ m4_make_argv_ref (m4 *context, m4_macro_args *argv, const 
char *argv0,
   m4_obstack *obs = m4_arg_scratch (context);
 
   new_value = (m4_symbol_value *) obstack_alloc (obs, sizeof *value);
-  value = make_argv_ref (new_value, obs, context->expansion_level - 1, argv,
-                        index, flatten, NULL);
+  value = make_argv_ref (context, new_value, obs, context->expansion_level - 1,
+                        argv, index, flatten, NULL);
   if (!value)
     {
       obstack_free (obs, new_value);
@@ -1527,7 +1523,8 @@ m4_push_args (m4 *context, m4_obstack *obs, m4_macro_args 
*argv, bool skip,
     }
 
   /* TODO allow shift, $@, to push builtins without flatten.  */
-  value = make_argv_ref (&tmp, obs, -1, argv, i, true, quote ? quotes : NULL);
+  value = make_argv_ref (context, &tmp, obs, -1, argv, i, true,
+                        quote ? quotes : NULL);
   assert (value == &tmp);
   if (len)
     {
diff --git a/m4/symtab.c b/m4/symtab.c
index 9636f9d..dc05c1b 100644
--- a/m4/symtab.c
+++ b/m4/symtab.c
@@ -533,15 +533,16 @@ m4_set_symbol_name_traced (m4_symbol_table *symtab, const 
char *name,
 }
 
 /* Grow OBS with a text representation of VALUE.  If QUOTES, then use
-   it to surround a text definition.  If MAXLEN, then truncate text
+   it to surround a text definition.  If FLATTEN, then flatten builtin
+   macros to the empty string.  If MAXLEN, then truncate text
    definitions to *MAXLEN, and adjust by how many characters are
    printed.  If MODULE, then include which module defined a builtin.
    Return true if the output was truncated.  QUOTES and MODULE do not
    count against the truncation length.  */
 bool
-m4_symbol_value_print (m4_symbol_value *value, m4_obstack *obs,
-                      const m4_string_pair *quotes, size_t *maxlen,
-                      bool module)
+m4_symbol_value_print (m4 *context, m4_symbol_value *value, m4_obstack *obs,
+                      const m4_string_pair *quotes, bool flatten,
+                      size_t *maxlen, bool module)
 {
   const char *text;
   const m4_builtin *bp;
@@ -558,18 +559,42 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack 
*obs,
        result = true;
       break;
     case M4_SYMBOL_FUNC:
-      bp = m4_get_symbol_value_builtin (value);
-      obstack_1grow (obs, '<');
-      obstack_grow (obs, bp->name, strlen (bp->name));
-      obstack_1grow (obs, '>');
+      if (flatten)
+       {
+         if (quotes)
+           {
+             obstack_grow (obs, quotes->str1, quotes->len1);
+             obstack_grow (obs, quotes->str2, quotes->len2);
+           }
+         module = false;
+       }
+      else
+       {
+         bp = m4_get_symbol_value_builtin (value);
+         obstack_1grow (obs, '<');
+         obstack_grow (obs, bp->name, strlen (bp->name));
+         obstack_1grow (obs, '>');
+       }
       break;
     case M4_SYMBOL_PLACEHOLDER:
-      text = m4_get_symbol_value_placeholder (value);
-      obstack_1grow (obs, '<');
-      obstack_1grow (obs, '<');
-      obstack_grow (obs, text, strlen (text));
-      obstack_1grow (obs, '>');
-      obstack_1grow (obs, '>');
+      if (flatten)
+       {
+         if (quotes)
+           {
+             obstack_grow (obs, quotes->str1, quotes->len1);
+             obstack_grow (obs, quotes->str2, quotes->len2);
+           }
+         module = false;
+       }
+      else
+       {
+         text = m4_get_symbol_value_placeholder (value);
+         obstack_1grow (obs, '<');
+         obstack_1grow (obs, '<');
+         obstack_grow (obs, text, strlen (text));
+         obstack_1grow (obs, '>');
+         obstack_1grow (obs, '>');
+       }
       break;
     case M4_SYMBOL_COMP:
       chain = value->u.u_c.chain;
@@ -585,8 +610,13 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack 
*obs,
                result = true;
              break;
            case M4__CHAIN_ARGV:
-             if (m4_arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
-                               chain->u.u_a.quotes, &len, module))
+             if (m4_arg_print (context, obs, chain->u.u_a.argv,
+                               chain->u.u_a.index,
+                               m4__quote_cache (M4SYNTAX, NULL,
+                                                chain->quote_age,
+                                                chain->u.u_a.quotes),
+                               chain->u.u_a.flatten, NULL, &len, false,
+                               module))
                result = true;
              break;
            default:
@@ -623,7 +653,7 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack 
*obs,
    MODULE, then include which module defined a builtin.  QUOTES and
    MODULE do not count toward truncation.  */
 void
-m4_symbol_print (m4_symbol *symbol, m4_obstack *obs,
+m4_symbol_print (m4 *context, m4_symbol *symbol, m4_obstack *obs,
                 const m4_string_pair *quotes, bool stack, size_t arg_length,
                 bool module)
 {
@@ -634,7 +664,7 @@ m4_symbol_print (m4_symbol *symbol, m4_obstack *obs,
   assert (obs);
 
   value = m4_get_symbol_value (symbol);
-  m4_symbol_value_print (value, obs, quotes, &len, module);
+  m4_symbol_value_print (context, value, obs, quotes, false, &len, module);
   if (stack)
     {
       value = VALUE_NEXT (value);
@@ -643,7 +673,8 @@ m4_symbol_print (m4_symbol *symbol, m4_obstack *obs,
          obstack_1grow (obs, ',');
          obstack_1grow (obs, ' ');
          len = arg_length;
-         m4_symbol_value_print (value, obs, quotes, &len, module);
+         m4_symbol_value_print (context, value, obs, quotes, false, &len,
+                                module);
          value = VALUE_NEXT (value);
        }
     }
@@ -820,15 +851,16 @@ m4_set_symbol_value_placeholder (m4_symbol_value *value, 
const char *text)
 static void *dump_symbol_CB    (m4_symbol_table *symtab, const char *name,
                                 m4_symbol *symbol, void *userdata);
 static M4_GNUC_UNUSED void *
-symtab_dump (m4_symbol_table *symtab)
+symtab_dump (m4 *context, m4_symbol_table *symtab)
 {
-  return m4_symtab_apply (symtab, true, dump_symbol_CB, NULL);
+  return m4_symtab_apply (symtab, true, dump_symbol_CB, context);
 }
 
 static void *
 dump_symbol_CB (m4_symbol_table *symtab, const char *name,
-               m4_symbol *symbol, void *ignored)
+               m4_symbol *symbol, void *ptr)
 {
+  m4 *            context      = (m4 *) ptr;
   m4_symbol_value *value       = m4_get_symbol_value (symbol);
   int             flags        = value ? SYMBOL_FLAGS (symbol) : 0;
   m4_module *      module      = value ? SYMBOL_MODULE (symbol) : NULL;
@@ -845,7 +877,7 @@ dump_symbol_CB (m4_symbol_table *symtab, const char *name,
     {
       m4_obstack obs;
       obstack_init (&obs);
-      m4_symbol_value_print (value, &obs, NULL, NULL, true);
+      m4_symbol_value_print (context, value, &obs, NULL, false, NULL, true);
       xfprintf (stderr, "%s", (char *) obstack_finish (&obs));
       obstack_free (&obs, NULL);
     }
diff --git a/m4/syntax.c b/m4/syntax.c
index 115884e..7479388 100644
--- a/m4/syntax.c
+++ b/m4/syntax.c
@@ -160,6 +160,10 @@ m4_syntax_create (void)
 
   /* Set up current table to match default.  */
   m4_set_syntax (syntax, '\0', '\0', NULL);
+  syntax->cached_simple.str1 = syntax->cached_lquote;
+  syntax->cached_simple.len1 = 1;
+  syntax->cached_simple.str2 = syntax->cached_rquote;
+  syntax->cached_simple.len2 = 1;
   return syntax;
 }
 
@@ -420,6 +424,7 @@ m4_set_syntax (m4_syntax_table *syntax, char key, char 
action,
       assert (false);
     }
   set_quote_age (syntax, false, true);
+  m4__quote_uncache (syntax);
   return code;
 }
 
@@ -758,6 +763,50 @@ set_quote_age (m4_syntax_table *syntax, bool reset, bool 
change)
     syntax->quote_age = 0;
 }
 
+/* Interface for caching frequently used quote pairs, independently of
+   the current quote delimiters (for example, consider a text macro
+   expansion that includes several copies of $@), and using AGE for
+   optimization.  If QUOTES is NULL, don't use quoting.  If OBS is
+   non-NULL, AGE should be the current quote age, and QUOTES should be
+   m4_get_syntax_quotes; the return value will be a cached quote pair,
+   where the pointer is valid at least as long as OBS is not reset,
+   but whose contents are only guaranteed until the next changequote
+   or quote_cache.  Otherwise, OBS is NULL, AGE should be the same as
+   before, and QUOTES should be a previously returned cache value;
+   used to refresh the contents of the result.  */
+const m4_string_pair *
+m4__quote_cache (m4_syntax_table *syntax, m4_obstack *obs, unsigned int age,
+                const m4_string_pair *quotes)
+{
+  /* Implementation - if AGE is non-zero, then the implementation of
+     set_quote_age guarantees that we can recreate the return value on
+     the fly; so we use static storage, and the contents must be used
+     immediately.  If AGE is zero, then we must copy QUOTES onto OBS,
+     but we might as well cache that copy.  */
+  if (!quotes)
+    return NULL;
+  if (age)
+    {
+      *syntax->cached_lquote = (age >> 8) & 0xff;
+      *syntax->cached_rquote = age & 0xff;
+      return &syntax->cached_simple;
+    }
+  if (!obs)
+    return quotes;
+  assert (quotes == &syntax->quote);
+  if (!syntax->cached_quote)
+    {
+      assert (obstack_object_size (obs) == 0);
+      syntax->cached_quote = (m4_string_pair *) obstack_copy (obs, quotes,
+                                                             sizeof *quotes);
+      syntax->cached_quote->str1 = (char *) obstack_copy0 (obs, quotes->str1,
+                                                          quotes->len1);
+      syntax->cached_quote->str2 = (char *) obstack_copy0 (obs, quotes->str2,
+                                                          quotes->len2);
+    }
+  return syntax->cached_quote;
+}
+
 
 /* Define these functions at the end, so that calls in the file use the
    faster macro version from m4module.h.  */
diff --git a/m4/utility.c b/m4/utility.c
index 89b4083..0a3296b 100644
--- a/m4/utility.c
+++ b/m4/utility.c
@@ -95,31 +95,6 @@ m4_numeric_arg (m4 *context, const char *caller, const char 
*arg, int *valuep)
   return true;
 }
 
-
-/* Print arguments from the table ARGV to obstack OBS, starting at
-   index START, separated by SEP, and quoted by the current quotes, if
-   QUOTED is true.  */
-void
-m4_dump_args (m4 *context, m4_obstack *obs, size_t start, m4_macro_args *argv,
-             const char *sep, bool quoted)
-{
-  size_t i;
-  size_t len = strlen (sep);
-  bool need_sep = false;
-  size_t argc = m4_arg_argc (argv);
-
-  for (i = start; i < argc; i++)
-    {
-      if (need_sep)
-       obstack_grow (obs, sep, len);
-      else
-       need_sep = true;
-
-      m4_shipout_string (context, obs, M4ARG (i), M4ARGLEN (i), quoted);
-    }
-}
-
-
 /* Parse ARG as a truth value.  If unrecognized, issue a warning on
    behalf of ME and return PREVIOUS; otherwise return the parsed
    value.  */
diff --git a/modules/m4.c b/modules/m4.c
index afb9d0c..eb6540b 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -358,7 +358,8 @@ M4BUILTIN_HANDLER (dumpdef)
       obstack_grow (obs, data.base[0], strlen (data.base[0]));
       obstack_1grow (obs, ':');
       obstack_1grow (obs, '\t');
-      m4_symbol_print (symbol, obs, quotes, stack, arg_length, module);
+      m4_symbol_print (context, symbol, obs, quotes, stack, arg_length,
+                      module);
       obstack_1grow (obs, '\n');
     }
 
@@ -792,7 +793,7 @@ M4BUILTIN_HANDLER (errprint)
   size_t len;
 
   assert (obstack_object_size (obs) == 0);
-  m4_dump_args (context, obs, 1, argv, " ", false);
+  m4_arg_print (context, obs, argv, 1, NULL, true, " ", NULL, false, false);
   m4_sysval_flush (context, false);
   len = obstack_object_size (obs);
   /* The close_stdin module makes it safe to skip checking the return
@@ -845,13 +846,13 @@ M4BUILTIN_HANDLER (m4exit)
    version only the first.  */
 M4BUILTIN_HANDLER (m4wrap)
 {
-  assert (obstack_object_size (obs) == 0);
+  obs = m4_push_wrapup_init (context);
   if (m4_get_posixly_correct_opt (context))
-    m4_shipout_string (context, obs, M4ARG (1), M4ARGLEN (1), false);
+    obstack_grow (obs, M4ARG (1), M4ARGLEN (1));
   else
-    m4_dump_args (context, obs, 1, argv, " ", false);
-  obstack_1grow (obs, '\0');
-  m4_push_wrapup (context, obstack_finish (obs));
+    /* TODO allow pushing builtins.  */
+    m4_arg_print (context, obs, argv, 1, NULL, true, " ", NULL, false, false);
+  m4_push_wrapup_finish ();
 }
 
 /* Enable tracing of all specified macros, or all, if none is specified.
diff --git a/tests/null.m4 b/tests/null.m4
index 2fa38dd..83e7c34 100644
Binary files a/tests/null.m4 and b/tests/null.m4 differ
diff --git a/tests/null.out b/tests/null.out
index c42e03c..aca4b78 100644
Binary files a/tests/null.out and b/tests/null.out differ


hooks/post-receive
--
GNU M4 source repository




reply via email to

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