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_4, updated. branch-cvs-r


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-readonly-58-gd59ecd1
Date: Thu, 21 Feb 2008 14:08:24 +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=d59ecd1edf7a7f56a4f15e2a378a7871a746bc7f

The branch, branch-1_4 has been updated
       via  d59ecd1edf7a7f56a4f15e2a378a7871a746bc7f (commit)
      from  5ca3ef321b2a9328cab37481ebcbdd80c0789e15 (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 d59ecd1edf7a7f56a4f15e2a378a7871a746bc7f
Author: Eric Blake <address@hidden>
Date:   Tue Nov 13 06:55:27 2007 -0700

    Stage 16: cache quotes and improve arg_print.
    
    * src/m4.h (push_wrapup_init, push_wrapup_finish, quote_cache)
    (func_print): New prototypes.
    (arg_print): Adjust prototype.
    * src/builtin.h (func_print): New function.
    (define_user_macro): Slight cleanup.
    (dump_args): Delete, no longer used.
    (m4_errprint): Use arg_print.
    (m4_m4wrap): Handle embedded NUL.
    * src/debug.c (trace_pre): Use arg_print.
    * src/input.c (cached_quote): New variable.
    (push_wrapup): Split...
    (push_wrapup_init, push_wrapup_finish): ...into these.
    (input_print): Use arg_print.
    (quote_cache): New function.
    (pop_input, next_char_1, append_quote_token, set_quote_age):
    Adjust users.
    * src/macro.c (arg_text, make_argv_ref_token): Adjust users.
    (arg_print): Add parameters.
    * examples/null.m4: Test for NUL in m4wrap.
    * examples/null.out: Update expected output.
    * doc/m4.texinfo (Debug Levels): Test --arglength truncation.
    
    (cherry picked from commit 44740d89961c48b712562dfc650dc0cb57898aa0)
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog         |   28 +++++++++++
 doc/m4.texinfo    |   26 ++++++++++-
 examples/null.m4  |  Bin 5764 -> 5747 bytes
 examples/null.out |  Bin 400 -> 402 bytes
 src/builtin.c     |   91 +++++++++++++++++-------------------
 src/debug.c       |   38 ++-------------
 src/input.c       |  132 ++++++++++++++++++++++++++++++++++++++++------------
 src/m4.h          |    8 ++-
 src/macro.c       |   82 +++++++++++++++++++--------------
 9 files changed, 254 insertions(+), 151 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0f4e496..6578264 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,33 @@
 2008-02-21  Eric Blake  <address@hidden>
 
+       Stage 16: cache quotes and improve 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.
+       * src/m4.h (push_wrapup_init, push_wrapup_finish, quote_cache)
+       (func_print): New prototypes.
+       (arg_print): Adjust prototype.
+       * src/builtin.h (func_print): New function.
+       (define_user_macro): Slight cleanup.
+       (dump_args): Delete, no longer used.
+       (m4_errprint): Use arg_print.
+       (m4_m4wrap): Handle embedded NUL.
+       * src/debug.c (trace_pre): Use arg_print.
+       * src/input.c (cached_quote): New variable.
+       (push_wrapup): Split...
+       (push_wrapup_init, push_wrapup_finish): ...into these.
+       (input_print): Use arg_print.
+       (quote_cache): New function.
+       (pop_input, next_char_1, append_quote_token, set_quote_age):
+       Adjust users.
+       * src/macro.c (arg_text, make_argv_ref_token): Adjust users.
+       (arg_print): Add parameters.
+       * examples/null.m4: Test for NUL in m4wrap.
+       * examples/null.out: Update expected output.
+       * doc/m4.texinfo (Debug Levels): Test --arglength truncation.
+
        Fix out-of-bounds read for sanitized macro names, from 2008-02-06.
        * src/m4.c (m4_verror_at_line): Properly terminate the string.
        Reported by Ralf Wildenhues.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 56445c0..2a549dd 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -3466,7 +3466,8 @@ following:
 In trace output, show the actual arguments that were collected before
 invoking the macro.  This applies to all macro calls if the @samp{t}
 flag is used, otherwise only the macros covered by calls of
address@hidden
address@hidden  Arguments are subject to length truncation specified by
+the command line option @option{--arglength} (or @option{-l}).
 
 @item c
 In trace output, show several trace lines for each macro call.  A line
@@ -3477,7 +3478,9 @@ after the call has completed.
 @item e
 In trace output, show the expansion of each macro call, if it is not
 void.  This applies to all macro calls if the @samp{t} flag is used,
-otherwise only the macros covered by calls of @code{traceon}.
+otherwise only the macros covered by calls of @code{traceon}.  The
+expansion is subject to length truncation specified by the command line
+option @option{--arglength} (or @option{-l}).
 
 @item f
 In debug and trace output, include the name of the current input file in
@@ -3557,6 +3560,25 @@ foo
 @result{}FOO
 @end example
 
+The following example demonstrates the behavior of length truncation,
+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
+$ @kbd{m4 -d -l 6}
+define(`echo', `$@@')debugmode(`+t')
address@hidden
+echo(`1', `long string')
address@hidden: -1- echo(`1', `long s...') -> ``1',`l...'
address@hidden,long string
+indir(`echo', defn(`changequote'))
address@hidden: -2- defn(`change...')
address@hidden: -1- indir(`echo', <changequote>) -> ``''
address@hidden
address@hidden example
+
 @node Debug Output
 @section Saving debugging output
 
diff --git a/examples/null.m4 b/examples/null.m4
index 2632522..79f4715 100644
Binary files a/examples/null.m4 and b/examples/null.m4 differ
diff --git a/examples/null.out b/examples/null.out
index c42e03c..aca4b78 100644
Binary files a/examples/null.out and b/examples/null.out differ
diff --git a/src/builtin.c b/src/builtin.c
index d4a0fee..09322ea 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -198,6 +198,28 @@ find_builtin_by_name (const char *name)
       return bp;
   return bp + 1;
 }
+
+/*------------------------------------------------------------------.
+| Print a representation of FUNC to OBS.  If FLATTEN, output QUOTES |
+| around an empty string instead.                                   |
+`------------------------------------------------------------------*/
+void
+func_print (struct obstack *obs, const builtin *func, bool flatten,
+           const string_pair *quotes)
+{
+  assert (func);
+  if (flatten && quotes)
+    {
+      obstack_grow (obs, quotes->str1, quotes->len1);
+      obstack_grow (obs, quotes->str2, quotes->len2);
+    }
+  else if (!flatten)
+    {
+      obstack_1grow (obs, '<');
+      obstack_grow (obs, func->name, strlen (func->name));
+      obstack_1grow (obs, '>');
+    }
+}
 
 /*-------------------------------------------------------------------------.
 | Install a builtin macro with name NAME, bound to the C function given in |
@@ -398,14 +420,15 @@ free_regex (void)
       }
 }
 
-/*-------------------------------------------------------------------------.
-| Define a predefined or user-defined macro, with name NAME, and expansion |
-| TEXT.  MODE destinguishes between the "define" and the "pushdef" case.   |
-| It is also used from main ().                                                
   |
-`-------------------------------------------------------------------------*/
+/*-----------------------------------------------------------------.
+| Define a predefined or user-defined macro, with name NAME of     |
+| length NAME_LEN, and expansion TEXT.  MODE is SYMBOL_INSERT for  |
+| "define" or SYMBOL_PUSHDEF for "pushdef".  This function is also |
+| used from main ().                                               |
+`-----------------------------------------------------------------*/
 
 void
-define_user_macro (const char *name, size_t len, const char *text,
+define_user_macro (const char *name, size_t name_len, const char *text,
                   symbol_lookup mode)
 {
   symbol *s;
@@ -422,24 +445,23 @@ define_user_macro (const char *name, size_t len, const 
char *text,
   if (macro_sequence_inuse && text)
     {
       regoff_t offset = 0;
-      len = strlen (defn);
+      struct re_registers *regs = &macro_sequence_regs;
+      size_t len = strlen (defn);
 
       while (offset < len
             && (offset = re_search (&macro_sequence_buf, defn, len, offset,
-                                    len - offset, &macro_sequence_regs)) >= 0)
+                                    len - offset, regs)) >= 0)
        {
          /* Skip empty matches.  */
-         if (macro_sequence_regs.start[0] == macro_sequence_regs.end[0])
+         if (regs->start[0] == regs->end[0])
            offset++;
          else
            {
-             char tmp;
-             offset = macro_sequence_regs.end[0];
-             tmp = defn[offset];
-             defn[offset] = '\0';
-             m4_warn (0, NULL, _("definition of `%s' contains sequence `%s'"),
-                      name, defn + macro_sequence_regs.start[0]);
-             defn[offset] = tmp;
+             offset = regs->end[0];
+             m4_warn (0, NULL,
+                      _("definition of `%s' contains sequence `%.*s'"),
+                      name, regs->end[0] - regs->start[0],
+                      defn + regs->start[0]);
            }
        }
       if (offset == -2)
@@ -599,34 +621,6 @@ shipout_int (struct obstack *obs, int val)
   obstack_grow (obs, s, strlen (s));
 }
 
-/*------------------------------------------------------------------.
-| Print arguments from the table ARGV to obstack OBS, starting with |
-| START, separated by SEP, and quoted by the current quotes if     |
-| QUOTED is true.                                                  |
-`------------------------------------------------------------------*/
-
-static void
-dump_args (struct obstack *obs, int start, macro_arguments *argv,
-          const char *sep, bool quoted)
-{
-  unsigned int i;
-  bool dump_sep = false;
-  size_t len = strlen (sep);
-  unsigned int argc = arg_argc (argv);
-
-  for (i = start; i < argc; i++)
-    {
-      if (dump_sep)
-       obstack_grow (obs, sep, len);
-      else
-       dump_sep = true;
-      if (quoted)
-       obstack_grow (obs, curr_quote.str1, curr_quote.len1);
-      obstack_grow (obs, ARG (i), ARG_LEN (i));
-      if (quoted)
-       obstack_grow (obs, curr_quote.str2, curr_quote.len2);
-    }
-}
 
 /* The rest of this file is code for builtins and expansion of user
    defined macros.  All the functions for builtins have a prototype as:
@@ -1518,7 +1512,7 @@ m4_errprint (struct obstack *obs, int argc, 
macro_arguments *argv)
 
   if (bad_argc (ARG (0), argc, 1, -1))
     return;
-  dump_args (obs, 1, argv, " ", false);
+  arg_print (obs, argv, 1, NULL, true, " ", NULL, false);
   debug_flush_files ();
   len = obstack_object_size (obs);
   /* The close_stdin module makes it safe to skip checking the return
@@ -1599,12 +1593,13 @@ m4_m4wrap (struct obstack *obs, int argc, 
macro_arguments *argv)
 {
   if (bad_argc (ARG (0), argc, 1, -1))
     return;
+  obs = push_wrapup_init ();
   if (no_gnu_extensions)
     obstack_grow (obs, ARG (1), ARG_LEN (1));
   else
-    dump_args (obs, 1, argv, " ", false);
-  obstack_1grow (obs, '\0');
-  push_wrapup ((char *) obstack_finish (obs));
+    /* TODO - allow builtins, rather than always flattening.  */
+    arg_print (obs, argv, 1, NULL, true, " ", NULL, false);
+  push_wrapup_finish ();
 }
 
 /* Enable tracing of all specified macros, or all, if none is specified.
diff --git a/src/debug.c b/src/debug.c
index d6b2ddc..737ee52 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -359,44 +359,16 @@ trace_prepre (const char *name, int id)
 void
 trace_pre (const char *name, int id, macro_arguments *argv)
 {
-  int i;
-  const builtin *bp;
-  int argc = arg_argc (argv);
-
   trace_header (id);
   trace_format ("%s", name);
 
-  if (argc > 1 && (debug_level & DEBUG_TRACE_ARGS))
+  if (arg_argc (argv) > 1 && (debug_level & DEBUG_TRACE_ARGS))
     {
+      int len = max_debug_argument_length;
       trace_format ("(");
-
-      for (i = 1; i < argc; i++)
-       {
-         if (i != 1)
-           trace_format (", ");
-
-         switch (arg_type (argv, i))
-           {
-           case TOKEN_TEXT:
-             trace_format ("%l%S%r", ARG (i));
-             break;
-
-           case TOKEN_FUNC:
-             bp = find_builtin_by_addr (arg_func (argv, i));
-             if (bp == NULL)
-               {
-                 assert (!"trace_pre");
-                 abort ();
-               }
-             trace_format ("<%s>", bp->name);
-             break;
-
-           default:
-             assert (!"trace_pre");
-             abort ();
-           }
-
-       }
+      arg_print (&trace, argv, 1,
+                (debug_level & DEBUG_TRACE_QUOTE) ? &curr_quote : NULL,
+                false, ", ", &len, true);
       trace_format (")");
     }
 
diff --git a/src/input.c b/src/input.c
index 5c3b345..bbd50f4 100644
--- a/src/input.c
+++ b/src/input.c
@@ -42,14 +42,14 @@
    loops (e.g. "define(`f',`m4wrap(`f')')f"), without memory leaks.
 
    Pushing new input on the input stack is done by push_file (),
-   push_string (), push_wrapup () (for wrapup text), and push_macro ()
-   (for macro definitions).  Because macro expansion needs direct
-   access to the current input obstack (for optimization), push_string
-   () is split in two functions, push_string_init (), which returns a
-   pointer to the current input stack, and push_string_finish (),
-   which returns a pointer to the final text.  The input_block *next
-   is used to manage the coordination between the different push
-   routines.
+   push_string (), push_wrapup_init/push_wrapup_finish () (for wrapup
+   text), and push_macro () (for macro definitions).  Because macro
+   expansion needs direct access to the current input obstack (for
+   optimization), push_string () is split in two functions,
+   push_string_init (), which returns a pointer to the current input
+   stack, and push_string_finish (), which returns a pointer to the
+   final text.  The input_block *next is used to manage the
+   coordination between the different push routines.
 
    The current file and line number are stored in two global
    variables, for use by the error handling functions in m4.c.  Macro
@@ -185,6 +185,9 @@ static struct re_registers regs;
    context.  */
 static unsigned int current_quote_age;
 
