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


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, branch-1.6, updated. v1.5.89a-71-g715c421
Date: Thu, 04 Dec 2008 04:31:21 +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=715c42128d8d357e3e751ec605069137d693c757

The branch, branch-1.6 has been updated
       via  715c42128d8d357e3e751ec605069137d693c757 (commit)
      from  9f5e389c810aacbd70b04f2530aa52a897cd0ad9 (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 715c42128d8d357e3e751ec605069137d693c757
Author: Eric Blake <address@hidden>
Date:   Thu Jan 17 14:34:36 2008 -0700

    Stage 27: Allow embedded NUL in text processing macros.
    
    * src/m4.h (evaluate): Add parameter.
    * src/builtin.c (compile_pattern) [DEBUG_REGEX]: Support NUL in
    output messages.
    (set_macro_sequence): Likewise.
    (m4_eval): Normalize messages, and adjust caller.
    (expand_ranges, substitute): Support NUL in macro expansion.
    (m4_translit, m4_regexp, m4_patsubst): Adjust callers, to manage
    NUL bytes.
    * src/format.c (expand_format): Manage NUL bytes.
    * src/eval.c (eval_error): Add EMPTY_ARGUMENT.
    (end_text): New variable.
    (eval_init_lex): Add parameter.
    (eval_lex, evaluate): Detect NUL in macro expansion.
    * doc/m4.texinfo (Format): Update to cover new behavior.
    (Eval): Mention that result is unquoted.
    * examples/null.m4: Enhance test.
    * examples/null.err: Update expected output.
    * examples/null.out: Likewise.
    
    Signed-off-by: Eric Blake <address@hidden>
    (cherry picked from commit 948d1ed0ca4089c2db579fe3d8b3ce172b3e616f)

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

Summary of changes:
 ChangeLog         |   26 ++++++
 doc/m4.texinfo    |   15 +++-
 examples/null.err |  Bin 713 -> 1078 bytes
 examples/null.m4  |  Bin 6499 -> 6667 bytes
 examples/null.out |  Bin 510 -> 553 bytes
 src/builtin.c     |  232 ++++++++++++++++++++++++++++++++++------------------
 src/eval.c        |   33 ++++++--
 src/format.c      |   43 ++++++----
 src/m4.h          |    2 +-
 9 files changed, 241 insertions(+), 110 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 2085dea..e991a8c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2008-12-03  Eric Blake  <address@hidden>
+
+       Stage 27: Allow embedded NUL in text processing macros.
+       Pass NUL through regular expressions, format, and translit, and
+       diagnose it in eval.  Improve warning capabilities of format.
+       Memory impact: none.
+       Speed impact: none noticed.
+       * src/m4.h (evaluate): Add parameter.
+       * src/builtin.c (compile_pattern) [DEBUG_REGEX]: Support NUL in
+       output messages.
+       (set_macro_sequence): Likewise.
+       (m4_eval): Normalize messages, and adjust caller.
+       (expand_ranges, substitute): Support NUL in macro expansion.
+       (m4_translit, m4_regexp, m4_patsubst): Adjust callers, to manage
+       NUL bytes.
+       * src/format.c (expand_format): Manage NUL bytes.
+       * src/eval.c (eval_error): Add EMPTY_ARGUMENT.
+       (end_text): New variable.
+       (eval_init_lex): Add parameter.
+       (eval_lex, evaluate): Detect NUL in macro expansion.
+       * doc/m4.texinfo (Format): Update to cover new behavior.
+       (Eval): Mention that result is unquoted.
+       * examples/null.m4: Enhance test.
+       * examples/null.err: Update expected output.
+       * examples/null.out: Likewise.
+
 2008-11-28  Eric Blake  <address@hidden>
 
        Add extension to divert builtin.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 8301bb7..2fb676d 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -6448,7 +6448,7 @@ Likewise, escape sequences are not yet recognized.
 @example
 format(`%p', `0')
 @error{}m4:stdin:1: Warning: format: unrecognized specifier in `%p'
address@hidden
address@hidden
 format(`%*d', `')
 @error{}m4:stdin:2: Warning: format: empty string treated as 0
 @error{}m4:stdin:2: Warning: format: too few arguments: 2 < 3
@@ -6734,7 +6734,9 @@ expansion.  The default radix is 10; this is also the 
case if
 @var{radix} is the empty string.  A warning results if the radix is
 outside the range of 1 through 36, inclusive.  The result of @code{eval}
 is always taken to be signed.  No radix prefix is output, and for
-radices greater than 10, the digits are lower case.  The @var{width}
+radices greater than 10, the digits are lower case (although some
+other implementations use upper case).  The output is unquoted, and
+subject to further macro expansion.  The @var{width}
 argument specifies the minimum output width, excluding any negative
 sign.  The result is zero-padded to extend the expansion to the
 requested width.  A warning results if the width is negative.  If
@@ -6759,14 +6761,19 @@ eval(`10', `', `0')
 eval(`10', `16')
 @result{}a
 eval(`1', `37')
address@hidden:stdin:9: Warning: eval: radix 37 out of range
address@hidden:stdin:9: Warning: eval: radix out of range: 37
 @result{}
 eval(`1', , `-1')
address@hidden:stdin:10: Warning: eval: negative width
address@hidden:stdin:10: Warning: eval: negative width: -1
 @result{}
 eval()
 @error{}m4:stdin:11: Warning: eval: empty string treated as 0
 @result{}0
+eval(` ')
address@hidden:stdin:12: Warning: eval: empty string treated as 0
address@hidden
+define(`a', `hi')eval(` 10 ', `16')
address@hidden
 @end example
 
 @node Shell commands
diff --git a/examples/null.err b/examples/null.err
index 897ce34..977b3b7 100644
Binary files a/examples/null.err and b/examples/null.err differ
diff --git a/examples/null.m4 b/examples/null.m4
index 1823073..e60aec5 100644
Binary files a/examples/null.m4 and b/examples/null.m4 differ
diff --git a/examples/null.out b/examples/null.out
index dd83416..c2c1cb9 100644
Binary files a/examples/null.out and b/examples/null.out differ
diff --git a/src/builtin.c b/src/builtin.c
index 24f2df6..613e1d2 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -311,7 +311,11 @@ compile_pattern (const char *str, size_t len, struct 
re_pattern_buffer **buf,
        regex_cache[i].count++;
 #ifdef DEBUG_REGEX
        if (trace_file)
-         xfprintf (trace_file, "cached:{%s}\n", str);
+         {
+           fputs ("cached:{", trace_file);
+           fwrite (str, 1, len, trace_file);
+           fputs ("}\n", trace_file);
+         }
 #endif /* DEBUG_REGEX */
        return NULL;
       }
@@ -321,7 +325,11 @@ compile_pattern (const char *str, size_t len, struct 
re_pattern_buffer **buf,
   msg = re_compile_pattern (str, len, new_buf);
 #ifdef DEBUG_REGEX
   if (trace_file)
-    xfprintf (trace_file, "compile:{%s}\n", str);
+    {
+      fputs ("compile:{", trace_file);
+      fwrite (str, 1, len, trace_file);
+      fputs ("}\n", trace_file);
+    }
 #endif /* DEBUG_REGEX */
   if (msg)
     {
@@ -356,7 +364,11 @@ compile_pattern (const char *str, size_t len, struct 
re_pattern_buffer **buf,
     {
 #ifdef DEBUG_REGEX
       if (trace_file)
-       xfprintf (trace_file, "flush:{%s}\n", victim->str);
+       {
+         fputs ("flush:{", trace_file);
+         fwrite (victim->str, 1, victim->len, trace_file);
+         fputs ("}\n", trace_file);
+       }
 #endif /* DEBUG_REGEX */
       free (victim->str);
       regfree (victim->buf);
@@ -404,8 +416,8 @@ set_macro_sequence (const char *regexp)
   msg = re_compile_pattern (regexp, strlen (regexp), &macro_sequence_buf);
   if (msg != NULL)
     m4_error (EXIT_FAILURE, 0, NULL,
-             _("--warn-macro-sequence: bad regular expression `%s': %s"),
-             regexp, msg);
+             _("--warn-macro-sequence: bad regular expression %s: %s"),
+             quotearg_style (locale_quoting_style, regexp), msg);
   re_set_registers (&macro_sequence_buf, &macro_sequence_regs,
                    macro_sequence_regs.num_regs,
                    macro_sequence_regs.start, macro_sequence_regs.end);
@@ -1208,7 +1220,7 @@ m4_eval (struct obstack *obs, int argc, macro_arguments 
*argv)
 
   if (radix < 1 || radix > 36)
     {
-      m4_warn (0, me, _("radix %d out of range"), radix);
+      m4_warn (0, me, _("radix out of range: %d"), radix);
       return;
     }
 
@@ -1216,13 +1228,11 @@ m4_eval (struct obstack *obs, int argc, macro_arguments 
*argv)
     return;
   if (min < 0)
     {
-      m4_warn (0, me, _("negative width"));
+      m4_warn (0, me, _("negative width: %d"), min);
       return;
     }
 
-  if (arg_empty (argv, 1))
-    m4_warn (0, me, _("empty string treated as 0"));
-  else if (evaluate (me, ARG (1), &value))
+  if (evaluate (me, ARG (1), ARG_LEN (1), &value))
     return;
 
   if (radix == 1)
@@ -1887,34 +1897,42 @@ m4_substr (struct obstack *obs, int argc, 
macro_arguments *argv)
   obstack_grow (obs, ARG (1) + start, length);
 }
 
-/*------------------------------------------------------------------------.
-| For "translit", ranges are allowed in the second and third argument.   |
-| They are expanded in 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.                        
  |
-`------------------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| For "translit", ranges are allowed in the second and third        |
+| argument.  They are expanded in 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.  This function expands S of length *LEN |
+| using OBS for the expansion, sets *LEN to the new length, and     |
+| returns the expansion.                                            |
+`------------------------------------------------------------------*/
 
 static const char *
-expand_ranges (const char *s, struct obstack *obs)
+expand_ranges (const char *s, size_t *len, struct obstack *obs)
 {
   unsigned char from;
   unsigned char to;
+  const char *end = s + *len;
+
+  assert (s != end);
+  from = *s++;
+  obstack_1grow (obs, from);
 
-  for (from = '\0'; *s != '\0'; from = to_uchar (*s++))
+  for ( ; s != end; from = *s++)
     {
-      if (*s == '-' && from != '\0')
+      if (*s == '-')
        {
-         to = to_uchar (*++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);
@@ -1928,7 +1946,7 @@ expand_ranges (const char *s, struct obstack *obs)
       else
        obstack_1grow (obs, *s);
     }
-  obstack_1grow (obs, '\0');
+  *len = obstack_object_size (obs);
   return (char *) obstack_finish (obs);
 }
 
@@ -1946,25 +1964,32 @@ m4_translit (struct obstack *obs, int argc, 
macro_arguments *argv)
   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;
 
-  if (bad_argc (arg_info (argv), argc, 2, 3))
+  enum { ASIS, REPLACE, DELETE };
+
+  if (bad_argc (arg_info (argv), argc, 2, 3) || arg_empty (argv, 1)
+      || arg_empty (argv, 2))
     {
       /* builtin(`translit') is blank, but translit(`abc') is abc.  */
-      if (argc == 2)
+      if (argc >= 2)
        push_arg (obs, argv, 1);
       return;
     }
 
   from = ARG (2);
-  if (strchr (from, '-') != NULL)
-    from = expand_ranges (from, arg_scratch ());
+  from_len = ARG_LEN (2);
+  if (memchr (from, '-', from_len) != NULL)
+    from = expand_ranges (from, &from_len, arg_scratch ());
 
   to = ARG (3);
-  if (strchr (to, '-') != NULL)
-    to = expand_ranges (to, arg_scratch ());
+  to_len = ARG_LEN (3);
+  if (memchr (to, '-', to_len) != NULL)
+    to = expand_ranges (to, &to_len, arg_scratch ());
 
   assert (from && to);
 
@@ -1974,23 +1999,45 @@ m4_translit (struct obstack *obs, int argc, 
macro_arguments *argv)
      pass of data, for linear behavior.  Traditional behavior is that
      only the first instance of a character in from is consulted,
      hence the found map.  */
-  for ( ; (ch = *from) != '\0'; from++)
+  while (from_len--)
     {
-      if (!found[ch])
+      ch = *from++;
+      if (found[ch] == ASIS)
+       {
+         if (to_len)
+           {
+             found[ch] = REPLACE;
+             map[ch] = *to;
+           }
+         else
+           found[ch] = DELETE;
+       }
+      if (to_len)
        {
-         found[ch] = 1;
-         map[ch] = *to;
+         to++;
+         to_len--;
        }
-      if (*to != '\0')
-       to++;
     }
 
-  for (data = ARG (1); (ch = *data) != '\0'; data++)
+  data = ARG (1);
+  from_len = ARG_LEN (1);
+  while (from_len--)
     {
-      if (!found[ch])
-       obstack_1grow (obs, ch);
-      else if (map[ch])
-       obstack_1grow (obs, map[ch]);
+      ch = *data++;
+      switch (found[ch])
+       {
+       case ASIS:
+         obstack_1grow (obs, ch);
+         break;
+       case REPLACE:
+         obstack_1grow (obs, map[ch]);
+         break;
+       case DELETE:
+         break;
+       default:
+         assert (!"m4_translit");
+         abort ();
+       }
     }
 }
 
@@ -2020,20 +2067,27 @@ static int substitute_warned = 0;
 
 static void
 substitute (struct obstack *obs, const call_info *me, const char *victim,
-           const char *repl, struct re_registers *regs)
+           const char *repl, size_t repl_len, struct re_registers *regs)
 {
   int ch;
 
-  for (;;)
+  while (repl_len--)
     {
-      while ((ch = *repl++) != '\\')
+      ch = *repl++;
+      if (ch != '\\')
        {
-         if (ch == '\0')
-           return;
          obstack_1grow (obs, ch);
+         continue;
+       }
+      if (!repl_len)
+       {
+         m4_warn (0, me, _("trailing \\ ignored in replacement"));
+         return;
        }
 
-      switch ((ch = *repl++))
+      ch = *repl++;
+      repl_len--;
+      switch (ch)
        {
        case '0':
          if (!substitute_warned)
@@ -2060,10 +2114,6 @@ substitute (struct obstack *obs, const call_info *me, 
const char *victim,
                          regs->end[ch] - regs->start[ch]);
          break;
 
-       case '\0':
-         m4_warn (0, me, _("trailing \\ ignored in replacement"));
-         return;
-
        default:
          obstack_1grow (obs, ch);
          break;
@@ -2122,26 +2172,36 @@ m4_regexp (struct obstack *obs, int argc, 
macro_arguments *argv)
   regexp = ARG (2);
   repl = ARG (3);
 
-  if (!*regexp)
+  if (arg_empty (argv, 2))
     {
       /* The empty regex matches everything!  */
       if (argc == 3)
        shipout_int (obs, 0);
       else
-       substitute (obs, me, victim, repl, NULL);
+       substitute (obs, me, victim, repl, ARG_LEN (3), NULL);
       return;
     }
 
 #ifdef DEBUG_REGEX
   if (trace_file)
-    xfprintf (trace_file, "r:{%s}:%s%s%s\n", regexp,
-             argc == 3 ? "" : "{", repl, argc == 3 ? "" : "}");
+    {
+      fputs ("r:{", trace_file);
+      fwrite (regexp, 1, ARG_LEN (2), trace_file);
+      if (argc > 3)
+       {
+         fputs ("}:{", trace_file);
+         fwrite (repl, 1, ARG_LEN (3), trace_file);
+       }
+      fputs ("}\n", trace_file);
+    }
 #endif /* DEBUG_REGEX */
 
   msg = compile_pattern (regexp, ARG_LEN (2), &buf, &regs);
   if (msg != NULL)
     {
-      m4_warn (0, me, _("bad regular expression: `%s': %s"), regexp, msg);
+      m4_warn (0, me, _("bad regular expression %s: %s"),
+              quotearg_style_mem (locale_quoting_style, regexp, ARG_LEN (2)),
+              msg);
       return;
     }
 
@@ -2151,11 +2211,12 @@ m4_regexp (struct obstack *obs, int argc, 
macro_arguments *argv)
                        argc == 3 ? NULL : regs);
 
   if (startpos == -2)
-    m4_warn (0, me, _("problem matching regular expression `%s'"), regexp);
+    m4_warn (0, me, _("problem matching regular expression %s"),
+            quotearg_style_mem (locale_quoting_style, regexp, ARG_LEN (2)));
   else if (argc == 3)
     shipout_int (obs, startpos);
   else if (startpos >= 0)
-    substitute (obs, me, victim, repl, regs);
+    substitute (obs, me, victim, repl, ARG_LEN (3), regs);
 }
 
 /*------------------------------------------------------------------.
@@ -2170,16 +2231,17 @@ static void
 m4_patsubst (struct obstack *obs, int argc, macro_arguments *argv)
 {
   const call_info *me = arg_info (argv);
-  const char *victim;          /* first argument */
-  const char *regexp;          /* regular expression */
-  const char *repl;
-
-  struct re_pattern_buffer *buf;/* compiled regular expression */
-  struct re_registers *regs;   /* for subexpression matches */
-  const char *msg;             /* error message from re_compile_pattern */
-  int matchpos;                        /* start position of match */
-  int offset;                  /* current match offset */
-  int length;                  /* length of first argument */
+  const char *victim;          /* First argument.  */
+  const char *regexp;          /* Regular expression.  */
+  const char *repl;            /* Replacement text.  */
+
+  struct re_pattern_buffer *buf;/* Compiled regular expression.  */
+  struct re_registers *regs;   /* For subexpression matches.  */
+  const char *msg;             /* Error message from re_compile_pattern.  */
+  int matchpos;                        /* Start position of match.  */
+  int offset;                  /* Current match offset.  */
+  int length;                  /* Length of first argument.  */
+  size_t repl_len;             /* Length of replacement.  */
 
   if (bad_argc (me, argc, 2, 3))
     {
@@ -2189,27 +2251,36 @@ m4_patsubst (struct obstack *obs, int argc, 
macro_arguments *argv)
       return;
     }
 
-  victim = ARG (1);
-  regexp = ARG (2);
-  repl = ARG (3);
-
   /* The empty regex matches everywhere, but if there is no
      replacement, we need not waste time with it.  */
-  if (!*regexp && !*repl)
+  if (arg_empty (argv, 2) && arg_empty (argv, 3))
     {
       push_arg (obs, argv, 1);
       return;
     }
 
+  victim = ARG (1);
+  regexp = ARG (2);
+  repl = ARG (3);
+  repl_len = ARG_LEN (3);
+
 #ifdef DEBUG_REGEX
   if (trace_file)
-    xfprintf (trace_file, "p:{%s}:{%s}\n", regexp, repl);
+    {
+      fputs ("p:{", trace_file);
+      fwrite (regexp, 1, ARG_LEN (2), trace_file);
+      fputs ("}:{", trace_file);
+      fwrite (repl, 1, repl_len, trace_file);
+      fputs ("}\n", trace_file);
+    }
 #endif /* DEBUG_REGEX */
 
   msg = compile_pattern (regexp, ARG_LEN (2), &buf, &regs);
   if (msg != NULL)
     {
-      m4_warn (0, me, _("bad regular expression `%s': %s"), regexp, msg);
+      m4_warn (0, me, _("bad regular expression %s: %s"),
+              quotearg_style_mem (locale_quoting_style, regexp, ARG_LEN (2)),
+              msg);
       return;
     }
 
@@ -2229,8 +2300,9 @@ m4_patsubst (struct obstack *obs, int argc, 
macro_arguments *argv)
             copied verbatim.  */
 
          if (matchpos == -2)
-           m4_warn (0, me, _("problem matching regular expression `%s'"),
-                    regexp);
+           m4_warn (0, me, _("problem matching regular expression %s"),
+                    quotearg_style_mem (locale_quoting_style, regexp,
+                                        ARG_LEN (2)));
          else if (offset < length)
            obstack_grow (obs, victim + offset, length - offset);
          break;
@@ -2243,7 +2315,7 @@ m4_patsubst (struct obstack *obs, int argc, 
macro_arguments *argv)
 
       /* Handle the part of the string that was covered by the match.  */
 
-      substitute (obs, me, victim, repl, regs);
+      substitute (obs, me, victim, repl, repl_len, regs);
 
       /* Update the offset to the end of the match.  If the regexp
         matched a null string, advance offset one more, to avoid
diff --git a/src/eval.c b/src/eval.c
index e2e600b..1b617ed 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -58,7 +58,8 @@ typedef enum eval_error
     MISSING_RIGHT,
     UNKNOWN_INPUT,
     EXCESS_INPUT,
-    INVALID_OPERATOR
+    INVALID_OPERATOR,
+    EMPTY_ARGUMENT
   }
 eval_error;
 
@@ -87,10 +88,15 @@ static const char *eval_text;
    can back up, if we have read too much.  */
 static const char *last_text;
 
+/* Detect when to end parsing.  */
+static const char *end_text;
+
+/* Prime the lexer at the start of TEXT, with length LEN.  */
 static void
-eval_init_lex (const char *text)
+eval_init_lex (const char *text, size_t len)
 {
   eval_text = text;
+  end_text = text + len;
   last_text = NULL;
 }
 
@@ -105,12 +111,12 @@ eval_undo (void)
 static eval_token
 eval_lex (int32_t *val)
 {
-  while (isspace (to_uchar (*eval_text)))
+  while (eval_text != end_text && isspace (to_uchar (*eval_text)))
     eval_text++;
 
   last_text = eval_text;
 
-  if (*eval_text == '\0')
+  if (eval_text == end_text)
     return EOTEXT;
 
   if (isdigit (to_uchar (*eval_text)))
@@ -287,14 +293,17 @@ eval_lex (int32_t *val)
 `---------------------------------------*/
 
 bool
-evaluate (const call_info *me, const char *expr, int32_t *val)
+evaluate (const call_info *me, const char *expr, size_t len, int32_t *val)
 {
   eval_token et;
   eval_error err;
 
-  eval_init_lex (expr);
+  eval_init_lex (expr, len);
   et = eval_lex (val);
-  err = logical_or_term (me, et, val);
+  if (et == EOTEXT)
+    err = EMPTY_ARGUMENT;
+  else
+    err = logical_or_term (me, et, val);
 
   if (err == NO_ERROR && *eval_text != '\0')
     {
@@ -306,9 +315,15 @@ evaluate (const call_info *me, const char *expr, int32_t 
*val)
 
   switch (err)
     {
+      /* Cases where result is printed.  */
     case NO_ERROR:
-      break;
+      return false;
+
+    case EMPTY_ARGUMENT:
+      m4_warn (0, me, _("empty string treated as 0"));
+      return false;
 
+      /* Cases where error makes result meaningless.  */
     case MISSING_RIGHT:
       m4_warn (0, me, _("bad expression (missing right parenthesis): %s"),
               expr);
@@ -347,7 +362,7 @@ evaluate (const call_info *me, const char *expr, int32_t 
*val)
       abort ();
     }
 
-  return err != NO_ERROR;
+  return true;
 }
 
 /*---------------------------.
diff --git a/src/format.c b/src/format.c
index 3325853..8b2b11a 100644
--- a/src/format.c
+++ b/src/format.c
@@ -126,11 +126,12 @@ expand_format (struct obstack *obs, int argc, 
macro_arguments *argv)
 {
   const call_info *me = arg_info (argv);/* Macro name.  */
   const char *f;                       /* Format control string.  */
+  size_t f_len;                                /* Length of f.  */
   const char *fmt;                     /* Position within f.  */
   char fstart[] = "%'+- 0#*.*hhd";     /* Current format spec.  */
   char *p;                             /* Position within fstart.  */
   unsigned char c;                     /* A simple character.  */
-  int i = 0;                           /* Index within argc used so far.  */
+  int i = 1;                           /* Index within argc used so far.  */
   bool valid_format = true;            /* True if entire format string ok.  */
 
   /* Flags.  */
@@ -159,25 +160,24 @@ expand_format (struct obstack *obs, int argc, 
macro_arguments *argv)
   int result = 0;
   enum {CHAR, INT, LONG, DOUBLE, STR} datatype;
 
-  f = fmt = ARG_STR (i, argc, argv);
+  f = fmt = ARG (1);
+  f_len = ARG_LEN (1);
+  assert (!f[f_len]); /* Requiring a terminating NUL makes parsing simpler.  */
   memset (ok, 0, sizeof ok);
-  while (true)
+  while (f_len--)
     {
-      while ((c = *fmt++) != '%')
+      c = *fmt++;
+      if (c != '%')
        {
-         if (c == '\0')
-           {
-             if (valid_format)
-               bad_argc (me, argc, i, i);
-             return;
-           }
          obstack_1grow (obs, c);
+         continue;
        }
 
       if (*fmt == '%')
        {
          obstack_1grow (obs, '%');
          fmt++;
+         f_len--;
          continue;
        }
 
@@ -228,7 +228,7 @@ expand_format (struct obstack *obs, int argc, 
macro_arguments *argv)
              break;
            }
        }
-      while (!(flags & DONE) && fmt++);
+      while (!(flags & DONE) && (f_len--, fmt++));
       if (flags & THOUSANDS)
        *p++ = '\'';
       if (flags & PLUS)
@@ -250,12 +250,14 @@ expand_format (struct obstack *obs, int argc, 
macro_arguments *argv)
        {
          width = ARG_INT (i, argc, argv);
          fmt++;
+         f_len--;
        }
       else
        while (isdigit (to_uchar (*fmt)))
          {
            width = 10 * width + *fmt - '0';
            fmt++;
+           f_len--;
          }
 
       /* Maximum precision; an explicit negative precision is the same
@@ -266,10 +268,12 @@ expand_format (struct obstack *obs, int argc, 
macro_arguments *argv)
       if (*fmt == '.')
        {
          ok['c'] = 0;
+         f_len--;
          if (*(++fmt) == '*')
            {
              prec = ARG_INT (i, argc, argv);
              ++fmt;
+             f_len--;
            }
          else
            {
@@ -278,6 +282,7 @@ expand_format (struct obstack *obs, int argc, 
macro_arguments *argv)
                {
                  prec = 10 * prec + *fmt - '0';
                  fmt++;
+                 f_len--;
                }
            }
        }
@@ -288,30 +293,34 @@ expand_format (struct obstack *obs, int argc, 
macro_arguments *argv)
          *p++ = 'l';
          lflag = 1;
          fmt++;
+         f_len--;
          ok['c'] = ok['s'] = 0;
        }
       else if (*fmt == 'h')
        {
          *p++ = 'h';
          fmt++;
+         f_len--;
          if (*fmt == 'h')
            {
              *p++ = 'h';
              fmt++;
+             f_len--;
            }
          ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = ok['f'] = ok['F']
            = ok['g'] = ok['G'] = ok['s'] = 0;
        }
 
-      c = *fmt++;
-      if (c > sizeof ok || !ok[c])
+      c = *fmt;
+      if (c > sizeof ok || !ok[c] || !f_len)
        {
-         m4_warn (0, me, _("unrecognized specifier in `%s'"), f);
+         m4_warn (0, me, _("unrecognized specifier in %s"),
+                  quotearg_style_mem (locale_quoting_style, f, ARG_LEN (1)));
          valid_format = false;
-         if (c == '\0')
-           fmt--;
          continue;
        }
+      fmt++;
+      f_len--;
 
       /* Specifiers.  We don't yet recognize C, S, n, or p.  */
       switch (c)
@@ -385,4 +394,6 @@ expand_format (struct obstack *obs, int argc, 
macro_arguments *argv)
         we constructed fstart, the result should not be negative.  */
       assert (0 <= result);
     }
+  if (valid_format)
+    bad_argc (me, argc, i, i);
 }
diff --git a/src/m4.h b/src/m4.h
index f643e49..76c697b 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -549,7 +549,7 @@ FILE *m4_path_search (const char *, char **);
 
 /* File: eval.c  --- expression evaluation.  */
 
-bool evaluate (const call_info *, const char *, int32_t *);
+bool evaluate (const call_info *, const char *, size_t, int32_t *);
 
 /* File: format.c  --- printf like formatting.  */
 


hooks/post-receive
--
GNU M4 source repository




reply via email to

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