m4-commit
[Top][All Lists]
Advanced

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

[SCM] GNU M4 source repository branch, master, updated. cvs-readonly-138


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, master, updated. cvs-readonly-138-g488e059
Date: Wed, 18 Jun 2008 13:29:08 +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=488e0594caac30004bad8ec4e6ad61b749a8bd20

The branch, master has been updated
       via  488e0594caac30004bad8ec4e6ad61b749a8bd20 (commit)
       via  7ae3299164295bb67a1c8ba46d64e01e7e82d4df (commit)
       via  c05ce945d2a377eb37365eada8f0dc402479a94e (commit)
      from  b4c7d8547c2072cf84237d2abd3474c17b009081 (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 488e0594caac30004bad8ec4e6ad61b749a8bd20
Author: Eric Blake <address@hidden>
Date:   Wed Jun 18 06:33:22 2008 -0600

    Whitespace cleanup.
    
    * m4/m4module.h: Use consistent spacing for pointer parameters.
    * m4/m4private.h: Likewise.
    
    Signed-off-by: Eric Blake <address@hidden>

commit 7ae3299164295bb67a1c8ba46d64e01e7e82d4df
Author: Eric Blake <address@hidden>
Date:   Wed Jun 18 06:31:44 2008 -0600

    Stage 25b: Handle embedded NUL in changesyntax and friends.
    
    * m4/m4module.h (m4_set_quotes, m4_set_comment, m4_set_syntax):
    Add parameter.
    (m4_reset_syntax): New prototype.
    * m4/syntax.c (add_syntax_set, subtract_syntax_set)
    (set_syntax_set, m4_set_quotes, m4_set_comment): Add parameter, to
    handle embedded NUL.
    (m4_set_syntax): Likewise.  Also, split code to reset the table...
    (m4_reset_syntax): ...into a new function.
    (m4_syntax_create): Adjust callers.
    * m4/input.c (match_input, MATCH): Add parameter.
    (m4__next_token, m4__next_token_is_open): Adjust callers.
    * modules/m4.h (m4_expand_ranges_func): Add parameter.
    * modules/m4.c (dumpdef): Handle NUL in dumped quotes.
    (changequote, changecom, translit, m4_expand_ranges): Track
    delimiter length.
    * modules/gnu.c (changesyntax): Handle embedded NUL.
    * src/freeze.c (reload_frozen_state): Adjust callers.
    * tests/freeze.at (reloading nul): Enhance test.
    * tests/null.m4: Likewise.
    * tests/null.out: Update expected output.
    * tests/null.err: Likewise.
    
    Signed-off-by: Eric Blake <address@hidden>

commit c05ce945d2a377eb37365eada8f0dc402479a94e
Author: Eric Blake <address@hidden>
Date:   Sat Jun 14 11:02:12 2008 -0600

    Stage 25a: Use obstack_printf for easier output.
    
    * ltdl/m4/gnulib-cache.m4: Import obstack-printf-posix module.
    * m4/macro.c (trace_format): Delete; use obstack_printf instead.
    (trace_header, trace_pre, trace_post): All callers updated.
    * m4/output.c (m4_shipout_int, m4_tmpname): Use obstack_printf.
    (m4_divert_text): Speed up syncline output.
    * modules/m4.c (dumpdef): Handle embedded NUL.
    (numb_obstack): Speed up eval output.
    (maketemp): Use obstack_printf.
    * modules/format.c (format): Likewise.
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog               |   49 +++++++++++++
 ltdl/m4/gnulib-cache.m4 |    4 +-
 m4/input.c              |   58 +++++++++-------
 m4/m4module.h           |   42 ++++++-----
 m4/m4private.h          |    2 +-
 m4/macro.c              |   91 ++++--------------------
 m4/output.c             |   24 ++-----
 m4/syntax.c             |  185 +++++++++++++++++++++++++++++------------------
 modules/format.c        |   49 ++++---------
 modules/gnu.c           |   31 ++++++--
 modules/m4.c            |  105 +++++++++++++++------------
 modules/m4.h            |    3 +-
 src/freeze.c            |   10 ++-
 tests/freeze.at         |    7 +-
 tests/null.err          |  Bin 460 -> 599 bytes
 tests/null.m4           |  Bin 6634 -> 7200 bytes
 tests/null.out          |  Bin 419 -> 524 bytes
 17 files changed, 353 insertions(+), 307 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 19631a6..7dc8277 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,54 @@
+2008-06-18  Eric Blake  <address@hidden>
+
+       Whitespace cleanup.
+       * m4/m4module.h: Use consistent spacing for pointer parameters.
+       * m4/m4private.h: Likewise.
+
+       Stage 25b: Handle embedded NUL in changesyntax and friends.
+       Track quote and comment delimiters by length, to allow embedded
+       NUL.  Improve changesyntax to support assigning syntax to NUL.
+       Memory impact: none.
+       Speed impact: none noticed.
+       * m4/m4module.h (m4_set_quotes, m4_set_comment, m4_set_syntax):
+       Add parameter.
+       (m4_reset_syntax): New prototype.
+       * m4/syntax.c (add_syntax_set, subtract_syntax_set)
+       (set_syntax_set, m4_set_quotes, m4_set_comment): Add parameter, to
+       handle embedded NUL.
+       (m4_set_syntax): Likewise.  Also, split code to reset the table...
+       (m4_reset_syntax): ...into a new function.
+       (m4_syntax_create): Adjust callers.
+       * m4/input.c (match_input, MATCH): Add parameter.
+       (m4__next_token, m4__next_token_is_open): Adjust callers.
+       * modules/m4.h (m4_expand_ranges_func): Add parameter.
+       * modules/m4.c (dumpdef): Handle NUL in dumped quotes.
+       (changequote, changecom, translit, m4_expand_ranges): Track
+       delimiter length.
+       * modules/gnu.c (changesyntax): Handle embedded NUL.
+       * src/freeze.c (reload_frozen_state): Adjust callers.
+       * tests/freeze.at (reloading nul): Enhance test.
+       * tests/null.m4: Likewise.
+       * tests/null.out: Update expected output.
+       * tests/null.err: Likewise.
+
 2008-06-16  Eric Blake  <address@hidden>
 
+       Stage 25a: Use obstack_printf for easier output.
+       Convert macro tracing and other locations to use obstack_printf
+       rather than hand-rolled equivalents.  Ensure that embedded NUL in
+       trace output does not truncate the trace string.
+       Memory impact: none.
+       Speed impact: none noticed.
+       * ltdl/m4/gnulib-cache.m4: Import obstack-printf-posix module.
+       * m4/macro.c (trace_format): Delete; use obstack_printf instead.
+       (trace_header, trace_pre, trace_post): All callers updated.
+       * m4/output.c (m4_shipout_int, m4_tmpname): Use obstack_printf.
+       (m4_divert_text): Speed up syncline output.
+       * modules/m4.c (dumpdef): Handle embedded NUL.
+       (numb_obstack): Speed up eval output.
+       (maketemp): Use obstack_printf.
+       * modules/format.c (format): Likewise.
+
        Add missing const qualifications.
        * m4/resyntax.c (m4_resyntax_map): Declare array elements as
        const.
diff --git a/ltdl/m4/gnulib-cache.m4 b/ltdl/m4/gnulib-cache.m4
index f5f442c..fb91ba5 100644
--- a/ltdl/m4/gnulib-cache.m4
+++ b/ltdl/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=libgnu 
--source-base=gnu --m4-base=ltdl/m4 --doc-base=doc --aux-dir=build-aux 
--with-tests --libtool --macro-prefix=M4 assert autobuild avltree-oset 
binary-io clean-temp cloexec close-stream closein config-h configmake dirname 
error exit fdl fflush filenamecat flexmember fopen-safer fseeko gendocs gettext 
git-version-gen gnumakefile gnupload gpl-3.0 intprops memmem mkstemp obstack 
progname propername quote regex regexprops-generic sprintf-posix stdbool 
stdlib-safer strnlen strtod strtol tempname unlocked-io vasnprintf-posix verror 
xalloc xalloc-die xmemdup0 xprintf-posix xstrndup xvasprintf-posix
+#   gnulib-tool --import --dir=. --local-dir=local --lib=libgnu 
--source-base=gnu --m4-base=ltdl/m4 --doc-base=doc --aux-dir=build-aux 
--with-tests --libtool --macro-prefix=M4 assert autobuild avltree-oset 
binary-io clean-temp cloexec close-stream closein config-h configmake dirname 
error exit fdl fflush filenamecat flexmember fopen-safer fseeko gendocs gettext 
git-version-gen gnumakefile gnupload gpl-3.0 intprops memmem mkstemp obstack 
obstack-printf-posix progname propername quote regex regexprops-generic 
sprintf-posix stdbool stdlib-safer strnlen strtod strtol tempname unlocked-io 
vasnprintf-posix verror xalloc xalloc-die xmemdup0 xprintf-posix xstrndup 
xvasprintf-posix
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([local])
-gl_MODULES([assert autobuild avltree-oset binary-io clean-temp cloexec 
close-stream closein config-h configmake dirname error exit fdl fflush 
filenamecat flexmember fopen-safer fseeko gendocs gettext git-version-gen 
gnumakefile gnupload gpl-3.0 intprops memmem mkstemp obstack progname 
propername quote regex regexprops-generic sprintf-posix stdbool stdlib-safer 
strnlen strtod strtol tempname unlocked-io vasnprintf-posix verror xalloc 
xalloc-die xmemdup0 xprintf-posix xstrndup xvasprintf-posix])
+gl_MODULES([assert autobuild avltree-oset binary-io clean-temp cloexec 
close-stream closein config-h configmake dirname error exit fdl fflush 
filenamecat flexmember fopen-safer fseeko gendocs gettext git-version-gen 
gnumakefile gnupload gpl-3.0 intprops memmem mkstemp obstack 
obstack-printf-posix progname propername quote regex regexprops-generic 
sprintf-posix stdbool stdlib-safer strnlen strtod strtol tempname unlocked-io 
vasnprintf-posix verror xalloc xalloc-die xmemdup0 xprintf-posix xstrndup 
xvasprintf-posix])
 gl_AVOID([])
 gl_SOURCE_BASE([gnu])
 gl_M4_BASE([ltdl/m4])
diff --git a/m4/input.c b/m4/input.c
index 212c1c6..ea59b44 100644
--- a/m4/input.c
+++ b/m4/input.c
@@ -123,7 +123,7 @@ static      void    init_builtin_token      (m4 *, 
m4_obstack *,
                                         m4_symbol_value *);
 static void    append_quote_token      (m4 *, m4_obstack *,
                                         m4_symbol_value *);
-static bool    match_input             (m4 *, const char *, bool);
+static bool    match_input             (m4 *, const char *, size_t, bool);
 static int     next_char               (m4 *, bool, bool, bool);
 static int     peek_char               (m4 *, bool);
 static bool    pop_input               (m4 *, bool);
@@ -1352,9 +1352,9 @@ m4_skip_line (m4 *context, const m4_call_info *caller)
 }
 
 