+/* Cache a quote pair.  See quote_cache.  */
+static string_pair *cached_quote;
+
 static bool pop_input (bool);
 static void set_quote_age (void);
 
@@ -500,17 +503,14 @@ push_string_finish (void)
   return ret;
 }
 
-/*------------------------------------------------------------------.
-| The function 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 push_string () and push_file () will  |
-| operate on wrapup_stack.  Push_wrapup should be done as           |
-| push_string (), but this will suffice, as long as arguments to    |
-| m4_m4wrap () are moderate in size.                                |
-`------------------------------------------------------------------*/
+/*--------------------------------------------------------------.
+| The function push_wrapup_init () returns an obstack ready for |
+| direct expansion of wrapup text, and should be followed by    |
+| push_wrapup_finish ().                                        |
+`--------------------------------------------------------------*/
 
-void
-push_wrapup (const char *s)
+struct obstack *
+push_wrapup_init (void)
 {
   input_block *i;
   i = (input_block *) obstack_alloc (wrapup_stack, sizeof *i);
@@ -518,9 +518,28 @@ push_wrapup (const char *s)
   i->type = INPUT_STRING;
   i->file = current_file;
   i->line = current_line;
-  i->u.u_s.len = strlen (s);
-  i->u.u_s.str = (char *) obstack_copy (wrapup_stack, s, i->u.u_s.len);
   wsp = i;
+  return wrapup_stack;
+}
+
+/*---------------------------------------------------------------.
+| After pushing wrapup text, push_wrapup_finish () completes the |
+| bookkeeping.                                                   |
+`---------------------------------------------------------------*/
+void
+push_wrapup_finish (void)
+{
+  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);
+    }
 }
 
 
