summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <ebb9@byu.net>2008-02-05 11:41:05 -0700
committerEric Blake <ebb9@byu.net>2009-02-10 14:43:13 -0700
commitfd9f6463352aee342c4061b5df9d0f4bf56742c7 (patch)
tree647390c9599b49def1a904c538595bff4d29cb26
parent948d1ed0ca4089c2db579fe3d8b3ce172b3e616f (diff)
downloadm4-fd9f6463352aee342c4061b5df9d0f4bf56742c7.tar.gz
Stage28: allow NUL in warning messages
-rw-r--r--doc/m4.texinfo38
-rw-r--r--examples/null.errbin1078 -> 3084 bytes
-rw-r--r--examples/null.m4bin6667 -> 6620 bytes
-rw-r--r--examples/null.outbin553 -> 572 bytes
-rw-r--r--m4/gnulib-cache.m42
-rw-r--r--src/builtin.c130
-rw-r--r--src/debug.c19
-rw-r--r--src/eval.c9
-rw-r--r--src/format.c55
-rw-r--r--src/freeze.c13
-rw-r--r--src/m4.c13
-rw-r--r--src/m4.h2
-rw-r--r--src/path.c4
13 files changed, 192 insertions, 93 deletions
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index eb2a6673..0f5c53ef 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -43,7 +43,7 @@ This manual is for @acronym{GNU} M4 (version @value{VERSION}, @value{UPDATED}),
a package containing an implementation of the m4 macro language.
Copyright @copyright{} 1989, 1990, 1991, 1992, 1993, 1994, 2004, 2005,
-2006, 2007, 2008 Free Software Foundation, Inc.
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
@quotation
Permission is granted to copy, distribute and/or modify this document
@@ -935,14 +935,16 @@ exception of the @sc{nul} character (the zero byte @samp{'\0'}).
@comment xout: null.out
@comment xerr: null.err
+@comment status: 1
@example
define(`m4exit')include(`null.m4')dnl
@end example
-@comment status: 2
+@comment status: 1
@example
include(`null.m4')
@result{}# This file tests m4 behavior on NUL bytes.
+@error{}m4:examples/null.m4:5: Warning: m4exit: non-numeric argument `2\0002'
@end example
@end ignore
@@ -6087,10 +6089,10 @@ eval(`2 = 2')
@error{}m4:stdin:1: Warning: eval: recommend ==, not =, for equality
@result{}1
eval(`++0')
-@error{}m4:stdin:2: eval: invalid operator: ++0
+@error{}m4:stdin:2: eval: invalid operator: `++0'
@result{}
eval(`0 |= 1')
-@error{}m4:stdin:3: eval: invalid operator: 0 |= 1
+@error{}m4:stdin:3: eval: invalid operator: `0 |= 1'
@result{}
@end example
@@ -6133,12 +6135,12 @@ eval(`+ + - ~ ! ~ 0')
eval(`2 || 1 / 0')
@result{}1
eval(`0 || 1 / 0')
-@error{}m4:stdin:9: Warning: eval: divide by zero: 0 || 1 / 0
+@error{}m4:stdin:9: Warning: eval: divide by zero: `0 || 1 / 0'
@result{}
eval(`0 && 1 % 0')
@result{}0
eval(`2 && 1 % 0')
-@error{}m4:stdin:11: Warning: eval: modulo by zero: 2 && 1 % 0
+@error{}m4:stdin:11: Warning: eval: modulo by zero: `2 && 1 % 0'
@result{}
@end example
@@ -6159,9 +6161,9 @@ eval(`2 ** 0')
@result{}1
eval(`0 ** 0')
@result{}
-@error{}m4:stdin:5: Warning: eval: divide by zero: 0 ** 0
+@error{}m4:stdin:5: Warning: eval: divide by zero: `0 ** 0'
eval(`4 ** -2')
-@error{}m4:stdin:6: Warning: eval: negative exponent: 4 ** -2
+@error{}m4:stdin:6: Warning: eval: negative exponent: `4 ** -2'
@result{}
@end example
@@ -6206,7 +6208,7 @@ square(square(`5')` + 1')
define(`foo', `666')
@result{}
eval(`foo / 6')
-@error{}m4:stdin:11: Warning: eval: bad expression: foo / 6
+@error{}m4:stdin:11: Warning: eval: bad expression: `foo / 6'
@result{}
eval(foo / 6)
@result{}111
@@ -6659,10 +6661,12 @@ define(`foo', `errprint(`oops')')
syscmd(`rm -f foo-??????')sysval
@result{}0
define(`file1', maketemp(`foo-XXXXXX'))dnl
+@error{}m4:stdin:3: Warning: maketemp: recommend using mkstemp instead
ifelse(esyscmd(`echo \` foo-?????? \''), ` foo-?????? ',
`no file', `created')
@result{}created
define(`file2', maketemp(`foo-XX'))dnl
+@error{}m4:stdin:6: Warning: maketemp: recommend using mkstemp instead
define(`file3', mkstemp(`foo-XXXXXX'))dnl
ifelse(len(defn(`file1')), len(defn(`file2')),
`same length', `different')
@@ -7082,6 +7086,20 @@ divert(1)undivert(null.out)' | ]__program__[ -F in.m4f \
])dnl
@error{}divnum #-- 3 0
@end example
+
+@c Do we reject unexpected NUL bytes?
+
+@example
+ifdef(`__unix__', ,
+ `errprint(` skipping: syscmd does not have unix semantics
+')m4exit(`77')')dnl
+changequote(`[', `]')dnl
+syscmd([printf '#bogus\nV1\nF3,4\nlenlen\0\n' > in.m4f \
+ && ]__program__[ -R in.m4f \
+ && rm in.m4f])sysval
+@error{}m4: ill-formed frozen file, invalid builtin `len\0' encountered
+@result{}1
+@end example
@end ignore
When an @code{m4} run is to be frozen, the automatic undiversion
@@ -7615,7 +7633,7 @@ forloop(`', `1', `2', ` odd iterator name')
forloop(`i', `5 + 5', `0xc', ` 0x`'eval(i, `16')')
@result{} 0xa 0xb 0xc
forloop(`i', `a', `b', `non-numeric bounds')
-@error{}m4:stdin:6: Warning: eval: bad expression (bad input): (b) >= (a)
+@error{}m4:stdin:6: Warning: eval: bad input in expression: `(b) >= (a)'
@result{}
@end example
diff --git a/examples/null.err b/examples/null.err
index 977b3b7c..b0858b3e 100644
--- a/examples/null.err
+++ b/examples/null.err
Binary files differ
diff --git a/examples/null.m4 b/examples/null.m4
index e60aec5a..3dc8d16c 100644
--- a/examples/null.m4
+++ b/examples/null.m4
Binary files differ
diff --git a/examples/null.out b/examples/null.out
index c2c1cb90..0dfbfdb4 100644
--- a/examples/null.out
+++ b/examples/null.out
Binary files differ
diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4
index 5a1cd9b4..eaa67a2f 100644
--- a/m4/gnulib-cache.m4
+++ b/m4/gnulib-cache.m4
@@ -1,4 +1,4 @@
-# Copyright (C) 2002-2008 Free Software Foundation, Inc.
+# Copyright (C) 2002-2009 Free Software Foundation, Inc.
#
# This file is free software, distributed under the terms of the GNU
# General Public License. As a special exception to the GNU General
diff --git a/src/builtin.c b/src/builtin.c
index beb2a04a..0c9b9056 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1,7 +1,7 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2000, 2004, 2006, 2007,
- 2008 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2000, 2004, 2006,
+ 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU M4.
@@ -562,18 +562,18 @@ bad_argc (const call_info *name, int argc, unsigned int min, unsigned int max)
return false;
}
-/*-------------------------------------------------------------------.
-| The function numeric_arg () converts ARG to an int pointed to by |
-| VALUEP. If the conversion fails, print error message on behalf of |
-| NAME. Return true iff conversion succeeds. |
-`-------------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| The function numeric_arg () converts ARG of length LEN to an int |
+| pointed to by VALUEP. If the conversion fails, print error |
+| message on behalf of NAME. Return true iff conversion succeeds. |
+`------------------------------------------------------------------*/
static bool
-numeric_arg (const call_info *name, const char *arg, int *valuep)
+numeric_arg (const call_info *name, const char *arg, size_t len, int *valuep)
{
char *endp;
- if (*arg == '\0')
+ if (!len)
{
*valuep = 0;
m4_warn (0, name, _("empty string treated as 0"));
@@ -582,9 +582,10 @@ numeric_arg (const call_info *name, const char *arg, int *valuep)
{
errno = 0;
*valuep = strtol (arg, &endp, 10);
- if (*endp != '\0')
+ if (endp - arg != len)
{
- m4_warn (0, name, _("non-numeric argument `%s'"), arg);
+ m4_warn (0, name, _("non-numeric argument %s"),
+ quotearg_style_mem (locale_quoting_style, arg, len));
return false;
}
if (isspace (to_uchar (*arg)))
@@ -1070,8 +1071,9 @@ m4_defn (struct obstack *obs, int argc, macro_arguments *argv)
b = SYMBOL_FUNC (s);
if (b == m4_placeholder)
m4_warn (0, me,
- _("builtin `%s' requested by frozen file not found"),
- ARG (i));
+ _("builtin %s requested by frozen file not found"),
+ quotearg_style_mem (locale_quoting_style, ARG (i),
+ ARG_LEN (i)));
else
push_macro (obs, b);
break;
@@ -1123,7 +1125,14 @@ static int sysval;
static void
m4_syscmd (struct obstack *obs, int argc, macro_arguments *argv)
{
- if (bad_argc (arg_info (argv), argc, 1, 1))
+ const call_info *me = arg_info (argv);
+ const char *cmd = ARG (1);
+ size_t len = ARG_LEN (1);
+
+ if (strlen (cmd) != len)
+ m4_warn (0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, cmd, len));
+ if (bad_argc (me, argc, 1, 1) || !*cmd)
{
/* The empty command is successful. */
sysval = 0;
@@ -1131,7 +1140,7 @@ m4_syscmd (struct obstack *obs, int argc, macro_arguments *argv)
}
debug_flush_files ();
- sysval = system (ARG (1));
+ sysval = system (cmd);
#if FUNC_SYSTEM_BROKEN
/* OS/2 has a buggy system() that returns exit status in the lowest eight
bits, although pclose() and WEXITSTATUS are defined to return exit
@@ -1148,10 +1157,15 @@ static void
m4_esyscmd (struct obstack *obs, int argc, macro_arguments *argv)
{
const call_info *me = arg_info (argv);
+ const char *cmd = ARG (1);
+ size_t len = ARG_LEN (1);
FILE *pin;
int ch;
- if (bad_argc (me, argc, 1, 1))
+ if (strlen (cmd) != len)
+ m4_warn (0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, cmd, len));
+ if (bad_argc (me, argc, 1, 1) || !*cmd)
{
/* The empty command is successful. */
sysval = 0;
@@ -1160,10 +1174,11 @@ m4_esyscmd (struct obstack *obs, int argc, macro_arguments *argv)
debug_flush_files ();
errno = 0;
- pin = popen (ARG (1), "r");
+ pin = popen (cmd, "r");
if (pin == NULL)
{
- m4_warn (errno, me, _("cannot open pipe to command `%s'"), ARG (1));
+ m4_warn (errno, me, _("cannot open pipe to command %s"),
+ quotearg_style (locale_quoting_style, cmd));
sysval = -1;
}
else
@@ -1200,7 +1215,7 @@ m4_eval (struct obstack *obs, int argc, macro_arguments *argv)
if (bad_argc (me, argc, 1, 3))
return;
- if (!arg_empty (argv, 2) && !numeric_arg (me, ARG (2), &radix))
+ if (!arg_empty (argv, 2) && !numeric_arg (me, ARG (2), ARG_LEN (2), &radix))
return;
if (radix < 1 || radix > 36)
@@ -1209,7 +1224,7 @@ m4_eval (struct obstack *obs, int argc, macro_arguments *argv)
return;
}
- if (argc >= 4 && !numeric_arg (me, ARG (3), &min))
+ if (argc >= 4 && !numeric_arg (me, ARG (3), ARG_LEN (3), &min))
return;
if (min < 0)
{
@@ -1264,7 +1279,7 @@ m4_incr (struct obstack *obs, int argc, macro_arguments *argv)
if (bad_argc (me, argc, 1, 1))
return;
- if (!numeric_arg (me, ARG (1), &value))
+ if (!numeric_arg (me, ARG (1), ARG_LEN (1), &value))
return;
shipout_int (obs, value + 1);
@@ -1279,7 +1294,7 @@ m4_decr (struct obstack *obs, int argc, macro_arguments *argv)
if (bad_argc (me, argc, 1, 1))
return;
- if (!numeric_arg (me, ARG (1), &value))
+ if (!numeric_arg (me, ARG (1), ARG_LEN (1), &value))
return;
shipout_int (obs, value - 1);
@@ -1300,7 +1315,7 @@ m4_divert (struct obstack *obs, int argc, macro_arguments *argv)
int i = 0;
bad_argc (me, argc, 0, 1);
- if (argc >= 2 && !numeric_arg (me, ARG (1), &i))
+ if (argc >= 2 && !numeric_arg (me, ARG (1), ARG_LEN (1), &i))
return;
make_diversion (i);
@@ -1339,11 +1354,16 @@ m4_undivert (struct obstack *obs, int argc, macro_arguments *argv)
for (i = 1; i < argc; i++)
{
const char *str = ARG (i);
+ size_t len = ARG_LEN (i);
file = strtol (str, &endp, 10);
- if (*endp == '\0' && !isspace (to_uchar (*str)))
+ if (endp - str == len && !isspace (to_uchar (*str)))
insert_diversion (file);
else if (no_gnu_extensions)
- m4_warn (0, me, _("non-numeric argument `%s'"), str);
+ m4_warn (0, me, _("non-numeric argument %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
+ else if (strlen (str) != len)
+ m4_warn (0, me, _("invalid file name %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
else
{
fp = m4_path_search (str, NULL);
@@ -1351,10 +1371,12 @@ m4_undivert (struct obstack *obs, int argc, macro_arguments *argv)
{
insert_file (fp);
if (fclose (fp) == EOF)
- m4_warn (errno, me, _("error undiverting `%s'"), str);
+ m4_warn (errno, me, _("error undiverting %s"),
+ quotearg_style (locale_quoting_style, str));
}
else
- m4_warn (errno, me, _("cannot undivert `%s'"), str);
+ m4_warn (errno, me, _("cannot undivert %s"),
+ quotearg_style (locale_quoting_style, str));
}
}
}
@@ -1453,15 +1475,23 @@ include (int argc, macro_arguments *argv, bool silent)
const call_info *me = arg_info (argv);
FILE *fp;
char *name;
+ const char *arg;
+ size_t len;
if (bad_argc (me, argc, 1, 1))
return;
- fp = m4_path_search (ARG (1), &name);
+ arg = ARG (1);
+ len = ARG_LEN (1);
+ if (strlen (arg) != len)
+ m4_warn (0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, arg, len));
+ fp = m4_path_search (arg, &name);
if (fp == NULL)
{
if (!silent)
- m4_error (0, errno, me, _("cannot open `%s'"), ARG (1));
+ m4_error (0, errno, me, _("cannot open %s"),
+ quotearg_style (locale_quoting_style, arg));
return;
}
@@ -1511,6 +1541,12 @@ mkstemp_helper (struct obstack *obs, const call_info *me, const char *pattern,
user forgot to supply them. Output must be quoted if
successful. */
obstack_grow (obs, curr_quote.str1, curr_quote.len1);
+ if (strlen (pattern) < len)
+ {
+ m4_warn (0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, pattern, len));
+ len = strlen (pattern);
+ }
obstack_grow (obs, pattern, len);
for (i = 0; len > 0 && i < 6; i++)
if (pattern[--len] != 'X')
@@ -1522,7 +1558,8 @@ mkstemp_helper (struct obstack *obs, const call_info *me, const char *pattern,
fd = mkstemp (name);
if (fd < 0)
{
- m4_warn (errno, me, _("cannot create tempfile `%s'"), pattern);
+ m4_warn (errno, me, _("cannot create file from template %s"),
+ quotearg_style (locale_quoting_style, pattern));
obstack_free (obs, obstack_finish (obs));
}
else
@@ -1541,6 +1578,7 @@ m4_maketemp (struct obstack *obs, int argc, macro_arguments *argv)
if (bad_argc (me, argc, 1, 1))
return;
+ m4_warn (0, me, _("recommend using mkstemp instead"));
if (no_gnu_extensions)
{
/* POSIX states "any trailing 'X' characters [are] replaced with
@@ -1562,7 +1600,6 @@ m4_maketemp (struct obstack *obs, int argc, macro_arguments *argv)
(unsigned long) getpid ());
char *pid = (char *) obstack_copy0 (scratch, "", 0);
- m4_warn (0, me, _("recommend using mkstemp instead"));
for (i = len; i > 1; i--)
if (str[i - 1] != 'X')
break;
@@ -1648,7 +1685,7 @@ m4_m4exit (struct obstack *obs, int argc, macro_arguments *argv)
/* Warn on bad arguments, but still exit. */
bad_argc (me, argc, 0, 1);
- if (argc >= 2 && !numeric_arg (me, ARG (1), &exit_code))
+ if (argc >= 2 && !numeric_arg (me, ARG (1), ARG_LEN (1), &exit_code))
exit_code = EXIT_FAILURE;
if (exit_code < 0 || exit_code > 255)
{
@@ -1763,6 +1800,7 @@ m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv)
{
const call_info *me = arg_info (argv);
const char *str = ARG (1);
+ size_t len = ARG_LEN (1);
int new_debug_level;
int change_flag;
@@ -1775,16 +1813,17 @@ m4_debugmode (struct obstack *obs, int argc, macro_arguments *argv)
if (*str == '+' || *str == '-')
{
change_flag = *str;
- new_debug_level = debug_decode (str + 1);
+ new_debug_level = debug_decode (str + 1, len - 1);
}
else
{
change_flag = 0;
- new_debug_level = debug_decode (str);
+ new_debug_level = debug_decode (str, len);
}
if (new_debug_level < 0)
- m4_warn (0, me, _("bad debug flags: `%s'"), str);
+ m4_warn (0, me, _("bad debug flags: %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
else
{
switch (change_flag)
@@ -1819,8 +1858,17 @@ m4_debugfile (struct obstack *obs, int argc, macro_arguments *argv)
if (argc == 1)
debug_set_output (me, NULL);
- else if (!debug_set_output (me, ARG (1)))
- m4_warn (errno, me, _("cannot set error file: `%s'"), ARG (1));
+ else
+ {
+ const char *str = ARG (1);
+ size_t len = ARG_LEN (1);
+ if (strlen (str) < len)
+ m4_warn (0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, str, len));
+ if (!debug_set_output (me, str))
+ m4_warn (errno, me, _("cannot set debug file %s"),
+ quotearg_style (locale_quoting_style, str));
+ }
}
/* This section contains text processing macros: "len", "index",
@@ -1896,10 +1944,10 @@ m4_substr (struct obstack *obs, int argc, macro_arguments *argv)
}
length = avail = ARG_LEN (1);
- if (!numeric_arg (me, ARG (2), &start))
+ if (!numeric_arg (me, ARG (2), ARG_LEN (2), &start))
return;
- if (argc >= 4 && !numeric_arg (me, ARG (3), &length))
+ if (argc >= 4 && !numeric_arg (me, ARG (3), ARG_LEN (3), &length))
return;
if (start < 0 || length <= 0 || start >= avail)
@@ -2362,8 +2410,8 @@ m4_patsubst (struct obstack *obs, int argc, macro_arguments *argv)
void
m4_placeholder (struct obstack *obs, int argc, macro_arguments *argv)
{
- m4_warn (0, NULL, _("builtin `%s' requested by frozen file not found"),
- ARG (0));
+ m4_warn (0, NULL, _("builtin %s requested by frozen file not found"),
+ quotearg_style_mem (locale_quoting_style, ARG (0), ARG_LEN (0)));
}
/*-------------------------------------------------------------------------.
diff --git a/src/debug.c b/src/debug.c
index c3f85bd6..82f0cbc8 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -43,21 +43,26 @@ debug_init (void)
obstack_init (&trace);
}
-/*-----------------------------------------------------------------.
-| Function to decode the debugging flags OPTS. Used by main while |
-| processing option -d, and by the builtin debugmode (). |
-`-----------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| Function to decode the debugging flags OPTS of length LEN. If LEN |
+| is SIZE_MAX, use strlen (OPTS) instead. Used by main while |
+| processing option -d, and by the builtin debugmode. |
+`-------------------------------------------------------------------*/
int
-debug_decode (const char *opts)
+debug_decode (const char *opts, size_t len)
{
int level;
- if (opts == NULL || *opts == '\0')
+ if (!opts)
+ opts = "";
+ if (len == SIZE_MAX)
+ len = strlen (opts);
+ if (!len)
level = DEBUG_TRACE_DEFAULT;
else
{
- for (level = 0; *opts; opts++)
+ for (level = 0; len--; opts++)
{
switch (*opts)
{
diff --git a/src/eval.c b/src/eval.c
index 1b617ed7..b72e5cd1 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -313,6 +313,8 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val)
err = EXCESS_INPUT;
}
+ if (err != NO_ERROR)
+ expr = quotearg_style_mem (locale_quoting_style, expr, len);
switch (err)
{
/* Cases where result is printed. */
@@ -325,8 +327,7 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val)
/* Cases where error makes result meaningless. */
case MISSING_RIGHT:
- m4_warn (0, me, _("bad expression (missing right parenthesis): %s"),
- expr);
+ m4_warn (0, me, _("missing right parenthesis: %s"), expr);
break;
case SYNTAX_ERROR:
@@ -334,11 +335,11 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val)
break;
case UNKNOWN_INPUT:
- m4_warn (0, me, _("bad expression (bad input): %s"), expr);
+ m4_warn (0, me, _("bad input in expression: %s"), expr);
break;
case EXCESS_INPUT:
- m4_warn (0, me, _("bad expression (excess input): %s"), expr);
+ m4_warn (0, me, _("excess input in expression: %s"), expr);
break;
case INVALID_OPERATOR:
diff --git a/src/format.c b/src/format.c
index 8b2b11ae..09cffa3c 100644
--- a/src/format.c
+++ b/src/format.c
@@ -27,24 +27,26 @@
same size; likewise for long and unsigned long. We do not yet
handle long double or long long. */
-/* Parse STR as an integer, reporting warnings on behalf of ME. */
+/* Parse STR of length LEN as an integer, reporting warnings on behalf
+ of ME. */
static int
-arg_int (const call_info *me, const char *str)
+arg_int (const call_info *me, const char *str, size_t len)
{
char *endp;
long value;
/* TODO - also allow parsing `'a' or `"a' which results in the
numeric value of 'a', as in printf(1). */
- if (*str == '\0')
+ if (!len)
{
m4_warn (0, me, _("empty string treated as 0"));
return 0;
}
errno = 0;
value = strtol (str, &endp, 10);
- if (*endp != '\0')
- m4_warn (0, me, _("non-numeric argument `%s'"), str);
+ if (endp - str != len)
+ m4_warn (0, me, _("non-numeric argument %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
else if (isspace (to_uchar (*str)))
m4_warn (0, me, _("leading whitespace ignored"));
else if (errno == ERANGE || (int) value != value)
@@ -52,24 +54,26 @@ arg_int (const call_info *me, const char *str)
return value;
}
-/* Parse STR as a long, reporting warnings on behalf of ME. */
+/* Parse STR of length LEN as a long, reporting warnings on behalf of
+ ME. */
static long
-arg_long (const call_info *me, const char *str)
+arg_long (const call_info *me, const char *str, size_t len)
{
char *endp;
long value;
/* TODO - also allow parsing `'a' or `"a' which results in the
numeric value of 'a', as in printf(1). */
- if (*str == '\0')
+ if (!len)
{
m4_warn (0, me, _("empty string treated as 0"));
return 0L;
}
errno = 0;
value = strtol (str, &endp, 10);
- if (*endp != '\0')
- m4_warn (0, me, _("non-numeric argument `%s'"), str);
+ if (endp - str != len)
+ m4_warn (0, me, _("non-numeric argument %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
else if (isspace (to_uchar (*str)))
m4_warn (0, me, _("leading whitespace ignored"));
else if (errno == ERANGE)
@@ -77,22 +81,35 @@ arg_long (const call_info *me, const char *str)
return value;
}
-/* Parse STR as a double, reporting warnings on behalf of ME. */
+/* Check STR of length LEN for embedded NUL, reporting warnings on
+ behalf of ME. */
+static const char *
+arg_string (const call_info *me, const char *str, size_t len)
+{
+ if (strlen (str) < len)
+ m4_warn (0, me, _("argument %s truncated"),
+ quotearg_style_mem (locale_quoting_style, str, len));
+ return str;
+}
+
+/* Parse STR of length LEN as a double, reporting warnings on behalf
+ of ME. */
static double
-arg_double (const call_info *me, const char *str)
+arg_double (const call_info *me, const char *str, size_t len)
{
char *endp;
double value;
- if (*str == '\0')
+ if (!len)
{
m4_warn (0, me, _("empty string treated as 0"));
return 0.0;
}
errno = 0;
value = strtod (str, &endp);
- if (*endp != '\0')
- m4_warn (0, me, _("non-numeric argument `%s'"), str);
+ if (endp - str != len)
+ m4_warn (0, me, _("non-numeric argument %s"),
+ quotearg_style_mem (locale_quoting_style, str, len));
else if (isspace (to_uchar (*str)))
m4_warn (0, me, _("leading whitespace ignored"));
else if (errno == ERANGE)
@@ -101,16 +118,16 @@ arg_double (const call_info *me, const char *str)
}
#define ARG_INT(i, argc, argv) \
- ((argc <= ++i) ? 0 : arg_int (me, ARG (i)))
+ ((argc <= ++i) ? 0 : arg_int (me, ARG (i), ARG_LEN (i)))
#define ARG_LONG(i, argc, argv) \
- ((argc <= ++i) ? 0L : arg_long (me, ARG (i)))
+ ((argc <= ++i) ? 0L : arg_long (me, ARG (i), ARG_LEN (i)))
#define ARG_STR(i, argc, argv) \
- ((argc <= ++i) ? "" : ARG (i))
+ ((argc <= ++i) ? "" : arg_string (me, ARG (i), ARG_LEN (i)))
#define ARG_DOUBLE(i, argc, argv) \
- ((argc <= ++i) ? 0.0 : arg_double (me, ARG (i)))
+ ((argc <= ++i) ? 0.0 : arg_double (me, ARG (i), ARG_LEN (i)))
/*------------------------------------------------------------------.
diff --git a/src/freeze.c b/src/freeze.c
index 5d4ac423..75e112b6 100644
--- a/src/freeze.c
+++ b/src/freeze.c
@@ -1,7 +1,7 @@
/* GNU m4 -- A simple macro processor
- Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007, 2008,
+ 2009 Free Software Foundation, Inc.
This file is part of GNU M4.
@@ -343,8 +343,13 @@ reload_frozen_state (const char *name)
case 'F':
- /* Enter a macro having a builtin function as a definition. */
-
+ /* Enter a macro having a builtin function as a
+ definition. No builtin contains NUL in the name. */
+ if (strlen (string[1]) < number[1])
+ m4_error (EXIT_FAILURE, 0, NULL, _("\
+ill-formed frozen file, invalid builtin %s encountered"),
+ quotearg_style_mem (locale_quoting_style, string[1],
+ number[1]));
bp = find_builtin_by_name (string[1]);
define_builtin (string[0], number[0], bp, SYMBOL_PUSHDEF);
break;
diff --git a/src/m4.c b/src/m4.c
index 6b59a8a4..23a42093 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -370,7 +370,8 @@ process_file (const char *name)
FILE *fp = m4_path_search (name, &full_name);
if (fp == NULL)
{
- error (0, errno, "%s", name);
+ error (0, errno, "cannot open %s",
+ quotearg_style (locale_quoting_style, name));
/* Set the status to EXIT_FAILURE, even though we
continue to process files after a missing file. */
retcode = EXIT_FAILURE;
@@ -530,10 +531,11 @@ main (int argc, char *const *argv, char *const *envp)
#endif
case 'd':
- debug_level = debug_decode (optarg);
+ debug_level = debug_decode (optarg, SIZE_MAX);
if (debug_level < 0)
{
- error (0, 0, "bad debug flags: `%s'", optarg);
+ error (0, 0, "bad debug flags: %s",
+ quotearg_style (locale_quoting_style, optarg));
debug_level = 0;
}
break;
@@ -584,7 +586,8 @@ main (int argc, char *const *argv, char *const *envp)
/* Do the basic initializations. */
if (debugfile && !debug_set_output (NULL, debugfile))
- m4_error (0, errno, NULL, _("cannot set debug file `%s'"), debugfile);
+ m4_error (0, errno, NULL, _("cannot set debug file %s"),
+ quotearg_style (locale_quoting_style, debugfile));
input_init ();
output_init ();
@@ -602,7 +605,7 @@ main (int argc, char *const *argv, char *const *envp)
if (interactive)
{
signal (SIGINT, SIG_IGN);
- setbuf (stdout, (char *) NULL);
+ setbuf (stdout, NULL);
}
/* Handle deferred command line macro definitions. Must come after
diff --git a/src/m4.h b/src/m4.h
index 173eecf0..1e6e7dca 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -199,7 +199,7 @@ extern FILE *debug;
#define DEBUG_TRACE_DEFAULT 0x007
void debug_init (void);
-int debug_decode (const char *);
+int debug_decode (const char *, size_t);
void debug_flush_files (void);
bool debug_set_output (const call_info *, const char *);
void debug_message (const char *, ...) M4_GNUC_PRINTF (1, 2);
diff --git a/src/path.c b/src/path.c
index 998c0ed9..75c3bf4d 100644
--- a/src/path.c
+++ b/src/path.c
@@ -160,7 +160,9 @@ m4_path_search (const char *file, char **result)
if (fp != NULL)
{
if (debug_level & DEBUG_TRACE_PATH)
- debug_message ("path search for `%s' found `%s'", file, name);
+ debug_message ("path search for %s found %s",
+ quotearg_style (locale_quoting_style, file),
+ quotearg_n_style (1, locale_quoting_style, name));
if (set_cloexec_flag (fileno (fp), true) != 0)
m4_warn (errno, NULL, _("cannot protect input file across forks"));
if (result)