-/* This function is for matching a string against a prefix of the
-   input stream.  If the string S matches the input and CONSUME is
-   true, the input is discarded; otherwise any characters read are
+/* If the string S of length LEN matches the next characters of the
+   input stream, return true.  If CONSUME is true and a match is
+   found, the input is discarded; otherwise any characters read are
    pushed back again.  The function is used only when multicharacter
    quotes or comment delimiters are used.
 
@@ -1365,7 +1365,7 @@ m4_skip_line (m4 *context, const m4_call_info *caller)
    not properly restore the current input file and line when we
    restore unconsumed characters.  */
 static bool
-match_input (m4 *context, const char *s, bool consume)
+match_input (m4 *context, const char *s, size_t len, bool consume)
 {
   int n;                       /* number of characters matched */
   int ch;                      /* input character */
@@ -1373,11 +1373,12 @@ match_input (m4 *context, const char *s, bool consume)
   m4_obstack *st;
   bool result = false;
 
+  assert (len);
   ch = peek_char (context, false);
   if (ch != to_uchar (*s))
     return false;                      /* fail */
 
-  if (s[1] == '\0')
+  if (len == 1)
     {
       if (consume)
        next_char (context, false, false, false);
@@ -1389,7 +1390,7 @@ match_input (m4 *context, const char *s, bool consume)
     {
       next_char (context, false, false, false);
       n++;
-      if (*s == '\0')          /* long match */
+      if (--len == 1)          /* long match */
        {
          if (consume)
            return true;
@@ -1406,17 +1407,17 @@ match_input (m4 *context, const char *s, bool consume)
   return result;
 }
 
-/* The macro MATCH() is used to match an unsigned char string S
-  against the input.  The first character is handled inline, for
-  speed.  Hopefully, this will not hurt efficiency too much when
-  single character quotes and comment delimiters are used.  If
-  CONSUME, then CH is the result of next_char, and a successful match
-  will discard the matched string.  Otherwise, CH is the result of
-  peek_char, and the input stream is effectively unchanged.  */
-#define MATCH(C, ch, s, consume)                                       \
-  (to_uchar ((s)[0]) == (ch)                                           \
-   && (ch) != '\0'                                                     \
-   && ((s)[1] == '\0' || (match_input (C, (s) + (consume), consume))))
+/* The macro MATCH() is used to match an unsigned char string S of
+  length LEN against the input.  The first character is handled
+  inline, for speed.  Hopefully, this will not hurt efficiency too
+  much when single character quotes and comment delimiters are used.
+  If CONSUME, then CH is the result of next_char, and a successful
+  match will discard the matched string.  Otherwise, CH is the result
+  of peek_char, and the input stream is effectively unchanged.  */
+#define MATCH(C, ch, s, len, consume)                                  \
+  ((len) && to_uchar ((s)[0]) == (ch)                                  \
+   && ((len) == 1                                                      \
+       || match_input (C, (s) + (consume), (len) - (consume), consume)))
 
 /* While the current input character has the given SYNTAX, append it
    to OBS.  Take care not to pop input source unless the next source
@@ -1628,7 +1629,8 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
          }
       }
     else if (!m4_is_syntax_single_quotes (M4SYNTAX)
-            && MATCH (context, ch, context->syntax->quote.str1, true))
+            && MATCH (context, ch, context->syntax->quote.str1,
+                      context->syntax->quote.len1, true))
       {                                        /* QUOTED STRING, LONGER QUOTES 
*/
        if (obs)
          obs_safe = obs;
@@ -1651,14 +1653,16 @@ m4__next_token (m4 *context, m4_symbol_value *token, 
int *line,
              }
            if (ch == CHAR_BUILTIN)
              init_builtin_token (context, obs, obs ? token : NULL);
-           else if (MATCH (context, ch, context->syntax->quote.str2, true))
+           else if (MATCH (context, ch, context->syntax->quote.str2,
+                           context->syntax->quote.len2, true))
              {
                if (--quote_level == 0)
                  break;
                obstack_grow (obs_safe, context->syntax->quote.str2,
                              context->syntax->quote.len2);
              }
-           else if (MATCH (context, ch, context->syntax->quote.str1, true))
+           else if (MATCH (context, ch, context->syntax->quote.str1,
+                           context->syntax->quote.len1, true))
              {
                quote_level++;
                obstack_grow (obs_safe, context->syntax->quote.str1,
@@ -1704,7 +1708,8 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
                ? M4_TOKEN_NONE : M4_TOKEN_STRING);
       }
     else if (!m4_is_syntax_single_comments (M4SYNTAX)
-            && MATCH (context, ch, context->syntax->comm.str1, true))
+            && MATCH (context, ch, context->syntax->comm.str1,
+                      context->syntax->comm.len1, true))
       {                                        /* COMMENT, LONGER DELIM */
        if (obs && !m4_get_discard_comments_opt (context))
          obs_safe = obs;
@@ -1729,7 +1734,8 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
                init_builtin_token (context, NULL, NULL);
                continue;
              }
-           if (MATCH (context, ch, context->syntax->comm.str2, true))
+           if (MATCH (context, ch, context->syntax->comm.str2,
+                      context->syntax->comm.len2, true))
              {
                obstack_grow (obs_safe, context->syntax->comm.str2,
                              context->syntax->comm.len2);
@@ -1864,9 +1870,11 @@ m4__next_token_is_open (m4 *context)
                                       | M4_SYNTAX_ALPHA | M4_SYNTAX_LQUOTE
                                       | M4_SYNTAX_ACTIVE))
       || (!m4_is_syntax_single_comments (M4SYNTAX)
-         && MATCH (context, ch, context->syntax->comm.str1, false))
+         && MATCH (context, ch, context->syntax->comm.str1,
+                   context->syntax->comm.len1, false))
       || (!m4_is_syntax_single_quotes (M4SYNTAX)
-         && MATCH (context, ch, context->syntax->quote.str1, false)))
+         && MATCH (context, ch, context->syntax->quote.str1,
+                   context->syntax->quote.len1, false)))
     return false;
   return m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_OPEN);
 }