@@ -607,6 +626,7 @@ pop_input (bool cleanup)
       abort ();
     }
   obstack_free (current_input, isp);
+  cached_quote = NULL;
   next = NULL;                 /* might be set in push_string_init () */
 
   isp = tmp;
@@ -674,13 +694,7 @@ input_print (struct obstack *obs, const input_block *input)
       obstack_1grow (obs, '>');
       break;
     case INPUT_MACRO:
-      {
-       const builtin *bp = find_builtin_by_addr (input->u.func);
-       assert (bp);
-       obstack_1grow (obs, '<');
-       obstack_grow (obs, bp->name, strlen (bp->name));
-       obstack_1grow (obs, '>');
-      }
+      func_print (obs, find_builtin_by_addr (input->u.func), false, NULL);
       break;
     case INPUT_CHAIN:
       chain = input->u.u_c.chain;
@@ -696,7 +710,9 @@ input_print (struct obstack *obs, const input_block *input)
            case CHAIN_ARGV:
              assert (!chain->u.u_a.comma);
              if (arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
-                            chain->u.u_a.quotes, &maxlen))
+                            quote_cache (NULL, chain->quote_age,
+                                         chain->u.u_a.quotes),
+                            chain->u.u_a.flatten, NULL, &maxlen, false))
                return;
              break;
            default:
