m4-commit
[Top][All Lists]
Advanced

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

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


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, branch-1.6, updated. v1.5.89a-26-gf3fbfb9
Date: Tue, 03 Jun 2008 03:51:11 +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=f3fbfb92cc3f44af244f888b8be6b465493dc590

The branch, branch-1.6 has been updated
       via  f3fbfb92cc3f44af244f888b8be6b465493dc590 (commit)
      from  b9a0d949a0485213215c59b6df9283d4886d5fff (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 f3fbfb92cc3f44af244f888b8be6b465493dc590
Author: Eric Blake <address@hidden>
Date:   Tue Dec 18 16:13:16 2007 -0700

    Stage 24: Allow embedded NUL in macro names.
    
    * m4/gnulib-cache.m4: Import xmemdup0 module.
    * src/m4.h (define_builtin, push_string_init, push_wrapup_init)
    (lookup_symbol): Add parameters.
    (struct call_info): Add name_len member.
    (struct token_data) [ENABLE_CHANGEWORD]: Add original_len member.
    (struct symbol): Add len member.
    (TOKEN_DATA_ORIG_LEN, SYMBOL_NAME_LEN): New accessors.
    (m4_error_at_line, m4_warn_at_line): Delete.
    (m4_error, m4_warn, debug_set_output, skip_line, set_word_regexp)
    (bad_argc, evaluate): Adjust parameter type.
    * src/m4.c (m4_error_at_line, m4_warn_at_line): Delete.
    (m4_verror_at_line, m4_error, m4_warn): Adjust parameter type.
    (main): Adjust caller.
    * src/symtab.c (profile_strcmp) [DEBUG_SYMTAB]: Rename...
    (profile_memcmp): ...and accomodate NUL.
    (hash, lookup_symbol): Add parameter to track length.
    (symtab_debug, symtab_print_list): Adjust callers.
    * src/input.c (push_string_init, push_wrapup_init): Take location
    as parameter rather than using global state.
    (skip_line, set_word_regexp, next_token): Adjust parameter type.
    (peek_input, next_char_1, match_input, lex_debug): Adjust
    callers.
    * src/macro.c (struct macro_arguments): Delete argv0 and argv0_len
    members, now covered by info.
    (expand_input, expand_token, expand_argument, collect_arguments)
    (expand_macro, arg_text, arg_empty, arg_len, make_argv_ref)
    (push_arg, wrap_args): Adjust callers.
    * src/builtin.c (define_builtin): Add parameter.
    (bad_argc, numeric_arg, mkstemp_helper, substitute): Adjust
    parameter type.
    (define_user_macro, builtin_init, define_macro, m4_undefine)
    (m4_popdef, m4_ifdef, m4_ifelse, dumpdef_cmp, m4_dumpdef)
    (m4_builtin, m4_indir, m4_defn, m4_syscmd, m4_esyscmd, m4_eval)
    (m4_incr, m4_decr, m4_divert, m4_divnum, m4_undivert, m4_shift)
    (m4_changequote, m4_changecom, m4_changeword, include)
    (m4_maketemp, m4_mkstemp, m4_errprint, m4___file__, m4___line__)
    (m4___program__, m4_m4exit, m4_m4wrap, m4_traceon, m4_traceoff)
    (m4_debugmode, m4_debugfile, m4_len, m4_index, m4_substr)
    (m4_translit, m4_format, m4_regexp, m4_patsubst): Adjust all
    callers.
    * src/debug.c (debug_set_file, debug_set_output): Adjust parameter
    type.
    (trace_flush, trace_prepre, trace_pre): Adjust all callers.
    * src/eval.c (logical_or_term, logical_and_term, or_term)
    (xor_term, and_term, equality_term, cmp_term, shift_term)
    (add_term, mult_term, exp_term, unary_term, simple_term)
    (evaluate): Adjust parameter type.
    * src/format.c (arg_int, arg_long, arg_double): Likewise.
    (expand_format): Adjust caller.
    * doc/m4.texinfo (Using frozen files): Test this.
    * examples/null.m4: Likewise.
    * examples/null.err: Adjust expected output.
    * examples/null.out: Likewise.
    
    (cherry picked from commit 6167507cf07ddbc838e14e3d66803b360e63f6f2)
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog          |   61 ++++++++++++++++
 doc/m4.texinfo     |   16 ++++
 examples/null.err  |  Bin 51 -> 505 bytes
 examples/null.m4   |  Bin 5876 -> 5891 bytes
 examples/null.out  |  Bin 404 -> 404 bytes
 m4/gnulib-cache.m4 |    4 +-
 src/builtin.c      |  193 +++++++++++++++++++++++++++++----------------------
 src/debug.c        |   26 ++++---
 src/eval.c         |   56 ++++++++--------
 src/format.c       |    8 +-
 src/freeze.c       |   10 ++--
 src/input.c        |  103 +++++++++++++++-------------
 src/m4.c           |  130 ++++++++++++-----------------------
 src/m4.h           |   34 +++++----
 src/macro.c        |   68 ++++++++----------
 src/symtab.c       |   74 +++++++++++---------
 16 files changed, 430 insertions(+), 353 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 7bb18a1..b3ddf60 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,66 @@
 2008-06-02  Eric Blake  <address@hidden>
 
+       Stage 24: Allow embedded NUL in macro names.
+       Replace const char *macro_name with const m4_call_info *call.  Use
+       length rather than NUL-termination when tracking macro names,
+       including in diagnostics.  Quote instances of problematic
+       characters in macro names when presented to user.
+       Memory impact: none.
+       Speed impact: slight penalty, due to more bookkeeping.
+       * m4/gnulib-cache.m4: Import xmemdup0 module.
+       * src/m4.h (define_builtin, push_string_init, push_wrapup_init)
+       (lookup_symbol): Add parameters.
+       (struct call_info): Add name_len member.
+       (struct token_data) [ENABLE_CHANGEWORD]: Add original_len member.
+       (struct symbol): Add len member.
+       (TOKEN_DATA_ORIG_LEN, SYMBOL_NAME_LEN): New accessors.
+       (m4_error_at_line, m4_warn_at_line): Delete.
+       (m4_error, m4_warn, debug_set_output, skip_line, set_word_regexp)
+       (bad_argc, evaluate): Adjust parameter type.
+       * src/m4.c (m4_error_at_line, m4_warn_at_line): Delete.
+       (m4_verror_at_line, m4_error, m4_warn): Adjust parameter type.
+       (main): Adjust caller.
+       * src/symtab.c (profile_strcmp) [DEBUG_SYMTAB]: Rename...
+       (profile_memcmp): ...and accomodate NUL.
+       (hash, lookup_symbol): Add parameter to track length.
+       (symtab_debug, symtab_print_list): Adjust callers.
+       * src/input.c (push_string_init, push_wrapup_init): Take location
+       as parameter rather than using global state.
+       (skip_line, set_word_regexp, next_token): Adjust parameter type.
+       (peek_input, next_char_1, match_input, lex_debug): Adjust
+       callers.
+       * src/macro.c (struct macro_arguments): Delete argv0 and argv0_len
+       members, now covered by info.
+       (expand_input, expand_token, expand_argument, collect_arguments)
+       (expand_macro, arg_text, arg_empty, arg_len, make_argv_ref)
+       (push_arg, wrap_args): Adjust callers.
+       * src/builtin.c (define_builtin): Add parameter.
+       (bad_argc, numeric_arg, mkstemp_helper, substitute): Adjust
+       parameter type.
+       (define_user_macro, builtin_init, define_macro, m4_undefine)
+       (m4_popdef, m4_ifdef, m4_ifelse, dumpdef_cmp, m4_dumpdef)
+       (m4_builtin, m4_indir, m4_defn, m4_syscmd, m4_esyscmd, m4_eval)
+       (m4_incr, m4_decr, m4_divert, m4_divnum, m4_undivert, m4_shift)
+       (m4_changequote, m4_changecom, m4_changeword, include)
+       (m4_maketemp, m4_mkstemp, m4_errprint, m4___file__, m4___line__)
+       (m4___program__, m4_m4exit, m4_m4wrap, m4_traceon, m4_traceoff)
+       (m4_debugmode, m4_debugfile, m4_len, m4_index, m4_substr)
+       (m4_translit, m4_format, m4_regexp, m4_patsubst): Adjust all
+       callers.
+       * src/debug.c (debug_set_file, debug_set_output): Adjust parameter
+       type.
+       (trace_flush, trace_prepre, trace_pre): Adjust all callers.
+       * src/eval.c (logical_or_term, logical_and_term, or_term)
+       (xor_term, and_term, equality_term, cmp_term, shift_term)
+       (add_term, mult_term, exp_term, unary_term, simple_term)
+       (evaluate): Adjust parameter type.
+       * src/format.c (arg_int, arg_long, arg_double): Likewise.
+       (expand_format): Adjust caller.
+       * doc/m4.texinfo (Using frozen files): Test this.
+       * examples/null.m4: Likewise.
+       * examples/null.err: Adjust expected output.
+       * examples/null.out: Likewise.
+
        Allow autobuild usage.
        * m4/gnulib.cache: Import autobuild module.
 
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 67393e2..fe429b4 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -7003,6 +7003,22 @@ $ @kbd{m4 -F /none/such}
 ^D
 @error{}m4: cannot open /none/such: No such file or directory
 @end example
+
address@hidden Another test - can we properly freeze embedded NUL?
+
address@hidden xout: null.out
address@hidden
+ifdef(`__unix__', ,
+      `errprint(` skipping: syscmd does not have unix semantics
+')m4exit(`77')')dnl
+changequote(`[', `]')dnl
+syscmd([printf 'define(-\0-,hi)dnl
+divert(1)undivert(null.out)' | ]__program__[ -F in.m4f \
+     && printf 'errprint(indir(-\0-))' | ]__program__[ -R in.m4f \
+     && rm in.m4f])errprint([ ]sysval[
+])dnl
address@hidden 0
address@hidden example
 @end ignore
 
 When an @code{m4} run is to be frozen, the automatic undiversion
diff --git a/examples/null.err b/examples/null.err
index d825818..05a1ba3 100644
Binary files a/examples/null.err and b/examples/null.err differ
diff --git a/examples/null.m4 b/examples/null.m4
index 10d15ae..c928360 100644
Binary files a/examples/null.m4 and b/examples/null.m4 differ
diff --git a/examples/null.out b/examples/null.out
index cd3764f..66f41b5 100644
Binary files a/examples/null.out and b/examples/null.out differ
diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4
index 26abbef..b6ba202 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 announce-gen assert autobuild avltree-oset 
binary-io clean-temp cloexec close-stream closein config-h error fdl fflush 
flexmember fopen-safer fseeko gendocs getopt git-version-gen gnumakefile 
gnupload gpl-3.0 intprops memchr2 memmem mkstemp obstack quote regex stdbool 
stdint stdlib-safer strtod strtol unlocked-io vasnprintf-posix 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 announce-gen assert autobuild avltree-oset 
binary-io clean-temp cloexec close-stream closein config-h error fdl fflush 
flexmember fopen-safer fseeko gendocs getopt git-version-gen gnumakefile 
gnupload gpl-3.0 intprops memchr2 memmem mkstemp obstack quote regex stdbool 
stdint stdlib-safer strtod strtol unlocked-io vasnprintf-posix verror 
version-etc version-etc-fsf xalloc xmemdup0 xprintf xvasprintf-posix
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([local])
-gl_MODULES([announce-gen assert autobuild avltree-oset binary-io clean-temp 
cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer 
fseeko gendocs getopt git-version-gen gnumakefile gnupload gpl-3.0 intprops 
memchr2 memmem mkstemp obstack quote regex stdbool stdint stdlib-safer strtod 
strtol unlocked-io vasnprintf-posix verror version-etc version-etc-fsf xalloc 
xprintf xvasprintf-posix])
+gl_MODULES([announce-gen assert autobuild avltree-oset binary-io clean-temp 
cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer 
fseeko gendocs getopt git-version-gen gnumakefile gnupload gpl-3.0 intprops 
memchr2 memmem mkstemp obstack quote regex stdbool stdint stdlib-safer strtod 
strtol unlocked-io vasnprintf-posix verror version-etc version-etc-fsf xalloc 
xmemdup0 xprintf xvasprintf-posix])
 gl_AVOID([])
 gl_SOURCE_BASE([lib])
 gl_M4_BASE([m4])
diff --git a/src/builtin.c b/src/builtin.c
index 830d4a2..e3ddf32 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -230,18 +230,19 @@ func_print (struct obstack *obs, const builtin *func, 
bool flatten,
     }
 }
 
-/*-------------------------------------------------------------------------.
-| Install a builtin macro with name NAME, bound to the C function given in |
-| BP.  MODE is SYMBOL_INSERT or SYMBOL_PUSHDEF.  TRACED defines whether        
   |
-| NAME is to be traced.                                                        
   |
-`-------------------------------------------------------------------------*/
+/*----------------------------------------------------------------.
+| Install a builtin macro with name NAME and length LEN, bound to |
+| the C function given in BP.  MODE is SYMBOL_INSERT or                  |
+| SYMBOL_PUSHDEF.                                                |
+`----------------------------------------------------------------*/
 
 void
-define_builtin (const char *name, const builtin *bp, symbol_lookup mode)
+define_builtin (const char *name, size_t len, const builtin *bp,
+               symbol_lookup mode)
 {
   symbol *sym;
 
-  sym = lookup_symbol (name, mode);
+  sym = lookup_symbol (name, len, mode);
   SYMBOL_TYPE (sym) = TOKEN_FUNC;
   SYMBOL_MACRO_ARGS (sym) = bp->groks_macro_args;
   SYMBOL_BLIND_NO_ARGS (sym) = bp->blind_if_no_args;
@@ -443,7 +444,7 @@ define_user_macro (const char *name, size_t name_len, const 
char *text,
   symbol *s;
   char *defn = xstrdup (text ? text : "");
 
-  s = lookup_symbol (name, mode);
+  s = lookup_symbol (name, name_len, mode);
   if (SYMBOL_TYPE (s) == TOKEN_TEXT)
     free (SYMBOL_TEXT (s));
 
@@ -468,16 +469,20 @@ define_user_macro (const char *name, size_t name_len, 
const char *text,
          else
            {
              offset = regs->end[0];
-             m4_warn (0, NULL,
-                      _("definition of `%s' contains sequence `%.*s'"),
-                      name, (int) (regs->end[0] - regs->start[0]),
-                      defn + regs->start[0]);
+             /* Safe to use slot 1 since we don't pass a macro name
+                to m4_warn.  */
+             m4_warn (0, NULL, _("definition of %s contains sequence %s"),
+                      quotearg_style_mem (locale_quoting_style, name,
+                                          name_len),
+                      quotearg_n_style_mem (1, locale_quoting_style,
+                                            defn + regs->start[0],
+                                            regs->end[0] - regs->start[0]));
            }
        }
       if (offset == -2)
        m4_warn (0, NULL,
-                _("problem checking --warn-macro-sequence for macro `%s'"),
-                name);
+                _("problem checking --warn-macro-sequence for macro %s"),
+                quotearg_style_mem (locale_quoting_style, name, name_len));
     }
 }
 