diff --git a/m4/m4module.h b/m4/m4module.h
index 29495f3..70a062e 100644
--- a/m4/m4module.h
+++ b/m4/m4module.h
@@ -244,12 +244,12 @@ m4_context_opt_bit_table
 typedef void m4_module_init_func   (m4 *, m4_module *, m4_obstack *);
 typedef void m4_module_finish_func (m4 *, m4_module *, m4_obstack *);
 
-extern m4_module *  m4_module_load     (m4 *, const char*, m4_obstack*);
+extern m4_module *  m4_module_load     (m4 *, const char *, m4_obstack *);
 extern const char * m4_module_makeresident (m4_module *);
 extern int         m4_module_refcount (const m4_module *);
-extern void        m4_module_unload   (m4 *, const char*, m4_obstack*);
-extern void *      m4_module_import   (m4 *, const char*, const char*,
-                                       m4_obstack*);
+extern void        m4_module_unload   (m4 *, const char *, m4_obstack *);
+extern void *      m4_module_import   (m4 *, const char *, const char *,
+                                       m4_obstack *);
 
 extern const char * m4_get_module_name (const m4_module *);
 extern void        m4__module_exit    (m4 *);
@@ -263,20 +263,20 @@ typedef void *m4_symtab_apply_func (m4_symbol_table *, 
const char *, size_t,
                                    m4_symbol *, void *);
 
 extern m4_symbol_table *m4_symtab_create  (size_t);
-extern void      m4_symtab_delete  (m4_symbol_table*);
-extern void *    m4_symtab_apply   (m4_symbol_table*, bool,
-                                    m4_symtab_apply_func*, void*);
+extern void      m4_symtab_delete  (m4_symbol_table *);
+extern void *    m4_symtab_apply   (m4_symbol_table *, bool,
+                                    m4_symtab_apply_func *, void *);
 