@@ -783,7 +799,9 @@ peek_input (bool allow_argv)
                     argument from argv.  */
                  push_string_init ();
                  push_arg_quote (current_input, chain->u.u_a.argv,
-                                 chain->u.u_a.index, chain->u.u_a.quotes);
+                                 chain->u.u_a.index,
+                                 quote_cache (NULL, chain->quote_age,
+                                              chain->u.u_a.quotes));
                  chain->u.u_a.index++;
                  chain->u.u_a.comma = true;
                  push_string_finish ();
@@ -911,7 +929,9 @@ next_char_1 (bool allow_quote)
                     argument from argv.  */
                  push_string_init ();
                  push_arg_quote (current_input, chain->u.u_a.argv,
-                                 chain->u.u_a.index, chain->u.u_a.quotes);
+                                 chain->u.u_a.index,
+                                 quote_cache (NULL, chain->quote_age,
+                                              chain->u.u_a.quotes));
                  chain->u.u_a.index++;
                  chain->u.u_a.comma = true;
                  push_string_finish ();
@@ -1007,7 +1027,9 @@ append_quote_token (struct obstack *obs, token_data *td)
   if (src_chain->type == CHAIN_ARGV)
     {
       arg_print (obs, src_chain->u.u_a.argv, src_chain->u.u_a.index,
-                src_chain->u.u_a.quotes, NULL);
+                quote_cache (NULL, src_chain->quote_age,
+                             src_chain->u.u_a.quotes),
+                src_chain->u.u_a.flatten, NULL, NULL, false);
       arg_adjust_refcount (src_chain->u.u_a.argv, false);
       return;
     }