@@ -495,14 +500,15 @@ 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 = xasprintf ("m4_%s", bp->name);
-           define_builtin (string, bp, SYMBOL_INSERT);
+           define_builtin (string, len + 3, bp, SYMBOL_INSERT);
            free (string);
          }
        else
-         define_builtin (bp->name, bp, SYMBOL_INSERT);
+         define_builtin (bp->name, len, bp, SYMBOL_INSERT);
       }
 
   for (pp = &predefined_tab[0]; pp->func != NULL; pp++)
@@ -530,7 +536,7 @@ builtin_init (void)
 `------------------------------------------------------------------*/
 
 bool
-bad_argc (const char *name, int argc, unsigned int min, unsigned int max)
+bad_argc (const call_info *name, int argc, unsigned int min, unsigned int max)
 {
   if (argc - 1 < min)
     {
@@ -549,7 +555,7 @@ bad_argc (const char *name, int argc, unsigned int min, 
unsigned int max)
 `-------------------------------------------------------------------*/
 
 static bool
-numeric_arg (const char *name, const char *arg, int *valuep)
+numeric_arg (const call_info *name, const char *arg, int *valuep)
 {
   char *endp;
 
@@ -657,7 +663,7 @@ static void
 define_macro (int argc, macro_arguments *argv, symbol_lookup mode)
 {
   const builtin *bp;
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
 
   if (bad_argc (me, argc, 1, 2))
     return;
@@ -688,7 +694,7 @@ define_macro (int argc, macro_arguments *argv, 
symbol_lookup mode)
       if (bp == NULL)
        return;
       else
-       define_builtin (ARG (1), bp, mode);
+       define_builtin (ARG (1), ARG_LEN (1), bp, mode);
       break;
 
     default:
@@ -706,7 +712,7 @@ m4_define (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_undefine (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int i;
   if (bad_argc (me, argc, 1, -1))
     return;
@@ -714,7 +720,7 @@ m4_undefine (struct obstack *obs, int argc, macro_arguments 
*argv)
     if (arg_type (argv, i) != TOKEN_TEXT)
       m4_warn (0, me, _("invalid macro name ignored"));
     else
-      lookup_symbol (ARG (i), SYMBOL_DELETE);
+      lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_DELETE);
 }
 
 static void
@@ -726,7 +732,7 @@ m4_pushdef (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_popdef (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int i;
   if (bad_argc (me, argc, 1, -1))
     return;
@@ -734,7 +740,7 @@ m4_popdef (struct obstack *obs, int argc, macro_arguments 
*argv)
     if (arg_type (argv, i) != TOKEN_TEXT)
       m4_warn (0, me, _("invalid macro name ignored"));
     else
-      lookup_symbol (ARG (i), SYMBOL_POPDEF);
+      lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_POPDEF);
 }
 
 /*---------------------.
@@ -744,7 +750,7 @@ m4_popdef (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_ifdef (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   symbol *s;
 
   if (bad_argc (me, argc, 2, 3))
@@ -755,14 +761,14 @@ m4_ifdef (struct obstack *obs, int argc, macro_arguments 
*argv)
       push_arg (obs, argv, 3);
       return;
     }
-  s = lookup_symbol (ARG (1), SYMBOL_LOOKUP);
+  s = lookup_symbol (ARG (1), ARG_LEN (1), SYMBOL_LOOKUP);
   push_arg (obs, argv, (s && SYMBOL_TYPE (s) != TOKEN_VOID) ? 2 : 3);
 }
 
 static void
 m4_ifelse (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int i;
 
   if (argc == 2 || bad_argc (me, argc, 3, -1))
@@ -832,8 +838,15 @@ dump_symbol (symbol *sym, void *arg)
 static int
 dumpdef_cmp (const void *s1, const void *s2)
 {
-  return strcmp (SYMBOL_NAME (* (symbol *const *) s1),
-                SYMBOL_NAME (* (symbol *const *) s2));
+  const symbol *sym1 = *(const symbol **) s1;
+  const symbol *sym2 = *(const symbol **) s2;
+  size_t len1 = SYMBOL_NAME_LEN (sym1);
+  size_t len2 = SYMBOL_NAME_LEN (sym2);
+  int result = memcmp (SYMBOL_NAME (sym1), SYMBOL_NAME (sym2),
+                      len1 < len2 ? len1 : len2);
+  if (!result)
+    result = len1 < len2 ? -1 : len2 < len1;
+  return result;
 }
 
 /*-------------------------------------------------------------------------.
@@ -844,12 +857,16 @@ dumpdef_cmp (const void *s1, const void *s2)
 static void
 m4_dumpdef (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   symbol *s;
   int i;
   struct dump_symbol_data data;
   const builtin *bp;
 
+  /* If there's no debug stream to dump to, skip all of this work.  */
+  if (!debug)
+    return;
+
   data.obs = obs;
   data.base = (symbol **) obstack_base (obs);
   data.size = 0;
@@ -867,23 +884,27 @@ m4_dumpdef (struct obstack *obs, int argc, 
macro_arguments *argv)
              m4_warn (0, me, _("invalid macro name ignored"));
              continue;
            }
-         s = lookup_symbol (ARG (i), SYMBOL_LOOKUP);
+         s = lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_LOOKUP);
          if (s != NULL && SYMBOL_TYPE (s) != TOKEN_VOID)
            dump_symbol (s, &data);
          else
-           m4_warn (0, me, _("undefined macro `%s'"), ARG (i));
+           m4_warn (0, me, _("undefined macro %s"),
+                    quotearg_style_mem (locale_quoting_style, ARG (i),
+                                        ARG_LEN (i)));
        }
     }
 
   /* Make table of symbols invisible to expand_macro ().  */
-
   obstack_finish (obs);
 
   qsort (data.base, data.size, sizeof (symbol *), dumpdef_cmp);