-extern m4_symbol *m4_symbol_lookup  (m4_symbol_table*, const char *, size_t);
-extern m4_symbol *m4_symbol_pushdef (m4_symbol_table*, const char *, size_t,
+extern m4_symbol *m4_symbol_lookup  (m4_symbol_table *, const char *, size_t);
+extern m4_symbol *m4_symbol_pushdef (m4_symbol_table *, const char *, size_t,
                                     m4_symbol_value *);
-extern m4_symbol *m4_symbol_define  (m4_symbol_table*, const char *, size_t,
+extern m4_symbol *m4_symbol_define  (m4_symbol_table *, const char *, size_t,
                                     m4_symbol_value *);
-extern void       m4_symbol_popdef  (m4_symbol_table*, const char *, size_t);
-extern m4_symbol *m4_symbol_rename  (m4_symbol_table*, const char *, size_t,
+extern void       m4_symbol_popdef  (m4_symbol_table *, const char *, size_t);
+extern m4_symbol *m4_symbol_rename  (m4_symbol_table *, const char *, size_t,
                                     const char *, size_t);
 
-extern void       m4_symbol_delete  (m4_symbol_table*, const char *, size_t);
+extern void       m4_symbol_delete  (m4_symbol_table *, const char *, size_t);
 
 #define m4_symbol_delete(symtab, name, len)            M4_STMT_START   \
   {                                                                    \
@@ -284,9 +284,9 @@ extern void       m4_symbol_delete  (m4_symbol_table*, 
const char *, size_t);
       m4_symbol_popdef (symtab, name, len);                            \
   } M4_STMT_END
 
-extern m4_symbol_value *m4_get_symbol_value      (m4_symbol*);
-extern bool            m4_get_symbol_traced      (m4_symbol*);
-extern bool            m4_set_symbol_name_traced (m4_symbol_table*,
+extern m4_symbol_value *m4_get_symbol_value      (m4_symbol *);
+extern bool            m4_get_symbol_traced      (m4_symbol *);
+extern bool            m4_set_symbol_name_traced (m4_symbol_table *,
                                                   const char *, size_t, bool);
 extern void    m4_symbol_print         (m4 *, m4_symbol *, m4_obstack *,
                                         const m4_string_pair *, bool, size_t,
@@ -487,9 +487,13 @@ enum {
 #define m4_has_syntax(S, C, T)                                         \
   ((m4_syntab ((S), sizeof (C) == 1 ? to_uchar (C) : (C)) & (T)) > 0)
 
-extern void    m4_set_quotes   (m4_syntax_table*, const char*, const char*);
-extern void    m4_set_comment  (m4_syntax_table*, const char*, const char*);
-extern int     m4_set_syntax   (m4_syntax_table*, char, char, const char*);
+extern void    m4_set_quotes   (m4_syntax_table *, const char *, size_t,
+                                const char *, size_t);
+extern void    m4_set_comment  (m4_syntax_table *, const char *, size_t,
+                                const char *, size_t);
+extern int     m4_set_syntax   (m4_syntax_table *, char, char, const char *,
+                                size_t);
+extern void    m4_reset_syntax (m4_syntax_table *);
 
 
 
diff --git a/m4/m4private.h b/m4/m4private.h
index 9734a16..1a3c0c0 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -438,7 +438,7 @@ struct m4_symbol_arg {
 #define SYMBOL_ARG_REST_BIT    (1 << 0)
 #define SYMBOL_ARG_KEY_BIT     (1 << 1)
 
-extern void m4__symtab_remove_module_references (m4_symbol_table*,
+extern void m4__symtab_remove_module_references (m4_symbol_table *,
                                                 m4_module *);
 extern bool m4__symbol_value_print (m4 *, m4_symbol_value *, m4_obstack *,
                                    const m4_string_pair *, bool,
diff --git a/m4/macro.c b/m4/macro.c
index b1f9f44..c638023 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -23,8 +23,6 @@
 
 #include <config.h>
 
-#include <stdarg.h>
-
 #include "m4private.h"
 
 #include "intprops.h"
@@ -134,9 +132,6 @@ static void    process_macro         (m4 *, m4_symbol_value 
*, m4_obstack *, int,
 
 static unsigned int trace_pre   (m4 *, m4_macro_args *);
 static void    trace_post       (m4 *, unsigned int, const m4_call_info *);
-
-static void    trace_format     (m4 *, const char *, ...)
-  M4_GNUC_PRINTF (2, 3);
 static unsigned int trace_header (m4 *, const m4_call_info *);
 static void    trace_flush      (m4 *, unsigned int);
 
@@ -796,80 +791,22 @@ process_macro (m4 *context, m4_symbol_value *value, 
m4_obstack *obs,
    This prevents tracing output from interfering with other debug
    messages generated by the various builtins.  */
 
-/* Tracing output is formatted here, by a simplified printf-to-obstack
-   function trace_format ().  Understands only %s, %d, %zu (size_t
-   value).  */
-static void
-trace_format (m4 *context, const char *fmt, ...)
-{
-  va_list args;
-  char ch;
-  const char *s;
-  char nbuf[INT_BUFSIZE_BOUND (sizeof (int) > sizeof (size_t)
-                              ? sizeof (int) : sizeof (size_t))];
-
-  va_start (args, fmt);
-
-  while (true)
-    {
-      while ((ch = *fmt++) != '\0' && ch != '%')
-       obstack_1grow (&context->trace_messages, ch);
-
-      if (ch == '\0')
-       break;
-
-      switch (*fmt++)
-       {
-       case 's':
-         s = va_arg (args, const char *);
-         break;
-
-       case 'd':
-         {
-           int d = va_arg (args, int);
-
-           sprintf (nbuf, "%d", d);
-           s = nbuf;
-         }
-         break;
-
-       case 'z':
-         ch = *fmt++;
-         assert (ch == 'u');
-         {
-           size_t z = va_arg (args, size_t);
-
-           sprintf (nbuf, "%zu", z);
-           s = nbuf;
-         }
-         break;
-
-       default:
-         abort ();
-         break;
-       }
-
-      obstack_grow (&context->trace_messages, s, strlen (s));
-    }
-
-  va_end (args);
-}
-
 /* Format the standard header attached to all tracing output lines,
    using the context in INFO as appropriate.  Return the offset into
    the trace obstack where this particular trace begins.  */
 static unsigned int
 trace_header (m4 *context, const m4_call_info *info)
 {
-  unsigned int result = obstack_object_size (&context->trace_messages);
-  trace_format (context, "m4trace:");
+  m4_obstack *trace = &context->trace_messages;
+  unsigned int result = obstack_object_size (trace);
+  obstack_grow (trace, "m4trace:", 8);
   if (info->debug_level & M4_DEBUG_TRACE_FILE)
-    trace_format (context, "%s:", info->file);
+    obstack_printf (trace, "%s:", info->file);
   if (info->debug_level & M4_DEBUG_TRACE_LINE)
-    trace_format (context, "%d:", info->line);
-  trace_format (context, " -%zu- ", context->expansion_level);
+    obstack_printf (trace, "%d:", info->line);
+  obstack_printf (trace, " -%zu- ", context->expansion_level);
   if (info->debug_level & M4_DEBUG_TRACE_CALLID)
-    trace_format (context, "id %zu: ", info->call_id);
+    obstack_printf (trace, "id %zu: ", info->call_id);
   return result;
 }
 
@@ -924,10 +861,10 @@ trace_pre (m4 *context, m4_macro_args *argv)
 {
   int trace_level = argv->info->debug_level;
   unsigned int start = trace_header (context, argv->info);
+  m4_obstack *trace = &context->trace_messages;
 
   assert (argv->info->trace);
-  obstack_grow (&context->trace_messages, argv->info->name,
-               argv->info->name_len);
+  obstack_grow (trace, argv->info->name, argv->info->name_len);
 
   if (1 < m4_arg_argc (argv) && (trace_level & M4_DEBUG_TRACE_ARGS))
     {
@@ -937,10 +874,10 @@ trace_pre (m4 *context, m4_macro_args *argv)
 
       if (trace_level & M4_DEBUG_TRACE_QUOTE)
        quotes = m4_get_syntax_quotes (M4SYNTAX);
-      trace_format (context, "(");
-      m4__arg_print (context, &context->trace_messages, argv, 1, quotes, false,
-                    NULL, ", ", &arg_length, true, module);
-      trace_format (context, ")");
+      obstack_1grow (trace, '(');
+      m4__arg_print (context, trace, argv, 1, quotes, false, NULL, ", ",
+                    &arg_length, true, module);
+      obstack_1grow (trace, ')');
     }
   return start;
 }
@@ -954,7 +891,7 @@ trace_post (m4 *context, unsigned int start, const 
m4_call_info *info)
   assert (info->trace);
   if (info->debug_level & M4_DEBUG_TRACE_EXPANSION)
     {
-      trace_format (context, " -> ");
+      obstack_grow (&context->trace_messages, " -> ", 4);
       m4_input_print (context, &context->trace_messages, info->debug_level);
     }
   trace_flush (context, start);
diff --git a/m4/output.c b/m4/output.c
index f94cbd2..f86f913 100644
--- a/m4/output.c
+++ b/m4/output.c
@@ -194,12 +194,7 @@ m4_tmpname (int divnum)
   static size_t offset;
   if (buffer == NULL)
     {
-      obstack_grow (&diversion_storage, output_temp_dir->dir_name,
-                   strlen (output_temp_dir->dir_name));
-      obstack_1grow (&diversion_storage, '/');
-      obstack_1grow (&diversion_storage, 'm');
-      obstack_1grow (&diversion_storage, '4');
-      obstack_1grow (&diversion_storage, '-');
+      obstack_printf (&diversion_storage, "%s/m4-", output_temp_dir->dir_name);
       offset = obstack_object_size (&diversion_storage);
       buffer = (char *) obstack_alloc (&diversion_storage,
                                       INT_BUFSIZE_BOUND (divnum));
@@ -474,8 +469,6 @@ m4_divert_text (m4 *context, m4_obstack *obs, const char 
*text, size_t length,
                int line)
 {
   static bool start_of_output_line = true;
-  char linebuf[6 + INT_BUFSIZE_BOUND (unsigned long int)]; /* "#line nnnn" */
-  const char *cursor;
 
   /* If output goes to an obstack, merely add TEXT to it.  */
 
@@ -537,20 +530,17 @@ m4_divert_text (m4 *context, m4_obstack *obs, const char 
*text, size_t length,
 
          if (m4_get_output_line (context) != line)
            {
+             char linebuf[sizeof "#line " + INT_BUFSIZE_BOUND (line)];
              sprintf (linebuf, "#line %lu",
                       (unsigned long int) m4_get_current_line (context));
-             for (cursor = linebuf; *cursor; cursor++)
-               OUTPUT_CHARACTER (*cursor);
+             m4_output_text (context, linebuf, strlen (linebuf));
              if (m4_get_output_line (context) < 1
                  && m4_get_current_file (context)[0] != '\0')
                {
+                 const char *file = m4_get_current_file (context);
                  OUTPUT_CHARACTER (' ');
                  OUTPUT_CHARACTER ('"');
-                 for (cursor = m4_get_current_file (context);
-                      *cursor; cursor++)
-                   {
-                     OUTPUT_CHARACTER (*cursor);
-                   }
+                 m4_output_text (context, file, strlen (file));
                  OUTPUT_CHARACTER ('"');
                }
              OUTPUT_CHARACTER ('\n');
@@ -585,9 +575,7 @@ m4_divert_text (m4 *context, m4_obstack *obs, const char 
*text, size_t length,
 void
 m4_shipout_int (m4_obstack *obs, int val)
 {
-  char buf[INT_BUFSIZE_BOUND (int)];
-  int len = sprintf(buf, "%d", val);
-  obstack_grow (obs, buf, len);
+  obstack_printf (obs, "%d", val);
 }
 
 /* Output the text S, of length LEN, to OBS.  If QUOTED, also output
diff --git a/m4/syntax.c b/m4/syntax.c
index 5892f2a..3bba0a8 100644
--- a/m4/syntax.c
+++ b/m4/syntax.c
@@ -159,7 +159,7 @@ m4_syntax_create (void)
       }
 
   /* Set up current table to match default.  */
-  m4_set_syntax (syntax, '\0', '\0', NULL);
+  m4_reset_syntax (syntax);
   syntax->cached_simple.str1 = syntax->cached_lquote;
   syntax->cached_simple.len1 = 1;
   syntax->cached_simple.str2 = syntax->cached_rquote;
@@ -248,12 +248,15 @@ remove_syntax_attribute (m4_syntax_table *syntax, int ch, 
int code)
   return syntax->table[ch];
 }
 
+/* Add the set CHARS of length LEN to syntax category CODE, removing
+   them from whatever category they used to be in.  */
 static void
-add_syntax_set (m4_syntax_table *syntax, const char *chars, int code)
+add_syntax_set (m4_syntax_table *syntax, const char *chars, size_t len,
+               int code)
 {
   int ch;
 
-  if (*chars == '\0')
+  if (!len)
     return;
 
   if (code == M4_SYNTAX_ESCAPE)
@@ -261,20 +264,27 @@ add_syntax_set (m4_syntax_table *syntax, const char 
*chars, int code)
 
   /* Adding doesn't affect single-quote or single-comment.  */
 
-  while ((ch = to_uchar (*chars++)))
-    add_syntax_attribute (syntax, ch, code);
+  while (len--)
+    {
+      ch = to_uchar (*chars++);
+      add_syntax_attribute (syntax, ch, code);
+    }
 }
 
+/* Remove the set CHARS of length LEN from syntax category CODE,
+   adding them to category M4_SYNTAX_OTHER instead.  */
 static void
-subtract_syntax_set (m4_syntax_table *syntax, const char *chars, int code)
+subtract_syntax_set (m4_syntax_table *syntax, const char *chars, size_t len,
+                    int code)
 {
   int ch;
 
-  if (*chars == '\0')
+  if (!len)
     return;
 
-  while ((ch = to_uchar (*chars++)))
+  while (len--)
     {
+      ch = to_uchar (*chars++);
       if ((code & M4_SYNTAX_MASKS) != 0)
        remove_syntax_attribute (syntax, ch, code);
       else if (m4_has_syntax (syntax, ch, code))
@@ -306,8 +316,13 @@ subtract_syntax_set (m4_syntax_table *syntax, const char 
*chars, int code)
     }
 }
 
+/* Make the set CHARS of length LEN become syntax category CODE,
+   removing CHARS from any other categories, and sending all bytes in
+   the category but not in CHARS to category M4_SYNTAX_OTHER
+   instead.  */
 static void
-set_syntax_set (m4_syntax_table *syntax, const char *chars, int code)
+set_syntax_set (m4_syntax_table *syntax, const char *chars, size_t len,
+               int code)
 {
   int ch;
   /* Explicit set of characters to install with this category; all
@@ -320,8 +335,11 @@ set_syntax_set (m4_syntax_table *syntax, const char 
*chars, int code)
       else if (m4_has_syntax (syntax, ch, code))
        add_syntax_attribute (syntax, ch, M4_SYNTAX_OTHER);
     }
-  while ((ch = to_uchar (*chars++)))
-    add_syntax_attribute (syntax, ch, code);
+  while (len--)
+    {
+      ch = to_uchar (*chars++);
+      add_syntax_attribute (syntax, ch, code);
+    }
 
   /* Check for any cleanup needed.  */
   check_is_macro_escaped (syntax);
@@ -329,6 +347,8 @@ set_syntax_set (m4_syntax_table *syntax, const char *chars, 
int code)
   check_is_single_comments (syntax);
 }
 
+/* Reset syntax category CODE to its default state, sending all other
+   characters in the category back to their default state.  */
 static void
 reset_syntax_set (m4_syntax_table *syntax, int code)
 {
@@ -360,47 +380,51 @@ reset_syntax_set (m4_syntax_table *syntax, int code)
   check_is_single_comments (syntax);
 }
 
-int
-m4_set_syntax (m4_syntax_table *syntax, char key, char action,
-              const char *chars)
+/* Reset the syntax table to its default state.  */
+void
+m4_reset_syntax (m4_syntax_table *syntax)
 {
-  int code;
+  /* Restore the default syntax, which has known quote and comment
+     properties.  */
+  memcpy (syntax->table, syntax->orig, sizeof syntax->orig);
 
-  assert (syntax);
-  assert (chars || key == '\0');
-
-  if (key == '\0')
-    {
-      /* Restore the default syntax, which has known quote and comment
-        properties.  */
-      memcpy (syntax->table, syntax->orig, sizeof syntax->orig);
-
-      free (syntax->quote.str1);
-      free (syntax->quote.str2);
-      free (syntax->comm.str1);
-      free (syntax->comm.str2);
-
-      syntax->quote.str1       = xstrdup (DEF_LQUOTE);
-      syntax->quote.len1       = 1;
-      syntax->quote.str2       = xstrdup (DEF_RQUOTE);
-      syntax->quote.len2       = 1;
-      syntax->comm.str1                = xstrdup (DEF_BCOMM);
-      syntax->comm.len1                = 1;
-      syntax->comm.str2                = xstrdup (DEF_ECOMM);
-      syntax->comm.len2                = 1;
+  free (syntax->quote.str1);
+  free (syntax->quote.str2);
+  free (syntax->comm.str1);
+  free (syntax->comm.str2);
 
-      add_syntax_attribute (syntax, to_uchar (syntax->quote.str2[0]),
-                           M4_SYNTAX_RQUOTE);
-      add_syntax_attribute (syntax, to_uchar (syntax->comm.str2[0]),
-                           M4_SYNTAX_ECOMM);
+  syntax->quote.str1 = xmemdup (DEF_LQUOTE, 1);
+  syntax->quote.len1 = 1;
+  syntax->quote.str2 = xmemdup (DEF_RQUOTE, 1);
+  syntax->quote.len2 = 1;
+  syntax->comm.str1 = xmemdup (DEF_BCOMM, 1);
+  syntax->comm.len1 = 1;
+  syntax->comm.str2 = xmemdup (DEF_ECOMM, 1);
+  syntax->comm.len2 = 1;
+
+  add_syntax_attribute (syntax, to_uchar (syntax->quote.str2[0]),
+                       M4_SYNTAX_RQUOTE);
+  add_syntax_attribute (syntax, to_uchar (syntax->comm.str2[0]),
+                       M4_SYNTAX_ECOMM);
+
+  syntax->is_single_quotes = true;
+  syntax->is_single_comments = true;
+  syntax->is_macro_escaped = false;
+  set_quote_age (syntax, true, false);
+}
 
-      syntax->is_single_quotes         = true;
-      syntax->is_single_comments       = true;
-      syntax->is_macro_escaped         = false;
-      set_quote_age (syntax, true, false);
-      return 0;
-    }
+/* Alter the syntax for category KEY, according to ACTION: '+' to add,
+   '-' to subtract, '=' to set, or '\0' to reset.  The array CHARS of
+   length LEN describes the characters to modify; it is ignored if
+   ACTION is '\0'.  Return -1 if KEY is invalid, otherwise return the
+   syntax category matching KEY.  */
+int
+m4_set_syntax (m4_syntax_table *syntax, char key, char action,
+              const char *chars, size_t len)
+{
+  int code;
 
+  assert (syntax && chars);
   code = m4_syntax_code (key);
   if (code < 0)
     {
@@ -409,15 +433,16 @@ m4_set_syntax (m4_syntax_table *syntax, char key, char 
action,
   switch (action)
     {
     case '+':
-      add_syntax_set (syntax, chars, code);
+      add_syntax_set (syntax, chars, len, code);
       break;
     case '-':
-      subtract_syntax_set (syntax, chars, code);
+      subtract_syntax_set (syntax, chars, len, code);
       break;
     case '=':
-      set_syntax_set (syntax, chars, code);
+      set_syntax_set (syntax, chars, len, code);
       break;
     case '\0':
+      assert (!len);
       reset_syntax_set (syntax, code);
       break;
     default:
@@ -555,8 +580,13 @@ check_is_macro_escaped (m4_syntax_table *syntax)
 /* Functions for setting quotes and comment delimiters.  Used by
    m4_changecom () and m4_changequote ().  Both functions override the
    syntax table to maintain compatibility.  */
+
+/* Set the quote delimiters to LQ and RQ, with respective lengths
+   LQ_LEN and RQ_LEN.  Pass NULL if the argument was not present, to
+   distinguish from an explicit empty string.  */
 void
-m4_set_quotes (m4_syntax_table *syntax, const char *lq, const char *rq)
+m4_set_quotes (m4_syntax_table *syntax, const char *lq, size_t lq_len,
+              const char *rq, size_t rq_len)
 {
   int ch;
 
@@ -572,21 +602,27 @@ m4_set_quotes (m4_syntax_table *syntax, const char *lq, 
const char *rq)
   if (!lq)
     {
       lq = DEF_LQUOTE;
+      lq_len = 1;
+      rq = DEF_RQUOTE;
+      rq_len = 1;
+    }
+  else if (!rq || (lq_len && !rq_len))
+    {
       rq = DEF_RQUOTE;
+      rq_len = 1;
     }
-  else if (!rq || (*lq && !*rq))
-    rq = DEF_RQUOTE;
 
-  if (strcmp (syntax->quote.str1, lq) == 0
-      && strcmp (syntax->quote.str2, rq) == 0)
+  if (syntax->quote.len1 == lq_len && syntax->quote.len2 == rq_len
+      && memcmp (syntax->quote.str1, lq, lq_len) == 0
+      && memcmp (syntax->quote.str2, rq, rq_len) == 0)
     return;
 
   free (syntax->quote.str1);
   free (syntax->quote.str2);
-  syntax->quote.str1 = xstrdup (lq);
-  syntax->quote.len1 = strlen (lq);
-  syntax->quote.str2 = xstrdup (rq);
-  syntax->quote.len2 = strlen (rq);
+  syntax->quote.str1 = xmemdup (lq, lq_len);
+  syntax->quote.len1 = lq_len;
+  syntax->quote.str2 = xmemdup (rq, rq_len);
+  syntax->quote.len2 = rq_len;
 
   /* changequote overrides syntax_table, but be careful when it is
      used to select a start-quote sequence that is effectively
@@ -620,8 +656,12 @@ m4_set_quotes (m4_syntax_table *syntax, const char *lq, 
const char *rq)
   set_quote_age (syntax, false, false);
 }
 
+/* Set the comment delimiters to BC and EC, with respective lengths
+   BC_LEN and EC_LEN.  Pass NULL if the argument was not present, to
+   distinguish from an explicit empty string.  */
 void
-m4_set_comment (m4_syntax_table *syntax, const char *bc, const char *ec)
+m4_set_comment (m4_syntax_table *syntax, const char *bc, size_t bc_len,
+               const char *ec, size_t ec_len)
 {
   int ch;
 
@@ -635,20 +675,27 @@ m4_set_comment (m4_syntax_table *syntax, const char *bc, 
const char *ec)
      comment.  See the texinfo for what some other implementations
      do.  */
   if (!bc)
-    bc = ec = "";
-  else if (!ec || (*bc && !*ec))
-    ec = DEF_ECOMM;
+    {
+      bc = ec = "";
+      bc_len = ec_len = 0;
+    }
+  else if (!ec || (bc_len && !ec_len))
+    {
+      ec = DEF_ECOMM;
+      ec_len = 1;
+    }
 
-  if (strcmp (syntax->comm.str1, bc) == 0
-      && strcmp (syntax->comm.str2, ec) == 0)
+  if (syntax->comm.len1 == bc_len && syntax->comm.len2 == ec_len
+      && memcmp (syntax->comm.str1, bc, bc_len) == 0
+      && memcmp (syntax->comm.str2, ec, ec_len) == 0)
     return;
 
   free (syntax->comm.str1);
   free (syntax->comm.str2);
-  syntax->comm.str1 = xstrdup (bc);
-  syntax->comm.len1 = strlen (bc);
-  syntax->comm.str2 = xstrdup (ec);
-  syntax->comm.len2 = strlen (ec);
+  syntax->comm.str1 = xmemdup (bc, bc_len);
+  syntax->comm.len1 = bc_len;
+  syntax->comm.str2 = xmemdup (ec, ec_len);
+  syntax->comm.len2 = ec_len;
 
   /* changecom overrides syntax_table, but be careful when it is used
      to select a start-comment sequence that is effectively
diff --git a/modules/format.c b/modules/format.c
index f5695e4..e2a1a42 100644
--- a/modules/format.c
+++ b/modules/format.c
@@ -152,10 +152,8 @@ format (m4 *context, m4_obstack *obs, int argc, 
m4_macro_args *argv)
      behavior in printf.  */
   char ok[128];
 
-  /* Buffer and stuff.  */
-  char *base;                  /* Current position in obs.  */
-  size_t len;                  /* Length of formatted text.  */
-  char *str;                   /* Malloc'd buffer of formatted text.  */
+  /* Check that formatted text succeeded with correct type.  */
+  int result = 0;
   enum {CHAR, INT, LONG, DOUBLE, STR} datatype;
 
   f = fmt = ARG_STR (i, argc, argv);
@@ -349,56 +347,39 @@ format (m4 *context, m4_obstack *obs, int argc, 
m4_macro_args *argv)
        }
       *p++ = c;
       *p = '\0';
-      base = obstack_next_free (obs);
-      len = obstack_room (obs);
 
       switch (datatype)
        {
        case CHAR:
-         str = asnprintf (base, &len, fstart, width,
-                          ARG_INT (i, argc, argv));
+         result = obstack_printf (obs, fstart, width,
+                                  ARG_INT (i, argc, argv));
          break;
 
        case INT:
-         str = asnprintf (base, &len, fstart, width, prec,
-                          ARG_INT (i, argc, argv));
+         result = obstack_printf (obs, fstart, width, prec,
+                                  ARG_INT (i, argc, argv));
          break;
 
        case LONG:
-         str = asnprintf (base, &len, fstart, width, prec,
-                          ARG_LONG (i, argc, argv));
+         result = obstack_printf (obs, fstart, width, prec,
+                                  ARG_LONG (i, argc, argv));
          break;
 
        case DOUBLE:
-         str = asnprintf (base, &len, fstart, width, prec,
-                          ARG_DOUBLE (i, argc, argv));
+         result = obstack_printf (obs, fstart, width, prec,
+                                  ARG_DOUBLE (i, argc, argv));
          break;
 
        case STR:
-         str = asnprintf (base, &len, fstart, width, prec,
-                          ARG_STR (i, argc, argv));
+         result = obstack_printf (obs, fstart, width, prec,
+                                  ARG_STR (i, argc, argv));
          break;
 
        default:
          abort ();
        }
-
-      if (str == NULL)
-       /* NULL is unexpected (EILSEQ and EINVAL are not possible
-          based on our construction of fstart, leaving only ENOMEM,
-          which should always be fatal).  */
-       m4_error (context, EXIT_FAILURE, errno, me,
-                 _("unable to format output for `%s'"), f);
-      else if (str == base)
-       /* The output was already computed in place, but we need to
-          account for its size.  */
-       obstack_blank_fast (obs, len);
-      else
-       {
-         /* The output exceeded available obstack space, copy the
-            allocated string.  */
-         obstack_grow (obs, str, len);
-         free (str);
-       }
+      /* Since obstack_printf can only fail with EILSEQ or EINVAL, but
+        we constructed fstart, the result should not be negative.  */
+      assert (0 <= result);
     }
 }
diff --git a/modules/gnu.c b/modules/gnu.c
index 99df3ef..75e5363 100644
--- a/modules/gnu.c
+++ b/modules/gnu.c
@@ -510,26 +510,41 @@ M4BUILTIN_HANDLER (changesyntax)
       size_t i;
       for (i = 1; i < argc; i++)
        {
-         const char *spec = M4ARG (i);
-         char key = *spec++;
-         char action = key ? *spec : '\0';
+         size_t len = M4ARGLEN (i);
+         const char *spec;
+         char key;
+         char action;
+
+         if (!len)
+           {
+             m4_reset_syntax (M4SYNTAX);
+             continue;
+           }
+         spec = M4ARG (i);
+         key = *spec++;
+         len--;
+         action = len ? *spec : '\0';
          switch (action)
            {
            case '-':
            case '+':
            case '=':
              spec++;
+             len--;
              break;
            case '\0':
-             break;
+             if (!len)
+               break;
+             /* fall through */
            default:
              action = '=';
              break;
            }
-         if (m4_set_syntax (M4SYNTAX, key, action,
-                            key ? m4_expand_ranges (spec, obs) : "") < 0)
-           m4_warn (context, 0, me, _("undefined syntax code: `%c'"),
-                    key);
+         if (len)
+           spec = m4_expand_ranges (spec, &len, m4_arg_scratch (context));
+         if (m4_set_syntax (M4SYNTAX, key, action, spec, len) < 0)
+           m4_warn (context, 0, me, _("undefined syntax code: %s"),
+                    quotearg_style_mem (locale_quoting_style, &key, 1));
        }
     }
   else
diff --git a/modules/m4.c b/modules/m4.c
index b993ec4..1857d6f 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -51,7 +51,7 @@ extern void m4_set_sysval    (int);
 extern void m4_sysval_flush  (m4 *, bool);
 extern void m4_dump_symbols  (m4 *, m4_dump_symbol_data *, size_t,
                              m4_macro_args *, bool);
-extern const char *m4_expand_ranges (const char *, m4_obstack *);
+extern const char *m4_expand_ranges (const char *, size_t *, m4_obstack *);
 extern void m4_make_temp     (m4 *, m4_obstack *, const m4_call_info *,
                              const char *, size_t, bool);
 
@@ -352,18 +352,19 @@ M4BUILTIN_HANDLER (dumpdef)
       m4_symbol *symbol = m4_symbol_lookup (M4SYMTAB, data.base->str,
                                            data.base->len);
       char *value;
+      size_t len;
       assert (symbol);
 
       /* TODO - add debugmode(b) option to control quoting style.  */
-      fwrite (data.base->str, 1, data.base->len, stderr);
-      fputc (':', stderr);
-      fputc ('\t', stderr);
+      obstack_grow (obs, data.base->str, data.base->len);
+      obstack_1grow (obs, ':');
+      obstack_1grow (obs, '\t');
       m4_symbol_print (context, symbol, obs, quotes, stack, arg_length,
                       module);
       obstack_1grow (obs, '\n');
-      obstack_1grow (obs, '\0');
+      len = obstack_object_size (obs);
       value = (char *) obstack_finish (obs);
-      fputs (value, stderr);
+      fwrite (value, 1, len, stderr);
       obstack_free (obs, value);
     }
 }
@@ -632,8 +633,8 @@ M4BUILTIN_HANDLER (shift)
 M4BUILTIN_HANDLER (changequote)
 {
   m4_set_quotes (M4SYNTAX,
-                (argc >= 2) ? M4ARG (1) : NULL,
-                (argc >= 3) ? M4ARG (2) : NULL);
+                (argc >= 2) ? M4ARG (1) : NULL, M4ARGLEN (1),
+                (argc >= 3) ? M4ARG (2) : NULL, M4ARGLEN (2));
 }
 
 /* Change the current comment delimiters.  The function set_comment ()
@@ -641,8 +642,8 @@ M4BUILTIN_HANDLER (changequote)
 M4BUILTIN_HANDLER (changecom)
 {
   m4_set_comment (M4SYNTAX,
-                 (argc >= 2) ? M4ARG (1) : NULL,
-                 (argc >= 3) ? M4ARG (2) : NULL);
+                 (argc >= 2) ? M4ARG (1) : NULL, M4ARGLEN (1),
+                 (argc >= 3) ? M4ARG (2) : NULL, M4ARGLEN (2));
 }
 
 
@@ -761,22 +762,19 @@ M4BUILTIN_HANDLER (maketemp)
       const char *str = M4ARG (1);
       size_t len = M4ARGLEN (1);
       size_t i;
-      size_t len2;
+      m4_obstack *scratch = m4_arg_scratch (context);
+      size_t pid_len = obstack_printf (scratch, "%lu",
+                                      (unsigned long) getpid ());
+      char *pid = (char *) obstack_copy0 (scratch, "", 0);
 
       for (i = len; i > 1; i--)
        if (str[i - 1] != 'X')
          break;
       obstack_grow (obs, str, i);
-      str = ntoa ((number) getpid (), 10);
-      len2 = strlen (str);
-      if (len2 > len - i)
-       obstack_grow (obs, str + len2 - (len - i), len - i);
+      if (len - i < pid_len)
+       obstack_grow (obs, pid + pid_len - (len - i), len - i);
       else
-       {
-         while (i++ < len - len2)
-           obstack_1grow (obs, '0');
-         obstack_grow (obs, str, len2);
-       }
+       obstack_printf (obs, "%.*d%s", len - i - pid_len, 0, pid);
     }
   else
     m4_make_temp (context, obs, me, M4ARG (1), M4ARGLEN (1), false);
@@ -953,31 +951,36 @@ M4BUILTIN_HANDLER (substr)
 }
 
 
-/* Ranges are expanded by the following function, and the expanded strings,
-   without any ranges left, are used to translate the characters of the
-   first argument.  A single - (dash) can be included in the strings by
-   being the first or the last character in the string.  If the first
-   character in a range is after the first in the character set, the range
-   is made backwards, thus 9-0 is the string 9876543210.  */
+/* Any ranges in string S of length *LEN are expanded, using OBS for
+   scratch space, and the expansion returned.  *LEN is set to the
+   expanded length.  A single - (dash) can be included in the strings
+   by being the first or the last character in the string.  If the
+   first character in a range is after the first in the character set,
+   the range is made backwards, thus 9-0 is the string 9876543210.  */
 const char *
-m4_expand_ranges (const char *s, m4_obstack *obs)
+m4_expand_ranges (const char *s, size_t *len, m4_obstack *obs)
 {
   unsigned char from;
   unsigned char to;
+  const char *end = s + *len;
 
   assert (obstack_object_size (obs) == 0);
-  for (from = '\0'; *s != '\0'; from = *s++)
+  assert (s != end);
+  from = *s++;
+  obstack_1grow (obs, from);
+
+  for ( ; s != end; from = *s++)
     {
-      if (*s == '-' && from != '\0')
+      if (*s == '-')
        {
-         to = *++s;
-         if (to == '\0')
+         if (++s == end)
            {
              /* trailing dash */
              obstack_1grow (obs, '-');
              break;
            }
-         else if (from <= to)
+         to = *s;
+         if (from <= to)
            {
              while (from++ < to)
                obstack_1grow (obs, from);
@@ -991,8 +994,9 @@ m4_expand_ranges (const char *s, m4_obstack *obs)
       else
        obstack_1grow (obs, *s);
     }
-  obstack_1grow (obs, '\0');
-  return obstack_finish (obs);
+  *len = obstack_object_size (obs);
+  /* FIXME - use obstack_finish once translit is updated.  */
+  return (char *) obstack_copy0 (obs, "", 0);
 }
 
 /* The macro "translit" translates all characters in the first
@@ -1005,6 +1009,8 @@ M4BUILTIN_HANDLER (translit)
   const char *data;
   const char *from;
   const char *to;
+  size_t from_len;
+  size_t to_len;
   char map[UCHAR_MAX + 1] = {0};
   char found[UCHAR_MAX + 1] = {0};
   unsigned char ch;
@@ -1016,16 +1022,18 @@ M4BUILTIN_HANDLER (translit)
     }
 
   from = M4ARG (2);
+  from_len = M4ARGLEN (2);
   if (strchr (from, '-') != NULL)
     {
-      from = m4_expand_ranges (from, m4_arg_scratch (context));
+      from = m4_expand_ranges (from, &from_len, m4_arg_scratch (context));
       assert (from);
     }
 
   to = M4ARG (3);
+  to_len = M4ARGLEN (3);
   if (strchr (to, '-') != NULL)
     {
-      to = m4_expand_ranges (to, m4_arg_scratch (context));
+      to = m4_expand_ranges (to, &to_len, m4_arg_scratch (context));
       assert (to);
     }
 
@@ -1169,19 +1177,25 @@ numb_obstack (m4_obstack *obs, number value, int radix, 
int min)
 {
   const char *s;
   size_t len;
+  unumber uvalue;
 
   if (radix == 1)
     {
-      /* FIXME - this code currently depends on undefined behavior.  */
       if (value < 0)
        {
          obstack_1grow (obs, '-');
-         value = -value;
+         uvalue = -value;
        }
-      while (min-- - value > 0)
-       obstack_1grow (obs, '0');
-      while (value-- != 0)
-       obstack_1grow (obs, '1');
+      else
+       uvalue = value;
+      if (uvalue < min)
+       {
+         obstack_blank (obs, min - uvalue);
+         memset ((char *) obstack_next_free (obs) - (min - uvalue), '0',
+                 min - uvalue);
+       }
+      obstack_blank (obs, uvalue);
+      memset ((char *) obstack_next_free (obs) - uvalue, '1', uvalue);
       return;
     }
 
@@ -1193,10 +1207,9 @@ numb_obstack (m4_obstack *obs, number value, int radix, 
int min)
       s++;
     }
   len = strlen (s);
-  for (min -= len; --min >= 0;)
-    obstack_1grow (obs, '0');
-
-  obstack_grow (obs, s, len);
+  if (min < len)
+    min = len;
+  obstack_printf (obs, "%.*d%s", min - len, 0, s);
 }
 
 
diff --git a/modules/m4.h b/modules/m4.h
index a82584e..63701ee 100644
--- a/modules/m4.h
+++ b/modules/m4.h
@@ -41,7 +41,8 @@ typedef void m4_set_sysval_func (int value);
 typedef void m4_dump_symbols_func (m4 *context, m4_dump_symbol_data *data,
                                   size_t argc, m4_macro_args *argv,
                                   bool complain);
-typedef const char *m4_expand_ranges_func (const char *s, m4_obstack *obs);
+typedef const char *m4_expand_ranges_func (const char *s, size_t *len,
+                                          m4_obstack *obs);
 typedef void m4_make_temp_func (m4 *context, m4_obstack *obs,
                                const m4_call_info *macro, const char *name,
                                size_t len, bool dir);
diff --git a/src/freeze.c b/src/freeze.c
index 0373459..7261b09 100644
--- a/src/freeze.c
+++ b/src/freeze.c
@@ -588,7 +588,7 @@ reload_frozen_state (m4 *context, const char *name)
        m4__module_open (context, "gnu", NULL);
       /* Disable { and } categories, since ${11} was not supported in
         1.4.x.  */
-      m4_set_syntax (M4SYNTAX, 'O', '+', "{}");
+      m4_set_syntax (M4SYNTAX, 'O', '+', "{}", 2);
       break;
     default:
       if (version > 2)
@@ -771,7 +771,7 @@ ill-formed frozen file, version 2 directive `%c' 
encountered"), 'S');
             other characters are additive.  */
          if ((m4_set_syntax (M4SYNTAX, syntax,
                              (m4_syntax_code (syntax) & M4_SYNTAX_MASKS
-                              ? '=' : '+'), string[0]) < 0)
+                              ? '=' : '+'), string[0], number[0]) < 0)
              && (syntax != '\0'))
            {
              m4_error (context, 0, 0, NULL,
@@ -843,7 +843,8 @@ ill-formed frozen file, version 2 directive `%c' 
encountered"), 't');
 
              /* Change comment strings.  */
 
-             m4_set_comment (M4SYNTAX, string[0], string[1]);
+             m4_set_comment (M4SYNTAX, string[0], number[0], string[1],
+                             number[1]);
              break;
 
            case 'D':
@@ -859,7 +860,8 @@ ill-formed frozen file, version 2 directive `%c' 
encountered"), 't');
 
              /* Change quote strings.  */
 
-             m4_set_quotes (M4SYNTAX, string[0], string[1]);
+             m4_set_quotes (M4SYNTAX, string[0], number[0], string[1],
+                            number[1]);
              break;
 
            default:
diff --git a/tests/freeze.at b/tests/freeze.at
index 6d76d32..a3b4b35 100644
--- a/tests/freeze.at
+++ b/tests/freeze.at
@@ -384,12 +384,13 @@ AT_CLEANUP
 AT_SETUP([reloading nul])
 AT_KEYWORDS([frozen])
 
-dnl AT_DATA can't generate NUL bytes (at least, not in all shells)
-AT_CHECK([printf 'define(-\0-,hi)dnl
+dnl AT_DATA can't generate NUL bytes (at least, not in all shells).
+# Skip the test if printf(1) is insufficient.
+AT_CHECK([printf 'define(-\0-,hi)changequote([,\0])changecom(--\0)dnl
 divert(1)undivert(null.out)' || exit 77],
  [0], [stdout], [ignore])
 mv stdout frozen.m4
-printf 'divert(0)indir(-\0-)\n' > unfrozen.m4
+printf 'divert(0)[divnum\0] @%:@-- indir(-\0-)\n' > unfrozen.m4
 
 # First generate the `expout' output by running over the sources before
 # freezing.
diff --git a/tests/null.err b/tests/null.err
index 8bf1f4f..9a3f322 100644
Binary files a/tests/null.err and b/tests/null.err differ
diff --git a/tests/null.m4 b/tests/null.m4
index 55bd3bd..18a5e1d 100644
Binary files a/tests/null.m4 and b/tests/null.m4 differ
diff --git a/tests/null.out b/tests/null.out
index 3a96faa..9e48a6a 100644
Binary files a/tests/null.out and b/tests/null.out differ


hooks/post-receive
--
GNU M4 source repository




reply via email to

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