@@ -1366,6 +1388,7 @@ set_quote_age (void)
                         | (*curr_quote.str2 & 0xff));
   else
     current_quote_age = 0;
+  cached_quote = NULL;
 }
 
 /* Return the current quote age.  Each non-trivial changequote alters
@@ -1391,6 +1414,53 @@ safe_quotes (void)
 {
   return current_quote_age != 0;
 }
+
+/* Interface for caching frequently used quote pairs, 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
+   &curr_quote; 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 string_pair *
+quote_cache (struct obstack *obs, unsigned int age, const string_pair *quotes)
+{
+  static char lquote[2];
+  static char rquote[2];
+  static string_pair simple = {lquote, 1, rquote, 1};
+
+  /* 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
+     (since changequote will invalidate the original), but we might as
+     well cache that copy (in case the current expansion contains more
+     than one instance of $@).  */
+  if (!quotes)
+    return NULL;
+  if (age)
+    {
+      *lquote = (age >> 8) & 0xff;
+      *rquote = age & 0xff;
+      return &simple;
+    }
+  if (!obs)
+    return quotes;
+  assert (next && quotes == &curr_quote);
+  if (!cached_quote)
+    {
+      assert (obs == current_input && obstack_object_size (obs) == 0);
+      cached_quote = (string_pair *) obstack_copy (obs, quotes,
+                                                  sizeof *quotes);
+      cached_quote->str1 = (char *) obstack_copy0 (obs, quotes->str1,
+                                                  quotes->len1);
+      cached_quote->str2 = (char *) obstack_copy0 (obs, quotes->str2,
+                                                  quotes->len2);
+    }
+  return cached_quote;
+}
 
 
 /*--------------------------------------------------------------------.
diff --git a/src/m4.h b/src/m4.h
index e1da7a7..0c2a8c8 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -386,7 +386,8 @@ void push_macro (builtin_func *);
 struct obstack *push_string_init (void);
 bool push_token (token_data *, int, bool);
 const input_block *push_string_finish (void);
-void push_wrapup (const char *);
+struct obstack *push_wrapup_init (void);
+void push_wrapup_finish (void);
 bool pop_wrapup (void);
 void input_print (struct obstack *, const input_block *);
 
@@ -410,6 +411,8 @@ void set_word_regexp (const char *, const char *);
 #endif
 unsigned int quote_age (void);
 bool safe_quotes (void);
+const string_pair *quote_cache (struct obstack *, unsigned int,
+                               const string_pair *);
 
 /* File: output.c --- output functions.  */
 extern int current_diversion;
@@ -494,7 +497,7 @@ size_t arg_len (macro_arguments *, unsigned int);
 builtin_func *arg_func (macro_arguments *, unsigned int);
 struct obstack *arg_scratch (void);
 bool arg_print (struct obstack *, macro_arguments *, unsigned int,
-               const string_pair *, int *);
+               const string_pair *, bool, const char *, int *, bool);
 macro_arguments *make_argv_ref (macro_arguments *, const char *, size_t,
                                bool, bool);
 void push_arg (struct obstack *, macro_arguments *, unsigned int);
