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-35-ge2b843f
Date: Fri, 21 Dec 2007 05:34:45 +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=e2b843f0aca9e296495f592e39d6a8cec69c6e8a

The branch, branch-1_4 has been updated
       via  e2b843f0aca9e296495f592e39d6a8cec69c6e8a (commit)
      from  c947bf47f48f9132155bc623596771e4a4e3f732 (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 e2b843f0aca9e296495f592e39d6a8cec69c6e8a
Author: Eric Blake <address@hidden>
Date:   Fri Oct 26 09:24:06 2007 -0600

    Stage 9: share rather than copy single-arg refs.
    
    * m4/gnulib-cache.m4: Import quote and memmem modules.
    * src/m4.h (arg_scratch): New prototype.
    * src/input.c (INPUT_INLINE_THRESHOLD): New define.
    (push_token): Use it to inline short text, and save references to
    longer text.
    (input_init, next_token): Simplify obstack handling.
    * src/macro.c (expand_argument): Likewise.
    (expand_macro): Track scratch space.
    (arg_scratch): New function.
    (make_argv_ref): Use it.
    (push_args): Likewise, and simplify comma handling, since most
    separators are short enough to be inlined.
    * src/builtin.c (builtin_init): Avoid cast.
    (m4_errprint, m4_index): Transparently support NUL.
    (m4_translit): Use scratch space, rather than leaking memory on
    expansion stack.
    * doc/m4.texinfo (Syntax): Add new test of embedded NUL.
    * checks/get-them: Extract test that uses external files.
    * checks/check-them: Run the new test.  Use unified diff if
    possible, and force text mode when debugging NUL handling.
    * examples/null.m4: New file.
    * examples/null.out: Likewise.
    * examples/null.err: Likewise.
    * examples/Makefile.am (EXTRA_FILES): Distribute these files.
    * .gitattributes: Treat new files as text, in spite of embedded
    NUL.
    
    (cherry picked from commit a6c94a314afa34958330b719d66c2d4e403a94af)
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog               |   30 +++++++++++++++++++
 checks/check-them       |   30 ++++++++++++++++---
 checks/get-them         |   20 +++++++++++++
 doc/m4.texinfo          |   12 ++++++++
 examples/.gitattributes |    1 +
 examples/Makefile.am    |    3 ++
 examples/null.err       |  Bin 0 -> 18 bytes
 examples/null.m4        |  Bin 0 -> 3671 bytes
 examples/null.out       |  Bin 0 -> 338 bytes
 m4/gnulib-cache.m4      |    4 +-
 src/builtin.c           |   37 ++++++++++-------------
 src/input.c             |   47 +++++++++++++++++++------------
 src/m4.h                |    1 +
 src/macro.c             |   72 ++++++++++++++++++++++++++++------------------
 14 files changed, 183 insertions(+), 74 deletions(-)
 create mode 100644 examples/.gitattributes
 create mode 100644 examples/null.err
 create mode 100644 examples/null.m4
 create mode 100644 examples/null.out

diff --git a/ChangeLog b/ChangeLog
index 2b2a0d0..e6fee41 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,33 @@
+2007-12-21  Eric Blake  <address@hidden>
+
+       Stage 9: share rather than copy single-arg refs.
+       * m4/gnulib-cache.m4: Import quote and memmem modules.
+       * src/m4.h (arg_scratch): New prototype.
+       * src/input.c (INPUT_INLINE_THRESHOLD): New define.
+       (push_token): Use it to inline short text, and save references to
+       longer text.
+       (input_init, next_token): Simplify obstack handling.
+       * src/macro.c (expand_argument): Likewise.
+       (expand_macro): Track scratch space.
+       (arg_scratch): New function.
+       (make_argv_ref): Use it.
+       (push_args): Likewise, and simplify comma handling, since most
+       separators are short enough to be inlined.
+       * src/builtin.c (builtin_init): Avoid cast.
+       (m4_errprint, m4_index): Transparently support NUL.
+       (m4_translit): Use scratch space, rather than leaking memory on
+       expansion stack.
+       * doc/m4.texinfo (Syntax): Add new test of embedded NUL.
+       * checks/get-them: Extract test that uses external files.
+       * checks/check-them: Run the new test.  Use unified diff if
+       possible, and force text mode when debugging NUL handling.
+       * examples/null.m4: New file.
+       * examples/null.out: Likewise.
+       * examples/null.err: Likewise.
+       * examples/Makefile.am (EXTRA_FILES): Distribute these files.
+       * .gitattributes: Treat new files as text, in spite of embedded
+       NUL.
+
 2007-12-18  Eric Blake  <address@hidden>
 
        Stage 8: extend life of references into argv.
diff --git a/checks/check-them b/checks/check-them
index b446f47..daa1b00 100755
--- a/checks/check-them
+++ b/checks/check-them
@@ -27,6 +27,7 @@ xerr=$tmp/m4-xerr
 failed=
 skipped=
 strip_needed=false
+diffopts=-c
 
 # Find out how the executable prints argv[0]
 m4=`m4 --help | sed -e 's/Usage: \(.*\) \[OPTION.*/\1/' \
@@ -49,6 +50,14 @@ if test "x$1" = x-I ; then
   shift; shift
 fi
 
+# Find out if diff supports useful options.
+if diff -u /dev/null /dev/null 2>/dev/null ; then
+  diffopts="-u"
+fi
+if diff -a /dev/null /dev/null 2>/dev/null ; then
+  diffopts="$diffopts -a"
+fi
+
 # Run the tests.
 for file
 do
@@ -77,9 +86,20 @@ do
       ;;
   esac
 
-  sed -e '/^dnl @result{}/!d' -e 's///' -e "s|\.\./examples|$examples|" \
-    "$file" > $xout
-  sed -e '/^dnl @error{}/!d' -e 's///' -e "s|^m4:|$m4:|" "$file" > $xerr
+  xoutfile=`sed -n 's/^dnl @ expected output: //p' "$file"`
+  if test -z "$xoutfile" ; then
+    sed -e '/^dnl @result{}/!d' -e 's///' -e "s|\.\./examples|$examples|" \
+      "$file" > $xout
+  else
+    cp "$examples/$xoutfile" $xout
+  fi
+
+  xerrfile=`sed -n 's/^dnl @ expected error: //p' "$file"`
+  if test -z "$xerrfile" ; then
+    sed -e '/^dnl @error{}/!d' -e 's///' -e "s|^m4:|$m4:|" "$file" > $xerr
+  else
+    cp "$examples/$xerrfile" $xerr
+  fi
 
   # For the benefit of mingw, normalize \r\n line endings
   if $strip_needed ; then
@@ -99,7 +119,7 @@ do
     failed="$failed $file:out"
     echo `sed -e 's/^dnl //' -e 1q $file`
     echo "$file: stdout mismatch"
-    diff $xout $out
+    diff $diffopts $xout $out
   fi
 
   if cmp -s $err $xerr; then
@@ -108,7 +128,7 @@ do
     failed="$failed $file:err"
     echo `sed -e 's/^dnl //' -e 1q $file`
     echo "$file: stderr mismatch"
-    diff $xerr $err
+    diff $diffopts $xerr $err
   fi
 
 done
diff --git a/checks/get-them b/checks/get-them
index 0d3e37b..e034962 100755
--- a/checks/get-them
+++ b/checks/get-them
@@ -16,6 +16,8 @@ BEGIN {
   file = "NONE";
   status = 0;
   options = "";
+  xout = "";
+  xerr = "";
 }
 
 /address@hidden / {
@@ -39,6 +41,8 @@ BEGIN {
   getline;
   status = 0;
   options = "";
+  xout = "";
+  xout = "";
   next;
 }
 
@@ -51,6 +55,16 @@ BEGIN {
   gsub ("@comment options:", "", options);
 }
 
+/address@hidden xout: / {
+  xout = $0;
+  gsub ("@comment xout: ", "", xout);
+}
+
+/address@hidden xerr: / {
+  xerr = $0;
+  gsub ("@comment xerr: ", "", xerr);
+}
+
 /address@hidden/, /address@hidden example$/ {
   if (seq < 0)
     next;
@@ -68,8 +82,14 @@ BEGIN {
           "dnl @ gives unlimited permission to copy and/or distribute it\n"\
           "dnl @ with or without modifications, as long as this notice\n"\
           "dnl @ is preserved.\n", FILENAME, NR, status, options) > file;
+    if (xout)
+       printf("dnl @ expected output: %s\n", xout) > file;
+    if (xerr)
+       printf("dnl @ expected error: %s\n", xerr) > file;
     status = 0;
     options = "";
+    xout = "";
+    xerr = "";
     next;
   }
   if ($0 ~ /address@hidden example$/) {
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index eaec266..bfdb6f2 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -923,6 +923,18 @@ use address@hidden characters in quoted strings 
(@pxref{Changequote}),
 comments (@pxref{Changecom}), and macro names (@pxref{Indir}), with the
 exception of the @sc{nul} character (the zero byte @samp{'\0'}).
 
address@hidden
address@hidden FIXME - each builtin needs to document how it handles NUL, then
address@hidden update the above paragraph to mention that NUL is now handled
address@hidden transparently.  Meanwhile, test that we don't regress.
+
address@hidden xout: null.out
address@hidden xerr: null.err
address@hidden
+include(`null.m4')dnl
address@hidden example
address@hidden ignore
+
 @menu
 * Names::                       Macro names
 * Quoted strings::              Quoting input to @code{m4}
diff --git a/examples/.gitattributes b/examples/.gitattributes
new file mode 100644
index 0000000..b35e74c
--- /dev/null
+++ b/examples/.gitattributes
@@ -0,0 +1 @@
+null.* diff merge
diff --git a/examples/Makefile.am b/examples/Makefile.am
index c1dc522..3450eac 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -45,6 +45,9 @@ indir.m4 \
 loop.m4 \
 misc.m4 \
 multiquotes.m4 \
+null.err \
+null.m4 \
+null.out \
 patsubst.m4 \
 pushpop.m4 \
 quote.m4 \
diff --git a/examples/null.err b/examples/null.err
new file mode 100644
index 0000000..61518e8
Binary files /dev/null and b/examples/null.err differ
diff --git a/examples/null.m4 b/examples/null.m4
new file mode 100644
index 0000000..904a6ef
Binary files /dev/null and b/examples/null.m4 differ
diff --git a/examples/null.out b/examples/null.out
new file mode 100644
index 0000000..6e8a114
Binary files /dev/null and b/examples/null.out differ
diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4
index a89650c..3112f91 100644
--- a/m4/gnulib-cache.m4
+++ b/m4/gnulib-cache.m4
@@ -15,11 +15,11 @@
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --local-dir=local --lib=libm4 
--source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests 
--no-libtool --macro-prefix=M4 assert avltree-oset binary-io clean-temp cloexec 
close-stream closein config-h error fdl fflush flexmember fopen-safer free 
fseeko gendocs getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint 
stdlib-safer strtol unlocked-io verror version-etc version-etc-fsf xalloc 
xprintf xvasprintf-posix
+#   gnulib-tool --import --dir=. --local-dir=local --lib=libm4 
--source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests 
--no-libtool --macro-prefix=M4 assert avltree-oset binary-io clean-temp cloexec 
close-stream closein config-h error fdl fflush flexmember fopen-safer free 
fseeko gendocs getopt gnupload gpl-3.0 memmem mkstemp obstack quote regex 
stdbool stdint stdlib-safer strtol unlocked-io verror version-etc 
version-etc-fsf xalloc xprintf xvasprintf-posix
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([local])
-gl_MODULES([assert avltree-oset binary-io clean-temp cloexec close-stream 
closein config-h error fdl fflush flexmember fopen-safer free fseeko gendocs 
getopt gnupload gpl-3.0 mkstemp obstack regex stdbool stdint stdlib-safer 
strtol unlocked-io verror version-etc version-etc-fsf xalloc xprintf 
xvasprintf-posix])
+gl_MODULES([assert avltree-oset binary-io clean-temp cloexec close-stream 
closein config-h error fdl fflush flexmember fopen-safer free fseeko gendocs 
getopt gnupload gpl-3.0 memmem mkstemp obstack quote regex stdbool stdint 
stdlib-safer strtol unlocked-io verror version-etc version-etc-fsf xalloc 
xprintf xvasprintf-posix])
 gl_AVOID([])
 gl_SOURCE_BASE([lib])
 gl_M4_BASE([m4])
diff --git a/src/builtin.c b/src/builtin.c
index e8edc4b..cb5f274 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -463,9 +463,10 @@ builtin_init (void)
   for (bp = &builtin_tab[0]; bp->name != NULL; bp++)
     if (!no_gnu_extensions || !bp->gnu_extension)
       {
+       size_t len = strlen (bp->name);
        if (prefix_all_builtins)
          {
-           string = (char *) xmalloc (strlen (bp->name) + 4);
+           string = xcharalloc (len + 4);
            strcpy (string, "m4_");
            strcat (string, bp->name);
            define_builtin (string, bp, SYMBOL_INSERT);
@@ -1514,12 +1515,16 @@ m4_mkstemp (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_errprint (struct obstack *obs, int argc, macro_arguments *argv)
 {
+  size_t len;
+
   if (bad_argc (ARG (0), argc, 1, -1))
     return;
   dump_args (obs, 1, argv, " ", false);
-  obstack_1grow (obs, '\0');
   debug_flush_files ();
-  xfprintf (stderr, "%s", (char *) obstack_finish (obs));
+  len = obstack_object_size (obs);
+  /* The close_stdin module makes it safe to skip checking the return
+     value here.  */
+  fwrite (obstack_finish (obs), 1, len, stderr);
   fflush (stderr);
 }
 
@@ -1770,14 +1775,10 @@ m4_index (struct obstack *obs, int argc, 
macro_arguments *argv)
   haystack = ARG (1);
   needle = ARG (2);
 
-  /* Optimize searching for the empty string (always 0) and one byte
-     (strchr tends to be more efficient than strstr).  */
-  if (!needle[0])
-    retval = 0;
-  else if (!needle[1])
-    result = strchr (haystack, *needle);
-  else
-    result = strstr (haystack, needle);
+  /* Rely on the optimizations guaranteed by gnulib's memmem
+     module.  */
+  result = (char *) memmem (haystack, arg_len (argv, 1),
+                           needle, arg_len (argv, 2));
   if (result)
     retval = result - haystack;
 
@@ -1895,19 +1896,13 @@ m4_translit (struct obstack *obs, int argc, 
macro_arguments *argv)
 
   from = ARG (2);
   if (strchr (from, '-') != NULL)
-    {
-      from = expand_ranges (from, obs);
-      if (from == NULL)
-       return;
-    }
+    from = expand_ranges (from, arg_scratch ());
 
   to = ARG (3);
   if (strchr (to, '-') != NULL)
-    {
-      to = expand_ranges (to, obs);
-      if (to == NULL)
-       return;
-    }
+    to = expand_ranges (to, arg_scratch ());
+
+  assert (from && to);
 
   /* Calling strchr(from) for each character in data is quadratic,
      since both strings can be arbitrarily long.  Instead, create a
diff --git a/src/input.c b/src/input.c
index 8386061..1753be2 100644
--- a/src/input.c
+++ b/src/input.c
@@ -64,6 +64,11 @@
 # include "regex.h"
 #endif /* ENABLE_CHANGEWORD */
 
+/* Number of bytes where it is more efficient to inline the reference
+   as a string than it is to track reference bookkeeping for those
+   bytes.  */
+#define INPUT_INLINE_THRESHOLD 16
+
 /* Type of an input block.  */
 enum input_type
 {
@@ -319,18 +324,29 @@ push_string_init (void)
 | gathering input from multiple locations, rather than copying       |
 | everything consecutively onto the input stack.  Must be called     |
 | between push_string_init and push_string_finish.  Return true only |
-| if LEVEL is non-negative, and a reference was created to TOKEN.    |
+| if LEVEL is non-negative, and a reference was created to TOKEN, in |
+| which case, the lifetime of TOKEN and its contents must last as    |
+| long as the input engine can parse references to it.               |
 `-------------------------------------------------------------------*/
 bool
 push_token (token_data *token, int level)
 {
   token_chain *chain;
+  bool result = false;
 
   assert (next);
   /* TODO - also accept TOKEN_COMP chains.  */
   assert (TOKEN_DATA_TYPE (token) == TOKEN_TEXT);
-  if (TOKEN_DATA_LEN (token) == 0)
-    return false;
+
+  /* Speed consideration - for short enough tokens, the speed and
+     memory overhead of parsing another INPUT_CHAIN link outweighs the
+     time to inline the token text.  */
+  if (TOKEN_DATA_LEN (token) <= INPUT_INLINE_THRESHOLD)
+    {
+      obstack_grow (current_input, TOKEN_DATA_TEXT (token),
+                   TOKEN_DATA_LEN (token));
+      return false;
+    }
 
   if (next->type == INPUT_STRING)
     {
@@ -345,21 +361,18 @@ push_token (token_data *token, int level)
     next->u.u_c.chain = chain;
   next->u.u_c.end = chain;
   chain->next = NULL;
-  if (level >= 0)
-    /* TODO - use token as-is, rather than copying data.  This implies
-       lengthening lifetime of $@ arguments until the rescan is
-       complete, rather than the current approach of freeing them
-       during expand_macro.  */
-    chain->str = (char *) obstack_copy (current_input, TOKEN_DATA_TEXT (token),
-                                       TOKEN_DATA_LEN (token));
-  else
-    chain->str = TOKEN_DATA_TEXT (token);
+  chain->str = TOKEN_DATA_TEXT (token);
   chain->len = TOKEN_DATA_LEN (token);
-  chain->level = -1;
+  chain->level = level;
   chain->argv = NULL;
   chain->index = 0;
   chain->flatten = false;
-  return false; /* No reference exists when text is copied.  */
+  if (level >= 0)
+    {
+      adjust_refcount (level, true);
+      result = true;
+    }
+  return result;
 }
 
 /*-------------------------------------------------------------------.
@@ -897,8 +910,7 @@ input_init (void)
      will always work even if the first token parsed spills to a new
      chunk.  */
   obstack_init (&token_stack);
-  obstack_alloc (&token_stack, 1);
-  token_bottom = obstack_base (&token_stack);
+  token_bottom = obstack_finish (&token_stack);
 
   isp = NULL;
   wsp = NULL;
@@ -1230,8 +1242,7 @@ next_token (token_data *td, int *line, const char *caller)
          if (startpos != 0 ||
              regs.end [0] != obstack_object_size (&token_stack))
            {
-             *(((char *) obstack_base (&token_stack)
-                + obstack_object_size (&token_stack)) - 1) = '\0';
+             obstack_blank (&token_stack, -1);
              break;
            }
          next_char ();
diff --git a/src/m4.h b/src/m4.h
index 854f28d..ce78455 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -449,6 +449,7 @@ bool arg_equal (macro_arguments *, unsigned int, unsigned 
int);
 bool arg_empty (macro_arguments *, unsigned int);
 size_t arg_len (macro_arguments *, unsigned int);
 builtin_func *arg_func (macro_arguments *, unsigned int);
+struct obstack *arg_scratch (void);
 macro_arguments *make_argv_ref (macro_arguments *, const char *, size_t,
                                bool, bool);
 void push_arg (struct obstack *, macro_arguments *, unsigned int);
diff --git a/src/macro.c b/src/macro.c
index 63d957d..964be5b 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -29,7 +29,10 @@
 #endif /* DEBUG_MACRO */
 
 /* Opaque structure describing all arguments to a macro, including the
-   macro name at index 0.  */
+   macro name at index 0.  The lifetime of argv0 is only guaranteed
+   within a call to expand_macro, whereas the lifetime of the array
+   members is guaranteed as long as the input engine can parse text
+   with a reference to address@hidden  */
 struct macro_arguments
 {
   /* Number of arguments owned by this object, may be larger than
@@ -368,16 +371,17 @@ expand_argument (struct obstack *obs, token_data *argp, 
const char *caller)
        case TOKEN_CLOSE:
          if (paren_level == 0)
            {
+             size_t len = obstack_object_size (obs);
              if (TOKEN_DATA_TYPE (argp) == TOKEN_FUNC)
                {
-                 if (obstack_object_size (obs) == 0)
+                 if (!len)
                    return t == TOKEN_COMMA;
                  warn_builtin_concat (caller, TOKEN_DATA_FUNC (argp));
                }
-             TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
-             TOKEN_DATA_LEN (argp) = obstack_object_size (obs);
              obstack_1grow (obs, '\0');
+             TOKEN_DATA_TYPE (argp) = TOKEN_TEXT;
              TOKEN_DATA_TEXT (argp) = (char *) obstack_finish (obs);
+             TOKEN_DATA_LEN (argp) = len;
              TOKEN_DATA_QUOTE_AGE (argp) = age;
              return t == TOKEN_COMMA;
            }
@@ -533,6 +537,7 @@ static void
 expand_macro (symbol *sym)
 {
   void *args_base;             /* Base of stacks[i].args on entry.  */
+  void *args_scratch;          /* Base of scratch space for call_macro.  */
   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.  */
@@ -594,6 +599,7 @@ expand_macro (symbol *sym)
     trace_prepre (SYMBOL_NAME (sym), my_call_id);
 
   argv = collect_arguments (sym, stacks[level].args, stacks[level].argv);
+  args_scratch = obstack_finish (stacks[level].args);
 
   /* The actual macro call.  */
   loc_close_file = current_file;
@@ -633,6 +639,7 @@ expand_macro (symbol *sym)
     {
       if (argv->inuse)
        {
+         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,
@@ -850,6 +857,16 @@ arg_func (macro_arguments *argv, unsigned int index)
   return TOKEN_DATA_FUNC (token);
 }
 
+/* Return an obstack useful for scratch calculations that will not
+   interfere with macro expansion.  The obstack will be reset when
+   expand_macro completes.  */
+struct obstack *
+arg_scratch (void)
+{
+  assert (obstack_object_size (stacks[expansion_level - 1].args) == 0);
+  return stacks[expansion_level - 1].args;
+}
+
 /* 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
@@ -865,9 +882,8 @@ make_argv_ref (macro_arguments *argv, const char *argv0, 
size_t argv0_len,
   token_data *token;
   token_chain *chain;
   unsigned int index = skip ? 2 : 1;
-  struct obstack *obs = stacks[expansion_level - 1].argv;
+  struct obstack *obs = arg_scratch ();
 
-  assert (obstack_object_size (obs) == 0);
   /* When making a reference through a reference, point to the
      original if possible.  */
   if (argv->has_ref)
@@ -924,6 +940,8 @@ push_arg (struct obstack *obs, macro_arguments *argv, 
unsigned int index)
 
   if (index == 0)
     {
+      /* Always push copy of arg 0, since its lifetime is not
+        guaranteed beyond expand_macro.  */
       obstack_grow (obs, argv->argv0, argv->argv0_len);
       return;
     }
@@ -944,44 +962,42 @@ void
 push_args (struct obstack *obs, macro_arguments *argv, bool skip, bool quote)
 {
   token_data *token;
-  token_data sep;
   unsigned int i = skip ? 2 : 1;
+  const char *sep = ",";
+  size_t sep_len = 1;
   bool use_sep = false;
   bool inuse = false;
-  static char comma[2] = ",";
+  struct obstack *scratch = arg_scratch ();
 
   if (i >= argv->argc)
     return;
 
-  TOKEN_DATA_TYPE (&sep) = TOKEN_TEXT;
-  TOKEN_DATA_QUOTE_AGE (&sep) = 0;
-  if (quote)
+  if (i + 1 == argv->argc)
     {
-      char *str;
-      obstack_grow (obs, lquote.string, lquote.length);
-      TOKEN_DATA_LEN (&sep) = obstack_object_size (obs);
-      obstack_1grow (obs, '\0');
-      str = (char *) obstack_finish (obs);
-      TOKEN_DATA_TEXT (&sep) = str;
-      push_token (&sep, -1);
-      obstack_grow (obs, rquote.string, rquote.length);
-      obstack_1grow (obs, ',');
-      obstack_grow0 (obs, lquote.string, lquote.length);
-      str = (char *) obstack_finish (obs);
-      TOKEN_DATA_TEXT (&sep) = str;
-      TOKEN_DATA_LEN (&sep) = rquote.length + 1 + lquote.length;
+      if (quote)
+       obstack_grow (obs, lquote.string, lquote.length);
+      push_arg (obs, argv, i);
+      if (quote)
+       obstack_grow (obs, rquote.string, rquote.length);
+      return;
     }
-  else
+
+  /* Compute the separator in the scratch space.  */
+  if (quote)
     {
-      TOKEN_DATA_TEXT (&sep) = comma;
-      TOKEN_DATA_LEN (&sep) = 1;
+      obstack_grow (obs, lquote.string, lquote.length);
+      obstack_grow (scratch, rquote.string, rquote.length);
+      obstack_1grow (scratch, ',');
+      obstack_grow0 (scratch, lquote.string, lquote.length);
+      sep = (char *) obstack_finish (scratch);
+      sep_len += lquote.length + rquote.length;
     }
   /* TODO push entire $@ reference, rather than pushing each arg.  */
   for ( ; i < argv->argc; i++)
     {
       token = arg_token (argv, i);
       if (use_sep)
-       push_token (&sep, -1);
+       obstack_grow (obs, sep, sep_len);
       else
        use_sep = true;
       /* TODO handle func tokens?  */


hooks/post-receive
--
GNU M4 source repository




reply via email to

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