-
   for (; data.size > 0; --data.size, data.base++)
     {
-      DEBUG_PRINT1 ("%s:\t", SYMBOL_NAME (data.base[0]));
+      /* TODO - add debugmode(b) option to control quoting style?  */
+      fwrite (SYMBOL_NAME (data.base[0]), 1, SYMBOL_NAME_LEN (data.base[0]),
+             debug);
+      fputc (':', debug);
+      fputc ('\t', debug);
 
       switch (SYMBOL_TYPE (data.base[0]))
        {
@@ -924,7 +945,7 @@ m4_dumpdef (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_builtin (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   const builtin *bp;
   const char *name;
 
@@ -939,7 +960,8 @@ m4_builtin (struct obstack *obs, int argc, macro_arguments 
*argv)
   name = ARG (1);
   bp = find_builtin_by_name (name);
   if (bp->func == m4_placeholder)
-    m4_warn (0, me, _("undefined builtin `%s'"), name);
+    m4_warn (0, me, _("undefined builtin %s"),
+            quotearg_style_mem (locale_quoting_style, name, ARG_LEN (1)));
   else
     {
       macro_arguments *new_argv = make_argv_ref (argv, name, ARG_LEN (1),
@@ -958,9 +980,10 @@ m4_builtin (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_indir (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   symbol *s;
   const char *name;
+  size_t len;
 
   if (bad_argc (me, argc, 1, -1))
     return;
@@ -971,12 +994,14 @@ m4_indir (struct obstack *obs, int argc, macro_arguments 
*argv)
     }
 
   name = ARG (1);
-  s = lookup_symbol (name, SYMBOL_LOOKUP);
+  len = ARG_LEN (1);
+  s = lookup_symbol (name, len, SYMBOL_LOOKUP);
   if (s == NULL || SYMBOL_TYPE (s) == TOKEN_VOID)
-    m4_warn (0, me, _("undefined macro `%s'"), name);
+    m4_warn (0, me, _("undefined macro %s"),
+            quotearg_style_mem (locale_quoting_style, name, len));
   else
     {
-      macro_arguments *new_argv = make_argv_ref (argv, name, ARG_LEN (1),
+      macro_arguments *new_argv = make_argv_ref (argv, name, len,
                                                 !SYMBOL_MACRO_ARGS (s),
                                                 SYMBOL_TRACED (s));
       trace_prepre (arg_info (new_argv));
@@ -993,7 +1018,7 @@ m4_indir (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_defn (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   symbol *s;
   builtin_func *b;
   int i;
@@ -1008,10 +1033,12 @@ m4_defn (struct obstack *obs, int argc, macro_arguments 
*argv)
          m4_warn (0, me, _("invalid macro name ignored"));
          continue;
        }
-      s = lookup_symbol (ARG (i), SYMBOL_LOOKUP);
+      s = lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_LOOKUP);
       if (s == NULL)
        {
-         m4_warn (0, me, _("undefined macro `%s'"), ARG (i));
+         m4_warn (0, me, _("undefined macro %s"),
+                  quotearg_style_mem (locale_quoting_style, ARG (i),
+                                      ARG_LEN (i)));
          continue;
        }
 
@@ -1080,7 +1107,7 @@ static int sysval;
 static void
 m4_syscmd (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  if (bad_argc (ARG (0), argc, 1, 1))
+  if (bad_argc (arg_info (argv), argc, 1, 1))
     {
       /* The empty command is successful.  */
       sysval = 0;
@@ -1104,7 +1131,7 @@ m4_syscmd (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_esyscmd (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   FILE *pin;
   int ch;
 
@@ -1147,7 +1174,7 @@ m4_sysval (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_eval (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int32_t value = 0;
   int radix = 10;
   int min = 1;
@@ -1211,7 +1238,7 @@ m4_eval (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_incr (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int value;
 
   if (bad_argc (me, argc, 1, 1))
@@ -1226,7 +1253,7 @@ m4_incr (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_decr (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int value;
 
   if (bad_argc (me, argc, 1, 1))
@@ -1249,7 +1276,7 @@ m4_decr (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_divert (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int i = 0;
 
   bad_argc (me, argc, 0, 1);
@@ -1266,7 +1293,7 @@ m4_divert (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_divnum (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  bad_argc (ARG (0), argc, 0, 0);
+  bad_argc (arg_info (argv), argc, 0, 0);
   shipout_int (obs, current_diversion);
 }
 
@@ -1280,7 +1307,7 @@ m4_divnum (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_undivert (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int i;
   int file;
   FILE *fp;
@@ -1324,7 +1351,7 @@ m4_undivert (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_dnl (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
 
   bad_argc (me, argc, 0, 0);
   skip_line (me);
@@ -1338,7 +1365,7 @@ m4_dnl (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_shift (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  if (bad_argc (ARG (0), argc, 1, -1))
+  if (bad_argc (arg_info (argv), argc, 1, -1))
     return;
   push_args (obs, argv, true, true);
 }
@@ -1350,7 +1377,7 @@ m4_shift (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_changequote (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  bad_argc (ARG (0), argc, 0, 2);
+  bad_argc (arg_info (argv), argc, 0, 2);
 
   /* Explicit NULL distinguishes between empty and missing argument.  */
   set_quotes ((argc >= 2) ? ARG (1) : NULL,
@@ -1365,7 +1392,7 @@ m4_changequote (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_changecom (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  bad_argc (ARG (0), argc, 0, 2);
+  bad_argc (arg_info (argv), argc, 0, 2);
 
   /* Explicit NULL distinguishes between empty and missing argument.  */
   set_comment ((argc >= 2) ? ARG (1) : NULL,
@@ -1382,7 +1409,7 @@ m4_changecom (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_changeword (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
 
   if (bad_argc (me, argc, 1, 1))
     return;
@@ -1403,7 +1430,7 @@ m4_changeword (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 include (int argc, macro_arguments *argv, bool silent)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   FILE *fp;
   char *name;
 
@@ -1453,7 +1480,7 @@ m4_sinclude (struct obstack *obs, int argc, 
macro_arguments *argv)
    securely create the file, and place the quoted new file name on
    OBS.  Report errors on behalf of ME.  */
 static void
-mkstemp_helper (struct obstack *obs, const char *me, const char *pattern,
+mkstemp_helper (struct obstack *obs, const call_info *me, const char *pattern,
                size_t len)
 {
   int fd;
@@ -1490,7 +1517,7 @@ mkstemp_helper (struct obstack *obs, const char *me, 
const char *pattern,
 static void
 m4_maketemp (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
 
   if (bad_argc (me, argc, 1, 1))
     return;
@@ -1535,7 +1562,7 @@ m4_maketemp (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_mkstemp (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
 
   if (bad_argc (me, argc, 1, 1))
     return;
@@ -1551,7 +1578,7 @@ m4_errprint (struct obstack *obs, int argc, 
macro_arguments *argv)
 {
   size_t len;
 
-  if (bad_argc (ARG (0), argc, 1, -1))
+  if (bad_argc (arg_info (argv), argc, 1, -1))
     return;
   arg_print (obs, argv, 1, NULL, true, NULL, " ", NULL, false);
   debug_flush_files ();
@@ -1565,7 +1592,7 @@ m4_errprint (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4___file__ (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  bad_argc (ARG (0), argc, 0, 0);
+  bad_argc (arg_info (argv), argc, 0, 0);
   obstack_grow (obs, curr_quote.str1, curr_quote.len1);
   obstack_grow (obs, current_file, strlen (current_file));
   obstack_grow (obs, curr_quote.str2, curr_quote.len2);
@@ -1574,14 +1601,14 @@ m4___file__ (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4___line__ (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  bad_argc (ARG (0), argc, 0, 0);
+  bad_argc (arg_info (argv), argc, 0, 0);
   shipout_int (obs, current_line);
 }
 
 static void
 m4___program__ (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  bad_argc (ARG (0), argc, 0, 0);
+  bad_argc (arg_info (argv), argc, 0, 0);
   obstack_grow (obs, curr_quote.str1, curr_quote.len1);
   obstack_grow (obs, program_name, strlen (program_name));
   obstack_grow (obs, curr_quote.str2, curr_quote.len2);
@@ -1599,7 +1626,7 @@ m4___program__ (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_m4exit (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int exit_code = EXIT_SUCCESS;
 
   /* Warn on bad arguments, but still exit.  */
@@ -1632,7 +1659,7 @@ m4_m4exit (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_m4wrap (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  if (bad_argc (ARG (0), argc, 1, -1))
+  if (bad_argc (arg_info (argv), argc, 1, -1))
     return;
   wrap_args (argv);
 }
@@ -1654,13 +1681,13 @@ set_trace (symbol *sym, void *data)
   SYMBOL_TRACED (sym) = data != NULL;
   /* Remove placeholder from table if macro is undefined and untraced.  */
   if (SYMBOL_TYPE (sym) == TOKEN_VOID && data == NULL)
-    lookup_symbol (SYMBOL_NAME (sym), SYMBOL_POPDEF);
+    lookup_symbol (SYMBOL_NAME (sym), SYMBOL_NAME_LEN (sym), SYMBOL_POPDEF);
 }
 
 static void
 m4_traceon (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   symbol *s;
   int i;
 
@@ -1674,9 +1701,9 @@ m4_traceon (struct obstack *obs, int argc, 
macro_arguments *argv)
            m4_warn (0, me, _("invalid macro name ignored"));
            continue;
          }
-       s = lookup_symbol (ARG (i), SYMBOL_LOOKUP);
+       s = lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_LOOKUP);
        if (!s)
-         s = lookup_symbol (ARG (i), SYMBOL_INSERT);
+         s = lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_INSERT);
        set_trace (s, obs);
       }
 }
@@ -1688,7 +1715,7 @@ m4_traceon (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_traceoff (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   symbol *s;
   int i;
 
@@ -1702,7 +1729,7 @@ m4_traceoff (struct obstack *obs, int argc, 
macro_arguments *argv)
            m4_warn (0, me, _("invalid macro name ignored"));
            continue;
          }
-       s = lookup_symbol (ARG (i), SYMBOL_LOOKUP);
+       s = lookup_symbol (ARG (i), ARG_LEN (i), SYMBOL_LOOKUP);
        if (s != NULL)
          set_trace (s, NULL);
       }
@@ -1717,7 +1744,7 @@ m4_traceoff (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   const char *str = ARG (1);
   int new_debug_level;
   int change_flag;
@@ -1769,7 +1796,7 @@ m4_debugmode (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_debugfile (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
 
   bad_argc (me, argc, 0, 1);
 
@@ -1790,7 +1817,7 @@ m4_debugfile (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_len (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  if (bad_argc (ARG (0), argc, 1, 1))
+  if (bad_argc (arg_info (argv), argc, 1, 1))
     return;
   shipout_int (obs, ARG_LEN (1));
 }
@@ -1808,7 +1835,7 @@ m4_index (struct obstack *obs, int argc, macro_arguments 
*argv)
   const char *result = NULL;
   int retval = -1;
 
-  if (bad_argc (ARG (0), argc, 2, 2))
+  if (bad_argc (arg_info (argv), argc, 2, 2))
     {
       /* builtin(`index') is blank, but index(`abc') is 0.  */
       if (argc == 2)
@@ -1838,7 +1865,7 @@ m4_index (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_substr (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   int start = 0;
   int length;
   int avail;
@@ -1929,7 +1956,7 @@ m4_translit (struct obstack *obs, int argc, 
macro_arguments *argv)
   char found[UCHAR_MAX + 1] = {0};
   unsigned char ch;
 
-  if (bad_argc (ARG (0), argc, 2, 3))
+  if (bad_argc (arg_info (argv), argc, 2, 3))
     {
       /* builtin(`translit') is blank, but translit(`abc') is abc.  */
       if (argc == 2)
@@ -1981,7 +2008,7 @@ m4_translit (struct obstack *obs, int argc, 
macro_arguments *argv)
 static void
 m4_format (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  if (bad_argc (ARG (0), argc, 1, -1))
+  if (bad_argc (arg_info (argv), argc, 1, -1))
     return;
   expand_format (obs, argc, argv);
 }
@@ -1998,7 +2025,7 @@ m4_format (struct obstack *obs, int argc, macro_arguments 
*argv)
 static int substitute_warned = 0;
 
 static void
-substitute (struct obstack *obs, const char *me, const char *victim,
+substitute (struct obstack *obs, const call_info *me, const char *victim,
            const char *repl, struct re_registers *regs)
 {
   int ch;
@@ -2078,7 +2105,7 @@ init_pattern_buffer (struct re_pattern_buffer *buf, 
struct re_registers *regs)
 static void
 m4_regexp (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   const char *victim;          /* first argument */
   const char *regexp;          /* regular expression */
   const char *repl;            /* replacement string */
@@ -2148,7 +2175,7 @@ m4_regexp (struct obstack *obs, int argc, macro_arguments 
*argv)
 static void
 m4_patsubst (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);
+  const call_info *me = arg_info (argv);
   const char *victim;          /* first argument */
   const char *regexp;          /* regular expression */
   const char *repl;
diff --git a/src/debug.c b/src/debug.c
index 0298fc8..2b2388f 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -30,7 +30,7 @@ FILE *debug = NULL;
 /* Obstack for trace messages.  */
 static struct obstack trace;
 
-static void debug_set_file (const char *, FILE *);
+static void debug_set_file (const call_info *, FILE *);
 
 /*----------------------------------.
 | Initialize the debugging module.  |
@@ -121,7 +121,7 @@ debug_decode (const char *opts)
 `-----------------------------------------------------------------*/
 
 static void
-debug_set_file (const char *caller, FILE *fp)
+debug_set_file (const call_info *caller, FILE *fp)
 {
   struct stat stdout_stat, debug_stat;
 
@@ -189,7 +189,7 @@ debug_flush_files (void)
 `-------------------------------------------------------------------*/
 
 bool
-debug_set_output (const char *caller, const char *name)
+debug_set_output (const call_info *caller, const char *name)
 {
   FILE *fp;
 
@@ -313,13 +313,16 @@ trace_header (const call_info *info)
 static void
 trace_flush (unsigned int start)
 {
-  char *line;
+  char *base = (char *) obstack_base (&trace);
+  size_t len = obstack_object_size (&trace);
 
-  obstack_1grow (&trace, '\0');
-  line = (char *) obstack_base (&trace);
-  DEBUG_PRINT1 ("%s\n", &line[start]);
-  start -= obstack_object_size (&trace);
-  obstack_blank (&trace, start);
+  if (debug)
+    {
+      /* TODO - quote nonprintable characters if debug is tty?  */
+      fwrite (&base[start], 1, len - start, debug);
+      fputc ('\n', debug);
+    }
+  obstack_blank (&trace, start - len);
 }
 
 /*-------------------------------------------------------------------.
@@ -333,7 +336,8 @@ trace_prepre (const call_info *info)
   if (info->trace && (info->debug_level & DEBUG_TRACE_CALL))
     {
       unsigned int start = trace_header (info);
-      trace_format ("%s ...", info->name);
+      obstack_grow (&trace, info->name, info->name_len);
+      obstack_grow (&trace, " ...", 4);
       trace_flush (start);
     }
 }
@@ -353,7 +357,7 @@ trace_pre (macro_arguments *argv)
   unsigned int start = trace_header (info);
 
   assert (info->trace);
-  trace_format ("%s", info->name);
+  obstack_grow (&trace, ARG (0), ARG_LEN (0));
   if (1 < arg_argc (argv) && (trace_level & DEBUG_TRACE_ARGS))
     {
       size_t len = max_debug_argument_length;
diff --git a/src/eval.c b/src/eval.c
index fdb50b7..e2e600b 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1,6 +1,6 @@
 /* GNU m4 -- A simple macro processor
 
-   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007
+   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GNU M4.
@@ -62,19 +62,19 @@ typedef enum eval_error
   }
 eval_error;
 
-static eval_error logical_or_term (const char *, eval_token, int32_t *);
-static eval_error logical_and_term (const char *, eval_token, int32_t *);
-static eval_error or_term (const char *, eval_token, int32_t *);
-static eval_error xor_term (const char *, eval_token, int32_t *);
-static eval_error and_term (const char *, eval_token, int32_t *);
-static eval_error equality_term (const char *, eval_token, int32_t *);
-static eval_error cmp_term (const char *, eval_token, int32_t *);
-static eval_error shift_term (const char *, eval_token, int32_t *);
-static eval_error add_term (const char *, eval_token, int32_t *);
-static eval_error mult_term (const char *, eval_token, int32_t *);
-static eval_error exp_term (const char *, eval_token, int32_t *);
-static eval_error unary_term (const char *, eval_token, int32_t *);
-static eval_error simple_term (const char *, eval_token, int32_t *);
+static eval_error logical_or_term (const call_info *, eval_token, int32_t *);
+static eval_error logical_and_term (const call_info *, eval_token, int32_t *);
+static eval_error or_term (const call_info *, eval_token, int32_t *);
+static eval_error xor_term (const call_info *, eval_token, int32_t *);
+static eval_error and_term (const call_info *, eval_token, int32_t *);
+static eval_error equality_term (const call_info *, eval_token, int32_t *);
+static eval_error cmp_term (const call_info *, eval_token, int32_t *);
+static eval_error shift_term (const call_info *, eval_token, int32_t *);
+static eval_error add_term (const call_info *, eval_token, int32_t *);
+static eval_error mult_term (const call_info *, eval_token, int32_t *);
+static eval_error exp_term (const call_info *, eval_token, int32_t *);
+static eval_error unary_term (const call_info *, eval_token, int32_t *);
+static eval_error simple_term (const call_info *, eval_token, int32_t *);
 
 /*--------------------.
 | Lexical functions.  |
@@ -287,7 +287,7 @@ eval_lex (int32_t *val)
 `---------------------------------------*/
 
 bool
-evaluate (const char *me, const char *expr, int32_t *val)
+evaluate (const call_info *me, const char *expr, int32_t *val)
 {
   eval_token et;
   eval_error err;
@@ -355,7 +355,7 @@ evaluate (const char *me, const char *expr, int32_t *val)
 `---------------------------*/
 
 static eval_error
-logical_or_term (const char *me, eval_token et, int32_t *v1)
+logical_or_term (const call_info *me, eval_token et, int32_t *v1)
 {
   int32_t v2;
   eval_error er;
@@ -386,7 +386,7 @@ logical_or_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-logical_and_term (const char *me, eval_token et, int32_t *v1)
+logical_and_term (const call_info *me, eval_token et, int32_t *v1)
 {
   int32_t v2;
   eval_error er;
@@ -417,7 +417,7 @@ logical_and_term (const char *me, eval_token et, int32_t 
*v1)
 }
 
 static eval_error
-or_term (const char *me, eval_token et, int32_t *v1)
+or_term (const call_info *me, eval_token et, int32_t *v1)
 {
   int32_t v2;
   eval_error er;
@@ -444,7 +444,7 @@ or_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-xor_term (const char *me, eval_token et, int32_t *v1)
+xor_term (const call_info *me, eval_token et, int32_t *v1)
 {
   int32_t v2;
   eval_error er;
@@ -471,7 +471,7 @@ xor_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-and_term (const char *me, eval_token et, int32_t *v1)
+and_term (const call_info *me, eval_token et, int32_t *v1)
 {
   int32_t v2;
   eval_error er;
@@ -498,7 +498,7 @@ and_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-equality_term (const char *me, eval_token et, int32_t *v1)
+equality_term (const call_info *me, eval_token et, int32_t *v1)
 {
   eval_token op;
   int32_t v2;
@@ -534,7 +534,7 @@ equality_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-cmp_term (const char *me, eval_token et, int32_t *v1)
+cmp_term (const call_info *me, eval_token et, int32_t *v1)
 {
   eval_token op;
   int32_t v2;
@@ -585,7 +585,7 @@ cmp_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-shift_term (const char *me, eval_token et, int32_t *v1)
+shift_term (const call_info *me, eval_token et, int32_t *v1)
 {
   eval_token op;
   int32_t v2;
@@ -638,7 +638,7 @@ shift_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-add_term (const char *me, eval_token et, int32_t *v1)
+add_term (const call_info *me, eval_token et, int32_t *v1)
 {
   eval_token op;
   int32_t v2;
@@ -673,7 +673,7 @@ add_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-mult_term (const char *me, eval_token et, int32_t *v1)
+mult_term (const call_info *me, eval_token et, int32_t *v1)
 {
   eval_token op;
   int32_t v2;
@@ -734,7 +734,7 @@ mult_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-exp_term (const char *me, eval_token et, int32_t *v1)
+exp_term (const call_info *me, eval_token et, int32_t *v1)
 {
   uint32_t result;
   int32_t v2;
@@ -773,7 +773,7 @@ exp_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-unary_term (const char *me, eval_token et, int32_t *v1)
+unary_term (const call_info *me, eval_token et, int32_t *v1)
 {
   eval_token et2 = et;
   eval_error er;
@@ -805,7 +805,7 @@ unary_term (const char *me, eval_token et, int32_t *v1)
 }
 
 static eval_error
-simple_term (const char *me, eval_token et, int32_t *v1)
+simple_term (const call_info *me, eval_token et, int32_t *v1)
 {
   int32_t v2;
   eval_error er;
diff --git a/src/format.c b/src/format.c
index 717a070..c783d11 100644
--- a/src/format.c
+++ b/src/format.c
@@ -29,7 +29,7 @@
 
 /* Parse STR as an integer, reporting warnings on behalf of ME.  */
 static int
-arg_int (const char *me, const char *str)
+arg_int (const call_info *me, const char *str)
 {
   char *endp;
   long value;
@@ -54,7 +54,7 @@ arg_int (const char *me, const char *str)
 
 /* Parse STR as a long, reporting warnings on behalf of ME.  */
 static long
-arg_long (const char *me, const char *str)
+arg_long (const call_info *me, const char *str)
 {
   char *endp;
   long value;
@@ -79,7 +79,7 @@ arg_long (const char *me, const char *str)
 
 /* Parse STR as a double, reporting warnings on behalf of ME.  */
 static double
-arg_double (const char *me, const char *str)
+arg_double (const call_info *me, const char *str)
 {
   char *endp;
   double value;
@@ -124,7 +124,7 @@ arg_double (const char *me, const char *str)
 void
 expand_format (struct obstack *obs, int argc, macro_arguments *argv)
 {
-  const char *me = ARG (0);            /* Macro name.  */
+  const call_info *me = arg_info (argv);/* Macro name.  */
   const char *f;                       /* Format control string.  */
   const char *fmt;                     /* Position within f.  */
   char fstart[] = "%'+- 0#*.*hhd";     /* Current format spec.  */
diff --git a/src/freeze.c b/src/freeze.c
index c88a266..e67bcc8 100644
--- a/src/freeze.c
+++ b/src/freeze.c
@@ -98,9 +98,9 @@ produce_frozen_state (const char *name)
            {
            case TOKEN_TEXT:
              xfprintf (file, "T%d,%d\n",
-                       (int) strlen (SYMBOL_NAME (sym)),
+                       (int) SYMBOL_NAME_LEN (sym),
                        (int) strlen (SYMBOL_TEXT (sym)));
-             fputs (SYMBOL_NAME (sym), file);
+             fwrite (SYMBOL_NAME (sym), 1, SYMBOL_NAME_LEN (sym), file);
              fputs (SYMBOL_TEXT (sym), file);
              fputc ('\n', file);
              break;
@@ -113,9 +113,9 @@ produce_frozen_state (const char *name)
                  abort ();
                }
              xfprintf (file, "F%d,%d\n",
-                       (int) strlen (SYMBOL_NAME (sym)),
+                       (int) SYMBOL_NAME_LEN (sym),
                        (int) strlen (bp->name));
-             fputs (SYMBOL_NAME (sym), file);
+             fwrite (SYMBOL_NAME (sym), 1, SYMBOL_NAME_LEN (sym), file);
              fputs (bp->name, file);
              fputc ('\n', file);
              break;
@@ -346,7 +346,7 @@ reload_frozen_state (const char *name)
              /* Enter a macro having a builtin function as a definition.  */
 
              bp = find_builtin_by_name (string[1]);
-             define_builtin (string[0], bp, SYMBOL_PUSHDEF);
+             define_builtin (string[0], number[0], bp, SYMBOL_PUSHDEF);
              break;
 
            case 'T':
diff --git a/src/input.c b/src/input.c
index c1f609b..acbc370 100644
--- a/src/input.c
+++ b/src/input.c
@@ -322,7 +322,7 @@ push_macro (struct obstack *obs, builtin_func *func)
 `--------------------------------------------------------------*/
 
 struct obstack *
-push_string_init (void)
+push_string_init (const char *file, int line)
 {
   /* Free any memory occupied by completely parsed strings.  */
   assert (next == NULL);
@@ -331,8 +331,8 @@ push_string_init (void)
   /* Reserve the next location on the obstack.  */
   next = (input_block *) obstack_alloc (current_input, sizeof *next);
   next->type = INPUT_STRING;
-  next->file = current_file;
-  next->line = current_line;
+  next->file = file;
+  next->line = line;
   next->u.u_s.len = 0;
 
   return current_input;
@@ -544,7 +544,7 @@ push_string_finish (void)
 `--------------------------------------------------------------*/
 
 struct obstack *
-push_wrapup_init (token_chain ***end)
+push_wrapup_init (const call_info *caller, token_chain ***end)
 {
   input_block *i;
   token_chain *chain;
@@ -560,8 +560,8 @@ push_wrapup_init (token_chain ***end)
     {
       i = (input_block *) obstack_alloc (wrapup_stack, sizeof *i);
       i->prev = wsp;
-      i->file = current_file;
-      i->line = current_line;
+      i->file = caller->file;
+      i->line = caller->line;
       i->type = INPUT_CHAIN;
       i->u.u_c.chain = i->u.u_c.end = NULL;
       wsp = i;
@@ -575,8 +575,8 @@ push_wrapup_init (token_chain ***end)
   chain->next = NULL;
   chain->type = CHAIN_LOC;
   chain->quote_age = 0;
-  chain->u.u_l.file = current_file;
-  chain->u.u_l.line = current_line;
+  chain->u.u_l.file = caller->file;
+  chain->u.u_l.line = caller->line;
   *end = &i->u.u_c.end;
   return wrapup_stack;
 }
@@ -859,7 +859,7 @@ peek_input (bool allow_argv)
                  /* Rather than directly parse argv here, we push
                     another input block containing the next unparsed
                     argument from argv.  */
-                 push_string_init ();
+                 push_string_init (block->file, block->line);
                  push_arg_quote (current_input, chain->u.u_a.argv,
                                  chain->u.u_a.index,
                                  quote_cache (NULL, chain->quote_age,
@@ -997,7 +997,7 @@ next_char_1 (bool allow_quote, bool allow_argv)
                  /* Rather than directly parse argv here, we push
                     another input block containing the next unparsed
                     argument from argv.  */
-                 push_string_init ();
+                 push_string_init (isp->file, isp->line);
                  push_arg_quote (current_input, chain->u.u_a.argv,
                                  chain->u.u_a.index,
                                  quote_cache (NULL, chain->quote_age,
@@ -1040,26 +1040,14 @@ next_char_1 (bool allow_quote, bool allow_argv)
 `-------------------------------------------------------------------*/
 
 void
-skip_line (const char *name)
+skip_line (const call_info *name)
 {
   int ch;
-  const char *file = current_file;
-  int line = current_line;
 
   while ((ch = next_char (false, false)) != CHAR_EOF && ch != '\n')
     ;
   if (ch == CHAR_EOF)
-    /* current_file changed to "" if we see CHAR_EOF, use the
-       previous value we stored earlier.  */
-    m4_warn_at_line (0, file, line, name,
-                    _("end of file treated as newline"));
-  /* On the rare occasion that dnl crosses include file boundaries
-     (either the input file did not end in a newline, or changeword
-     was used), calling next_char can update current_file and
-     current_line, and that update will be undone as we return to
-     expand_macro.  This informs next_char to fix things again.  */
-  if (file != current_file || line != current_line)
-    input_change = true;
+    m4_warn (0, name, _("end of file treated as newline"));
 }
 
 /*------------------------------------------------------------------.
@@ -1250,7 +1238,7 @@ match_input (const char *s, bool consume)
     }
 
   /* Failed or shouldn't consume, push back input.  */
-  push_string_init ();
+  push_string_init (current_file, current_line);
   obstack_grow (current_input, t, n);
   push_string_finish ();
   return result;
@@ -1396,7 +1384,7 @@ set_comment (const char *bc, const char *ec)
 `-------------------------------------------------------------------*/
 
 void
-set_word_regexp (const char *caller, const char *regexp)
+set_word_regexp (const call_info *caller, const char *regexp)
 {
   const char *msg;
   struct re_pattern_buffer new_word_regexp;
@@ -1586,7 +1574,7 @@ quote_cache (struct obstack *obs, unsigned int age, const 
string_pair *quotes)
 
 token_type
 next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv,
-           const char *caller)
+           const call_info *caller)
 {
   int ch;
   int quote_level;
@@ -1594,20 +1582,21 @@ next_token (token_data *td, int *line, struct obstack 
*obs, bool allow_argv,
 #ifdef ENABLE_CHANGEWORD
   char *orig_text = NULL;
 #endif /* ENABLE_CHANGEWORD */
-  const char *file;
-  int dummy;
+  const char *file = NULL;
   /* The obstack where token data is stored.  Generally token_stack,
      for tokens where argument collection might not use the literal
      token.  But for comments and strings, we can output directly into
      the argument collection obstack obs, if one was provided.  */
   struct obstack *obs_td = &token_stack;
-
   obstack_free (&token_stack, token_bottom);
-  if (!line)
-    line = &dummy;
 
   TOKEN_DATA_TYPE (td) = TOKEN_VOID;
   ch = next_char (false, allow_argv && current_quote_age);
+  if (line)
+    {
+      *line = current_line;
+      file = current_file;
+    }
   if (ch == CHAR_EOF)
     {
 #ifdef DEBUG_INPUT
@@ -1636,8 +1625,6 @@ next_token (token_data *td, int *line, struct obstack 
*obs, bool allow_argv,
       return TOKEN_ARGV;
     }
 
-  file = current_file;
-  *line = current_line;
   if (MATCH (ch, curr_comm.str1, true))
     {
       if (obs)
@@ -1647,10 +1634,17 @@ next_token (token_data *td, int *line, struct obstack 
*obs, bool allow_argv,
        {
          ch = next_char (false, false);
          if (ch == CHAR_EOF)
-           /* Current_file changed to "" if we see CHAR_EOF, use the
-              previous value we stored earlier.  */
-           m4_error_at_line (EXIT_FAILURE, 0, file, *line, caller,
-                             _("end of file in comment"));
+           {
+             /* Current_file changed to "" if we see CHAR_EOF, use
+                the previous value we stored earlier.  */
+             if (!caller)
+               {
+                 assert (line);
+                 current_line = *line;
+                 current_file = file;
+               }
+             m4_error (EXIT_FAILURE, 0, caller, _("end of file in comment"));
+           }
          if (ch == CHAR_MACRO)
            {
              init_macro_token (obs, obs ? td : NULL);
@@ -1699,8 +1693,10 @@ next_token (token_data *td, int *line, struct obstack 
*obs, bool allow_argv,
          next_char (false, false);
        }
 
+      TOKEN_DATA_ORIG_LEN (td) = obstack_object_size (&token_stack);
       obstack_1grow (&token_stack, '\0');
       orig_text = (char *) obstack_finish (&token_stack);
+      TOKEN_DATA_ORIG_TEXT (td) = orig_text;
 
       if (regs.start[1] != -1)
        obstack_grow (&token_stack, orig_text + regs.start[1],
@@ -1743,11 +1739,17 @@ next_token (token_data *td, int *line, struct obstack 
*obs, bool allow_argv,
        {
          ch = next_char (obs != NULL && current_quote_age, false);
          if (ch == CHAR_EOF)
-           /* Current_file changed to "" if we see CHAR_EOF, use
-              the previous value we stored earlier.  */
-           m4_error_at_line (EXIT_FAILURE, 0, file, *line, caller,
-                             _("end of file in string"));
-
+           {
+             /* Current_file changed to "" if we see CHAR_EOF, use
+                the previous value we stored earlier.  */
+             if (!caller)
+               {
+                 assert (line);
+                 current_line = *line;
+                 current_file = file;
+               }
+             m4_error (EXIT_FAILURE, 0, caller, _("end of file in string"));
+           }
          if (ch == CHAR_MACRO)
            init_macro_token (obs, obs ? td : NULL);
          else if (ch == CHAR_QUOTE)
@@ -1784,12 +1786,10 @@ next_token (token_data *td, int *line, struct obstack 
*obs, bool allow_argv,
        TOKEN_DATA_TEXT (td) = NULL;
       TOKEN_DATA_QUOTE_AGE (td) = current_quote_age;
 #ifdef ENABLE_CHANGEWORD
-      if (orig_text == NULL)
-       TOKEN_DATA_ORIG_TEXT (td) = TOKEN_DATA_TEXT (td);
-      else
+      if (!orig_text)
        {
-         TOKEN_DATA_ORIG_TEXT (td) = orig_text;
-         TOKEN_DATA_LEN (td) = strlen (orig_text);
+         TOKEN_DATA_ORIG_TEXT (td) = TOKEN_DATA_TEXT (td);
+         TOKEN_DATA_ORIG_LEN (td) = TOKEN_DATA_LEN (td);
        }
 #endif /* ENABLE_CHANGEWORD */
 #ifdef DEBUG_INPUT
@@ -1948,6 +1948,10 @@ print_token (const char *s, token_type t, token_data *td)
       xfprintf (stderr, "macro: %p\n", TOKEN_DATA_FUNC (td));
       break;
 
+    case TOKEN_ARGV:
+      xfprintf (stderr, "argv:");
+      break;
+
     case TOKEN_EOF:
       xfprintf (stderr, "eof\n");
       break;
@@ -1960,8 +1964,9 @@ lex_debug (void)
 {
   token_type t;
   token_data td;
+  int line;
 
-  while ((t = next_token (&td, NULL, NULL, false, "<debug>")) != TOKEN_EOF)
+  while ((t = next_token (&td, &line, NULL, false, NULL)) != TOKEN_EOF)
     print_token ("lex", t, &td);
 }
 #endif /* DEBUG_INPUT */
diff --git a/src/m4.c b/src/m4.c
index 84cb8e0..e2ef4bc 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -86,46 +86,53 @@ typedef struct macro_definition macro_definition;
 /*------------------------------------------------------------------.
 | Helper for all the error reporting, as a wrapper around          |
 | error_at_line.  Report error message based on FORMAT and ARGS, on |
-| behalf of MACRO, at the location FILE and LINE (but with no      |
-| location if LINE is 0).  If ERRNUM, decode the errno value that   |
-| caused the error.  If STATUS, exit immediately with that status.  |
-| If WARN, prepend 'Warning: '.                                            |
+| behalf of CALLER (if any), otherwise at the global current       |
+| location.  If ERRNUM, decode the errno value that caused the      |
+| error.  If STATUS, exit immediately with that status.  If WARN,   |
+| prepend 'Warning: '.                                             |
 `------------------------------------------------------------------*/
 
 static void
-m4_verror_at_line (bool warn, int status, int errnum, const char *file,
-                  int line, const char *macro, const char *format,
-                  va_list args)
+m4_verror_at_line (bool warn, int status, int errnum, const call_info *caller,
+                  const char *format, va_list args)
 {
   char *full = NULL;
   char *safe_macro = NULL;
+  const char *macro = caller ? caller->name : NULL;
+  size_t len = caller ? caller->name_len : 0;
+  const char *file = caller ? caller->file : current_file;
+  int line = caller ? caller->line : current_line;
 
   /* Sanitize MACRO, since we are turning around and using it in a
      format string.  The allocation is overly conservative, but
      problematic macro names only occur via indir or changeword.  */
-  if (macro && strchr (macro, '%'))
+  if (macro && memchr (macro, '%', len))
     {
-      char *p = safe_macro = xcharalloc (2 * strlen (macro) + 1);
-      do
+      char *p = safe_macro = xcharalloc (2 * len);
+      const char *end = macro + len;
+      while (macro != end)
        {
          if (*macro == '%')
-           *p++ = '%';
+           {
+             *p++ = '%';
+             len++;
+           }
          *p++ = *macro++;
        }
-      while (*macro);
-      *p = '\0';
     }
+  if (macro)
+    /* Use slot 1, so that the rest of the code can use the simpler
+       quotearg interface in slot 0.  */
+    macro = quotearg_n_mem (1, safe_macro ? safe_macro : macro, len);
   /* Prepend warning and the macro name, as needed.  But if that fails
      for non-memory reasons (unlikely), then still use the original
      format.  */
   if (warn && macro)
-    full = xasprintf (_("Warning: %s: %s"),
-                     quotearg (safe_macro ? safe_macro : macro), format);
+    full = xasprintf (_("Warning: %s: %s"), macro, format);
   else if (warn)
     full = xasprintf (_("Warning: %s"), format);
   else if (macro)
-    full = xasprintf (_("%s: %s"),
-                     quotearg (safe_macro ? safe_macro : macro), format);
+    full = xasprintf (_("%s: %s"), macro, format);
   verror_at_line (status, errnum, line ? file : NULL, line,
                  full ? full : format, args);
   free (full);
@@ -134,82 +141,40 @@ m4_verror_at_line (bool warn, int status, int errnum, 
const char *file,
     retcode = EXIT_FAILURE;
 }
 
-/*----------------------------------------------------------------.
-| Wrapper around error.  Report error message based on FORMAT and |
-| subsequent args, on behalf of MACRO, and the current input line |
-| (if any).  If ERRNUM, decode the errno value that caused the   |
-| error.  If STATUS, exit immediately with that status.                  |
-`----------------------------------------------------------------*/
-
-void
-m4_error (int status, int errnum, const char *macro, const char *format, ...)
-{
-  va_list args;
-  va_start (args, format);
-  if (status == EXIT_SUCCESS && warning_status)
-    status = EXIT_FAILURE;
-  m4_verror_at_line (false, status, errnum, current_file, current_line,
-                    macro, format, args);
-  va_end (args);
-}
-
-/*----------------------------------------------------------------.
-| Wrapper around error_at_line.  Report error message based on   |
-| FORMAT and subsequent args, on behalf of MACRO, at the location |
-| FILE and LINE (but with no location if LINE is 0).  If ERRNUM,  |
-| decode the errno value that caused the error.  If STATUS, exit  |
-| immediately with that status.                                          |
-`----------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| Wrapper around error.  Report error message based on FORMAT and   |
+| subsequent args, on behalf of CALLER (if any), and the current    |
+| input line (if any).  If ERRNUM, decode the errno value that      |
+| caused the error.  If STATUS, exit immediately with that status.  |
+`------------------------------------------------------------------*/
 
 void
-m4_error_at_line (int status, int errnum, const char *file, int line,
-                 const char *macro, const char *format, ...)
+m4_error (int status, int errnum, const call_info *caller,
+         const char *format, ...)
 {
   va_list args;
   va_start (args, format);
   if (status == EXIT_SUCCESS && warning_status)
     status = EXIT_FAILURE;
-  m4_verror_at_line (false, status, errnum, file, line, macro, format, args);
+  m4_verror_at_line (false, status, errnum, caller, format, args);
   va_end (args);
 }
 
 /*------------------------------------------------------------------.
 | Wrapper around error.  Report warning message based on FORMAT and |
-| subsequent args, on behalf of MACRO, and the current input line   |
-| (if any).  If ERRNUM, decode the errno value that caused the     |
-| warning.                                                         |
+| subsequent args, on behalf of CALLER (if any), and the current    |
+| input line (if any).  If ERRNUM, decode the errno value that      |
+| caused the warning.                                              |
 `------------------------------------------------------------------*/
 
 void
-m4_warn (int errnum, const char *macro, const char *format, ...)
-{
-  va_list args;
-  if (!suppress_warnings)
-    {
-      va_start (args, format);
-      m4_verror_at_line (true, warning_status, errnum, current_file,
-                        current_line, macro, format, args);
-      va_end (args);
-    }
-}
-
-/*----------------------------------------------------------------.
-| Wrapper around error_at_line.  Report warning message based on  |
-| FORMAT and subsequent args, on behalf of MACRO, at the location |
-| FILE and LINE (but with no location if LINE is 0).  If ERRNUM,  |
-| decode the errno value that caused the warning.                |
-`----------------------------------------------------------------*/
-
-void
-m4_warn_at_line (int errnum, const char *file, int line, const char *macro,
-                const char *format, ...)
+m4_warn (int errnum, const call_info *caller, const char *format, ...)
 {
   va_list args;
   if (!suppress_warnings)
     {
       va_start (args, format);
-      m4_verror_at_line (true, warning_status, errnum, file, line, macro,
-                        format, args);
+      m4_verror_at_line (true, warning_status, errnum, caller, format, args);
       va_end (args);
     }
 }
@@ -239,7 +204,7 @@ usage (int status)
 {
   if (status != EXIT_SUCCESS)
     xfprintf (stderr, _("Try `%s --help' for more information.\n"),
-              program_name);
+             program_name);
   else
     {
       xprintf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);
@@ -652,23 +617,20 @@ main (int argc, char *const *argv, char *const *envp)
        {
        case 'D':
          {
-           /* defines->arg is read-only, so we need a copy.  */
-           char *macro_name = xstrdup (defines->arg);
-           char *macro_value = strchr (macro_name, '=');
-           if (macro_value)
-             *macro_value++ = '\0';
-           define_user_macro (macro_name, strlen (macro_name),
-                              macro_value, SYMBOL_INSERT);
-           free (macro_name);
+           const char *value = strchr (defines->arg, '=');
+           size_t len = value ? value - defines->arg : strlen (defines->arg);
+           define_user_macro (defines->arg, len, value ? value + 1 : "",
+                              SYMBOL_INSERT);
          }
          break;
 
        case 'U':
-         lookup_symbol (defines->arg, SYMBOL_DELETE);
+         lookup_symbol (defines->arg, strlen (defines->arg), SYMBOL_DELETE);
          break;
 
        case 't':
-         sym = lookup_symbol (defines->arg, SYMBOL_INSERT);
+         sym = lookup_symbol (defines->arg, strlen (defines->arg),
+                              SYMBOL_INSERT);
          SYMBOL_TRACED (sym) = true;
          break;
 
diff --git a/src/m4.h b/src/m4.h
index b2e55e5..d16d87a 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -50,6 +50,7 @@
 #include "vasnprintf.h"
 #include "verror.h"
 #include "xalloc.h"
+#include "xmemdup0.h"
 #include "xprintf.h"
 #include "xvasprintf.h"
 
@@ -150,19 +151,16 @@ struct call_info
   int trace : 1;       /* True to trace this macro.  */
   int debug_level : 31;        /* The debug level for tracing the macro call.  
*/
   const char *name;    /* The macro name.  */
+  size_t name_len;     /* The length of name.  */
 };
 typedef struct call_info call_info;
 
 extern int retcode;
 extern const char *program_name;
 
-void m4_error (int, int, const char *, const char *, ...)
+void m4_error (int, int, const call_info *, const char *, ...)
   M4_GNUC_PRINTF (4, 5);
-void m4_error_at_line (int, int, const char *, int, const char *,
-                      const char *, ...) M4_GNUC_PRINTF (6, 7);
-void m4_warn (int, const char *, const char *, ...) M4_GNUC_PRINTF (3, 4);
-void m4_warn_at_line (int, const char *, int, const char *,
-                     const char *, ...) M4_GNUC_PRINTF (5, 6);
+void m4_warn (int, const call_info *, const char *, ...) M4_GNUC_PRINTF (3, 4);
 
 #ifdef USE_STACKOVF
 void setup_stackovf_trap (char *const *, char *const *,
@@ -256,7 +254,7 @@ extern FILE *debug;
 void debug_init (void);
 int debug_decode (const char *);
 void debug_flush_files (void);
-bool debug_set_output (const char *, const char *);
+bool debug_set_output (const call_info *, const char *);
 void debug_message_prefix (void);
 
 void trace_prepre (const call_info *);
@@ -366,6 +364,7 @@ struct token_data
             portion that matched the () group to form a macro name.
             Otherwise, this field is unused.  */
          const char *original_text;
+         size_t original_len; /* Length of original_text.  */
 #endif
        }
       u_t;
@@ -391,6 +390,7 @@ struct token_data
 #define TOKEN_DATA_QUOTE_AGE(Td)       ((Td)->u.u_t.quote_age)
 #ifdef ENABLE_CHANGEWORD
 # define TOKEN_DATA_ORIG_TEXT(Td)      ((Td)->u.u_t.original_text)
+# define TOKEN_DATA_ORIG_LEN(Td)       ((Td)->u.u_t.original_len)
 #endif
 #define TOKEN_DATA_FUNC(Td)            ((Td)->u.func)
 
@@ -400,8 +400,8 @@ typedef enum token_data_type token_data_type;
 void input_init (void);
 token_type peek_token (void);
 token_type next_token (token_data *, int *, struct obstack *, bool,
-                      const char *);
-void skip_line (const char *);
+                      const call_info *);
+void skip_line (const call_info *);
 
 /* push back input */
 void make_text_link (struct obstack *, token_chain **, token_chain **);
@@ -409,10 +409,10 @@ void push_file (FILE *, const char *, bool);
 void append_macro (struct obstack *, builtin_func *, token_chain **,
                   token_chain **);
 void push_macro (struct obstack *, builtin_func *);
-struct obstack *push_string_init (void);
+struct obstack *push_string_init (const char *, int);
 bool push_token (token_data *, int, bool);
 void push_string_finish (void);
-struct obstack *push_wrapup_init (token_chain ***);
+struct obstack *push_wrapup_init (const call_info *, token_chain ***);
 void push_wrapup_finish (void);
 bool pop_wrapup (void);
 void input_print (struct obstack *);
@@ -433,7 +433,7 @@ extern string_pair curr_quote;
 void set_quotes (const char *, const char *);
 void set_comment (const char *, const char *);
 #ifdef ENABLE_CHANGEWORD
-void set_word_regexp (const char *, const char *);
+void set_word_regexp (const call_info *, const char *);
 #endif
 unsigned int quote_age (void);
 bool safe_quotes (void);
@@ -478,6 +478,7 @@ struct symbol
   int pending_expansions;
 
   char *name;
+  size_t len;
   token_data data;  /* Type should be only TOKEN_TEXT or TOKEN_FUNC.  */
 };
 
@@ -489,6 +490,7 @@ struct symbol
 #define SYMBOL_DELETED(S)      ((S)->deleted)
 #define SYMBOL_PENDING_EXPANSIONS(S) ((S)->pending_expansions)
 #define SYMBOL_NAME(S)         ((S)->name)
+#define SYMBOL_NAME_LEN(S)     ((S)->len)
 #define SYMBOL_TYPE(S)         (TOKEN_DATA_TYPE (&(S)->data))
 #define SYMBOL_TEXT(S)         (TOKEN_DATA_TEXT (&(S)->data))
 #define SYMBOL_FUNC(S)         (TOKEN_DATA_FUNC (&(S)->data))
@@ -503,7 +505,7 @@ extern symbol **symtab;
 
 void free_symbol (symbol *sym);
 void symtab_init (void);
-symbol *lookup_symbol (const char *, symbol_lookup);
+symbol *lookup_symbol (const char *, size_t, symbol_lookup);
 void hack_all_symbols (hack_symbol *, void *);
 
 /* File: macro.c  --- macro expansion.  */
@@ -573,8 +575,8 @@ struct re_registers;
 #define DEFAULT_MACRO_SEQUENCE "\\$\\({[^}]*}\\|[0-9][0-9]+\\)"
 
 void builtin_init (void);
-bool bad_argc (const char *, int, unsigned int, unsigned int);
-void define_builtin (const char *, const builtin *, symbol_lookup);
+bool bad_argc (const call_info *, int, unsigned int, unsigned int);
+void define_builtin (const char *, size_t, const builtin *, symbol_lookup);
 void set_macro_sequence (const char *);
 void free_regex (void);
 void define_user_macro (const char *, size_t, const char *, symbol_lookup);
@@ -598,7 +600,7 @@ FILE *m4_path_search (const char *, char **);
 
 /* File: eval.c  --- expression evaluation.  */
 
-bool evaluate (const char *, const char *, int32_t *);
+bool evaluate (const call_info *, const char *, int32_t *);
 
 /* File: format.c  --- printf like formatting.  */
 
diff --git a/src/macro.c b/src/macro.c
index 2a5b52a..0b57436 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -29,7 +29,7 @@
 #endif /* DEBUG_MACRO */
 
 /* Opaque structure describing all arguments to a macro, including the
-   macro name at index 0.  The lifetime of argv0 is only guaranteed
+   macro name at index 0.  The lifetime of info 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  */
@@ -53,8 +53,6 @@ struct macro_arguments
   bool_bitfield flatten : 1;
   /* True if any token contains builtins.  */
   bool_bitfield has_func : 1;
-  const char *argv0; /* The macro name being expanded.  */
-  size_t argv0_len; /* Length of argv0.  */
   /* The value of quote_age used when parsing all arguments in this
      object, or 0 if quote_age changed during parsing or if any of the
      arguments might contain content that can affect rescan.  */
@@ -221,6 +219,7 @@ expand_input (void)
   TOKEN_DATA_LEN (&empty_token) = 0;
 #ifdef ENABLE_CHANGEWORD
   TOKEN_DATA_ORIG_TEXT (&empty_token) = "";
+  TOKEN_DATA_ORIG_LEN (&empty_token) = 0;
 #endif
 
   while ((t = next_token (&td, &line, NULL, false, NULL)) != TOKEN_EOF)
@@ -301,7 +300,8 @@ expand_token (struct obstack *obs, token_type t, token_data 
*td, int line,
       break;
 
     case TOKEN_WORD:
-      sym = lookup_symbol (TOKEN_DATA_TEXT (td), SYMBOL_LOOKUP);
+      sym = lookup_symbol (TOKEN_DATA_TEXT (td), TOKEN_DATA_LEN (td),
+                          SYMBOL_LOOKUP);
       if (sym == NULL || SYMBOL_TYPE (sym) == TOKEN_VOID
          || (SYMBOL_TYPE (sym) == TOKEN_FUNC
              && SYMBOL_BLIND_NO_ARGS (sym)
@@ -309,7 +309,7 @@ expand_token (struct obstack *obs, token_type t, token_data 
*td, int line,
        {
 #ifdef ENABLE_CHANGEWORD
          divert_text (obs, TOKEN_DATA_ORIG_TEXT (td),
-                      TOKEN_DATA_LEN (td), line);
+                      TOKEN_DATA_ORIG_LEN (td), line);
 #else
          divert_text (obs, TOKEN_DATA_TEXT (td), TOKEN_DATA_LEN (td), line);
 #endif /* !ENABLE_CHANGEWORD */
@@ -344,12 +344,12 @@ expand_token (struct obstack *obs, token_type t, 
token_data *td, int line,
 `-------------------------------------------------------------------*/
 
 static bool
-expand_argument (struct obstack *obs, token_data *argp, const char *caller)
+expand_argument (struct obstack *obs, token_data *argp,
+                const call_info *caller)
 {
   token_type t;
   token_data td;
   int paren_level;
-  const char *file = current_file;
   int line = current_line;
   unsigned int age = quote_age ();
   bool first = true;
@@ -414,10 +414,8 @@ expand_argument (struct obstack *obs, token_data *argp, 
const char *caller)
          break;
 
        case TOKEN_EOF:
-         /* Current_file changed to "" if we see TOKEN_EOF, use the
-            previous value we stored earlier.  */
-         m4_error_at_line (EXIT_FAILURE, 0, file, line, caller,
-                           _("end of file in argument list"));
+         m4_error (EXIT_FAILURE, 0, caller,
+                   _("end of file in argument list"));
          break;
 
        case TOKEN_WORD:
@@ -495,8 +493,6 @@ collect_arguments (symbol *sym, call_info *info, struct 
obstack *arguments,
   args.has_ref = false;
   args.flatten = !groks_macro_args;
   args.has_func = false;
-  args.argv0 = SYMBOL_NAME (sym);
-  args.argv0_len = strlen (args.argv0);
   args.quote_age = quote_age ();
   args.info = info;
   args.level = expansion_level - 1;
@@ -506,11 +502,11 @@ collect_arguments (symbol *sym, call_info *info, struct 
obstack *arguments,
   if (peek_token () == TOKEN_OPEN)
     {
       /* gobble parenthesis */
-      next_token (&td, NULL, NULL, false, SYMBOL_NAME (sym));
+      next_token (&td, NULL, NULL, false, info);
       do
        {
          tdp = (token_data *) obstack_alloc (arguments, sizeof *tdp);
-         more_args = expand_argument (arguments, tdp, SYMBOL_NAME (sym));
+         more_args = expand_argument (arguments, tdp, info);
 
          if ((TOKEN_DATA_TYPE (tdp) == TOKEN_TEXT && !TOKEN_DATA_LEN (tdp))
              || (!groks_macro_args && TOKEN_DATA_TYPE (tdp) == TOKEN_FUNC))
@@ -622,10 +618,6 @@ expand_macro (symbol *sym)
   int level = expansion_level; /* Expansion level of this macro.  */
   call_info my_call_info;      /* Context of this macro.  */
 
-  /* TODO - make m4_warn use optional call_info, so we don't need these.  */
-  const char *loc_close_file;
-  int loc_close_line;
-
   /* Obstack preparation.  */
   if (level >= stacks_count)
     {
@@ -670,6 +662,7 @@ expand_macro (symbol *sym)
   my_call_info.trace = (debug_level & DEBUG_TRACE_ALL) || SYMBOL_TRACED (sym);
   my_call_info.debug_level = debug_level;
   my_call_info.name = SYMBOL_NAME (sym);
+  my_call_info.name_len = SYMBOL_NAME_LEN (sym);
   trace_prepre (&my_call_info);
 
   /* Collect the arguments.  */
@@ -677,23 +670,13 @@ expand_macro (symbol *sym)
                            stacks[level].argv);
   args_scratch = obstack_finish (stacks[level].args);
 
-  /*  Temporarily reset the location so that error messages are
-      tracked to the macro name.  */
-  loc_close_file = current_file;
-  loc_close_line = current_line;
-  current_file = my_call_info.file;
-  current_line = my_call_info.line;
-
   /* The actual macro call.  */
-  expansion = push_string_init ();
+  expansion = push_string_init (my_call_info.file, my_call_info.line);
   call_macro (sym, argv, expansion);
   push_string_finish ();
 
   /* Cleanup.  */
-  current_file = loc_close_file;
-  current_line = loc_close_line;
   argv->info = NULL;
-
   --expansion_level;
   --SYMBOL_PENDING_EXPANSIONS (sym);
 
@@ -714,7 +697,7 @@ expand_macro (symbol *sym)
          if (debug_macro_level & PRINT_ARGCOUNT_CHANGES)
            xfprintf (debug, "m4debug: -%d- `%s' in use, level=%d, "
                      "refcount=%zu, argcount=%zu\n", my_call_info.call_id,
-                     argv->argv0, level, stacks[level].refcount,
+                     my_call_info.name, level, stacks[level].refcount,
                      stacks[level].argcount);
        }
       else
@@ -916,7 +899,10 @@ arg_text (macro_arguments *argv, unsigned int arg, bool 
flatten)
   struct obstack *obs; /* Scratch space; cleaned at end of macro_expand.  */
 
   if (arg == 0)
-    return argv->argv0;
+    {
+      assert (argv->info);
+      return argv->info->name;
+    }
   if (arg >= argv->argc)
     return "";
   token = arg_token (argv, arg, NULL, flatten);
@@ -1119,7 +1105,10 @@ bool
 arg_empty (macro_arguments *argv, unsigned int arg)
 {
   if (arg == 0)
-    return argv->argv0_len == 0;
+    {
+      assert (argv->info);
+      return argv->info->name_len == 0;
+    }
   if (arg >= argv->argc)
     return true;
   return arg_token (argv, arg, NULL, false) == &empty_token;
@@ -1135,7 +1124,10 @@ arg_len (macro_arguments *argv, unsigned int arg)
   size_t len;
 
   if (arg == 0)
-    return argv->argv0_len;
+    {
+      assert (argv->info);
+      return argv->info->name_len;
+    }
   if (arg >= argv->argc)
     return 0;
   token = arg_token (argv, arg, NULL, false);
@@ -1450,12 +1442,11 @@ make_argv_ref (macro_arguments *argv, const char 
*argv0, size_t argv0_len,
     }
   new_argv->argc = argv->argc - 1;
   new_argv->inuse = false;
-  new_argv->argv0 = argv0;
-  new_argv->argv0_len = argv0_len;
   new_argv->quote_age = argv->quote_age;
   new_argv->info = info;
   info->trace = (argv->info->debug_level & DEBUG_TRACE_ALL) || trace;
   info->name = argv0;
+  info->name_len = argv0_len;
   new_argv->level = argv->level;
   return new_argv;
 }
@@ -1469,7 +1460,8 @@ push_arg (struct obstack *obs, macro_arguments *argv, 
unsigned int arg)
     {
       /* Always push copy of arg 0, since its lifetime is not
         guaranteed beyond expand_macro.  */
-      obstack_grow (obs, argv->argv0, argv->argv0_len);
+      assert (argv->info);
+      obstack_grow (obs, argv->info->name, argv->info->name_len);
       return;
     }
   if (arg >= argv->argc)
@@ -1538,7 +1530,7 @@ wrap_args (macro_arguments *argv)
   if ((argv->argc == 2 || no_gnu_extensions) && arg_empty (argv, 1))
     return;
 
-  obs = push_wrapup_init (&end);
+  obs = push_wrapup_init (argv->info, &end);
   for (i = 1; i < (no_gnu_extensions ? 2 : argv->argc); i++)
     {
       if (i != 1)
diff --git a/src/symtab.c b/src/symtab.c
index dac49d7..d4da200 100644
--- a/src/symtab.c
+++ b/src/symtab.c
@@ -62,19 +62,20 @@ show_profile (void)
     }
 }
 
-/* Like strcmp (S1, S2), but also track profiling statistics.  */
+/* Like memcmp (S1, S2, L), but also track profiling statistics.  */
 static int
-profile_strcmp (const char *s1, const char *s2)
+profile_memcmp (const char *s1, const char *s2, size_t l)
 {
-  int i = 1;
+  int i = 0;
   int result;
-  while (*s1 && *s1 == *s2)
+  while (l && *s1 == *s2)
     {
       s1++;
       s2++;
       i++;
+      l--;
     }
-  result = (unsigned char) *s1 - (unsigned char) *s2;
+  result = l ? (unsigned char) *s1 - (unsigned char) *s2 : 0;
   profiles[current_mode].comparisons++;
   if (result != 0)
     profiles[current_mode].misses++;
@@ -82,7 +83,7 @@ profile_strcmp (const char *s1, const char *s2)
   return result;
 }
 
-# define strcmp profile_strcmp
+# define memcmp profile_memcmp
 #endif /* DEBUG_SYM */
 
 
@@ -111,19 +112,18 @@ symtab_init (void)
 }
 
 /*--------------------------------------------------.
-| Return a hashvalue for a string, from GNU-emacs.  |
+| Return a hashvalue for a string S of length LEN.  |
 `--------------------------------------------------*/
 
 static size_t
-hash (const char *s)
+hash (const char *s, size_t len)
 {
-  register size_t val = 0;
+  size_t val = len;
 
-  register const char *ptr = s;
-  register char ch;
-
-  while ((ch = *ptr++) != '\0')
-    val = (val << 7) + (val >> (sizeof (val) * CHAR_BIT - 7)) + ch;
+  /* This algorithm was originally borrowed from GNU Emacs, but has
+     been modified to allow embedded NUL.  */
+  while (len--)
+    val = (val << 7) + (val >> (sizeof val * CHAR_BIT - 7)) + to_uchar (*s++);
   return val;
 }
 
@@ -146,20 +146,20 @@ free_symbol (symbol *sym)
 }
 
 /*-------------------------------------------------------------------.
-| Search in, and manipulation of the symbol table, are all done by   |
-| lookup_symbol ().  It basically hashes NAME to a list in the      |
-| symbol table, and searches this list for the first occurrence of a |
-| symbol with the name.                                                     |
-|                                                                   |
+| Searches and manipulation of the symbol table are all done by      |
+| lookup_symbol ().  It basically hashes NAME, of length LEN, to a   |
+| list in the symbol table, and searches this list for the first     |
+| occurrence of a symbol with the name.                              |
+|                                                                    |
 | The MODE parameter determines what lookup_symbol () will do.  It   |
-| can either just do a lookup, do a lookup and insert if not        |
+| can either just do a lookup, do a lookup and insert if not         |
 | present, do an insertion even if the name is already in the list,  |
 | delete the first occurrence of the name on the list, or delete all |
-| occurrences of the name on the list.                              |
+| occurrences of the name on the list.                               |
 `-------------------------------------------------------------------*/
 
 symbol *
-lookup_symbol (const char *name, symbol_lookup mode)
+lookup_symbol (const char *name, size_t len, symbol_lookup mode)
 {
   size_t h;
   int cmp = 1;
@@ -171,12 +171,13 @@ lookup_symbol (const char *name, symbol_lookup mode)
   profiles[mode].entry++;
 #endif /* DEBUG_SYM */
 
-  h = hash (name);
+  h = hash (name, len);
   sym = symtab[h % hash_table_size];
 
   for (prev = NULL; sym != NULL; prev = sym, sym = sym->next)
     {
-      cmp = strcmp (SYMBOL_NAME (sym), name);
+      cmp = (len < SYMBOL_NAME_LEN (sym) ? -1 : len > SYMBOL_NAME_LEN (sym) ? 1
+            : memcmp (SYMBOL_NAME (sym), name, len));
       if (cmp >= 0)
        break;
     }
@@ -210,7 +211,8 @@ lookup_symbol (const char *name, symbol_lookup mode)
              sym = (symbol *) xmalloc (sizeof (symbol));
              SYMBOL_TYPE (sym) = TOKEN_VOID;
              SYMBOL_TRACED (sym) = SYMBOL_TRACED (old);
-             SYMBOL_NAME (sym) = xstrdup (name);
+             SYMBOL_NAME (sym) = xmemdup0 (name, len);
+             SYMBOL_NAME_LEN (sym) = len;
              SYMBOL_SHADOWED (sym) = false;
              SYMBOL_MACRO_ARGS (sym) = false;
              SYMBOL_BLIND_NO_ARGS (sym) = false;
@@ -234,7 +236,8 @@ lookup_symbol (const char *name, symbol_lookup mode)
       sym = (symbol *) xmalloc (sizeof (symbol));
       SYMBOL_TYPE (sym) = TOKEN_VOID;
       SYMBOL_TRACED (sym) = false;
-      SYMBOL_NAME (sym) = xstrdup (name);
+      SYMBOL_NAME (sym) = xmemdup0 (name, len);
+      SYMBOL_NAME_LEN (sym) = len;
       SYMBOL_SHADOWED (sym) = false;
       SYMBOL_MACRO_ARGS (sym) = false;
       SYMBOL_BLIND_NO_ARGS (sym) = false;
@@ -287,7 +290,8 @@ lookup_symbol (const char *name, symbol_lookup mode)
            sym = (symbol *) xmalloc (sizeof (symbol));
            SYMBOL_TYPE (sym) = TOKEN_VOID;
            SYMBOL_TRACED (sym) = true;
-           SYMBOL_NAME (sym) = xstrdup (name);
+           SYMBOL_NAME (sym) = xmemdup0 (name, len);
+           SYMBOL_NAME_LEN (sym) = len;
            SYMBOL_SHADOWED (sym) = false;
            SYMBOL_MACRO_ARGS (sym) = false;
            SYMBOL_BLIND_NO_ARGS (sym) = false;
@@ -348,28 +352,32 @@ symtab_debug (void)
   const char *text;
   symbol *s;
   int delete;
+  size_t len;
+  int line;
   static int i;
 
-  while (next_token (&td, NULL, NULL, false, "<debug>") == TOKEN_WORD)
+  while (next_token (&td, &line, NULL, false, NULL) == TOKEN_WORD)
     {
       text = TOKEN_DATA_TEXT (&td);
+      len = TOKEN_DATA_LEN (&td);
       if (*text == '_')
        {
          delete = 1;
          text++;
+         len--;
        }
       else
        delete = 0;
 
-      s = lookup_symbol (text, SYMBOL_LOOKUP);
+      s = lookup_symbol (text, len, SYMBOL_LOOKUP);
 
       if (s == NULL)
        xprintf ("Name `%s' is unknown\n", text);
 
       if (delete)
-       (void) lookup_symbol (text, SYMBOL_DELETE);
+       lookup_symbol (text, len, SYMBOL_DELETE);
       else
-       (void) lookup_symbol (text, SYMBOL_INSERT);
+       lookup_symbol (text, len, SYMBOL_INSERT);
     }
   symtab_print_list (i++);
 }
@@ -383,9 +391,9 @@ symtab_print_list (int i)
   xprintf ("Symbol dump #%d:\n", i);
   for (h = 0; h < hash_table_size; h++)
     for (sym = symtab[h]; sym != NULL; sym = sym->next)
-      xprintf ("\tname %s, bucket %lu, addr %p, next %p, "
+      xprintf ("\tname %s, len %zu, bucket %lu, addr %p, next %p, "
               "flags%s%s%s, pending %d\n",
-              SYMBOL_NAME (sym),
+              SYMBOL_NAME (sym), SYMBOL_NAME_LEN (sym),
               (unsigned long int) h, sym, SYMBOL_NEXT (sym),
               SYMBOL_TRACED (sym) ? " traced" : "",
               SYMBOL_SHADOWED (sym) ? " shadowed" : "",


hooks/post-receive
--
GNU M4 source repository




reply via email to

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