@@ -553,6 +556,7 @@ const char *ntoa (int32_t, int);
 
 const builtin *find_builtin_by_addr (builtin_func *);
 const builtin *find_builtin_by_name (const char *);
+void func_print (struct obstack *, const builtin *, bool, const string_pair *);
 
 /* File: path.c  --- path search for include files.  */
 
diff --git a/src/macro.c b/src/macro.c
index 8b85cf6..8b7e303 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -911,7 +911,9 @@ arg_text (macro_arguments *argv, unsigned int index)
              break;
            case CHAIN_ARGV:
              arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
-                        chain->u.u_a.quotes, NULL);
+                        quote_cache (NULL, chain->quote_age,
+                                     chain->u.u_a.quotes),
+                        chain->u.u_a.flatten, NULL, NULL, false);
              break;
            default:
              assert (!"arg_text");
@@ -1097,50 +1099,70 @@ arg_scratch (void)
 
 /* 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.  */
+   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.  */
 bool
 arg_print (struct obstack *obs, macro_arguments *argv, unsigned int index,
-          const string_pair *quotes, int *max_len)
+          const string_pair *quotes, bool flatten, const char *sep,
+          int *max_len, bool quote_each)
 {
   int len = max_len ? *max_len : INT_MAX;
   unsigned int i;
   token_data *token;
   token_chain *chain;
-  bool comma = false;
-
+  bool use_sep = false;
+  bool done;
+  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 && obstack_print (obs, ",", 1, &len))
+      if (quote_each && max_len)
+       len = *max_len;
+      if (use_sep && obstack_print (obs, sep, sep_len, plen))
        return true;
-      else
-       comma = true;
+      use_sep = true;
       token = arg_token (argv, i, NULL);
-      if (quotes && obstack_print (obs, quotes->str1, quotes->len1, &len))
-       return true;
       switch (TOKEN_DATA_TYPE (token))
        {
        case TOKEN_TEXT:
+         if (quotes && obstack_print (obs, quotes->str1, quotes->len1, plen))
+           return true;
          if (obstack_print (obs, TOKEN_DATA_TEXT (token),
-                            TOKEN_DATA_LEN (token), &len))
+                            TOKEN_DATA_LEN (token), &len) && !quote_each)
+           return true;
+         if (quotes && obstack_print (obs, quotes->str2, quotes->len2, plen))
            return true;
          break;
        case TOKEN_COMP:
+         if (quotes && obstack_print (obs, quotes->str1, quotes->len1, plen))
+           return true;
          chain = token->u.u_c.chain;
-         while (chain)
+         done = false;
+         while (chain && !done)
            {
              switch (chain->type)
                {
                case CHAIN_STR:
                  if (obstack_print (obs, chain->u.u_s.str, chain->u.u_s.len,
                                     &len))
-                   return true;
+                   done = true;
                  break;
                case CHAIN_ARGV:
                  if (arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
-                                chain->u.u_a.quotes, &len))
-                   return true;
+                                quote_cache (NULL, chain->quote_age,
+                                             chain->u.u_a.quotes),
+                                flatten, NULL, &len, false))
+                   done = true;
                  break;
                default:
                  assert (!"arg_print");
@@ -1148,16 +1170,19 @@ arg_print (struct obstack *obs, macro_arguments *argv, 
unsigned int index,
                }
              chain = chain->next;
            }
+         if (done && !quote_each)
+           return true;
+         if (quotes && obstack_print (obs, quotes->str2, quotes->len2, plen))
+           return true;
          break;
        case TOKEN_FUNC:
-         /* TODO - support func.  */
+         func_print (obs, find_builtin_by_addr (TOKEN_DATA_FUNC (token)),
+                     flatten, quotes);
+         break;
        default:
          assert (!"arg_print");
          abort ();
        }
-      if (quotes && obstack_print (obs, quotes->str2, quotes->len2,
-                                  &len))
-       return true;
     }
   if (max_len)
     *max_len = len;
@@ -1201,20 +1226,7 @@ make_argv_ref_token (token_data *token, struct obstack 
*obs, int 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 a subsequent
-        changequote may take effect before the $@ ref is
-        rescanned.  */
-      /* TODO - optimize when quote_age is nonzero.  */
-      string_pair *tmp = (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 = quote_cache (obs, chain->quote_age, quotes);
   return token;
 }
 


hooks/post-receive
--
GNU M4 source repository




reply via email to

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