[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
improved error messages
From: |
Eric Blake |
Subject: |
improved error messages |
Date: |
Thu, 22 Nov 2007 20:44:24 -0700 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071031 Thunderbird/2.0.0.9 Mnenhy/0.7.5.666 |
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
A lot of error messages include the macro name, and some even make the
enclosing macro name optional (such as detecting end of file in a string).
However, blindly printing a macro name to a tty can corrupt terminal
state, if the user has used changeword/changesyntax, or is using indir, to
include non-printing characters in the macro name. So this patch factors
out the macro name into the m4_warn function, so that a future patch can
use the gnulib quotearg module to protect strange macro names in one place
(other things also need help from quotearg, but one step at a time...).
The branch has the bigger impact, but even head is impacted.
2007-11-22 Eric Blake <address@hidden>
More error messages tied to macro names.
* src/input.c (set_word_regexp): Take additional parameter.
(input_init): Adjust caller.
* src/debug.c (debug_set_file, debug_set_output): Take additional
parameter.
(debug_init): Adjust caller.
(expansion_level): Move declaration...
* src/m4.h (expansion_level): ...here.
(debug_set_output, set_word_regexp): Adjust prototypes.
* src/builtin.c (m4_changeword, m4_m4exit, m4_debugfile): Adjust
callers.
* src/m4.c (main): Likewise.
Refactor error messages to avoid macros.
* src/m4.h (_): Define, as a placeholder for now.
(M4ERROR, M4ERROR_AT_LINE): Delete.
(m4_error, m4_error_at_line): Change prototype.
(m4_warn, m4_warn_at_line): New prototypes.
* src/m4.c (m4_verror_at_line): New helper function.
(m4_error, m4_error_at_line): Use new function, and properly call
va_end.
(m4_warn, m4_warn_at_line): New functions.
(stackovf_handler, main): All callers changed.
* src/builtin.c: Likewise.
* src/debug.c: Likewise.
* src/eval.c: Likewise.
* src/format.c: Likewise.
* src/freeze.c: Likewise.
* src/input.c: Likewise.
* src/macro.c: Likewise.
* doc/m4.texinfo (Indir, Builtin, Dumpdef, Incr, Eval, Substr)
(Improved forloop): Adjust tests accordingly.
- --
Don't work too hard, make some time for fun as well!
Eric Blake address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFHRkyX84KuGfSFAYARAlc1AJ4n4Mn7kizMBo7IVL6aW9VB9P4e9gCgm5Ct
uRBDpuy4zsZMo4teL/WxxXY=
=mZY6
-----END PGP SIGNATURE-----
>From 910837ec453663d0423f73eb79c17740486450a0 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 22 Nov 2007 14:13:49 -0700
Subject: [PATCH] Refactor error messages to avoid macros.
* src/m4.h (_): Define, as a placeholder for now.
(M4ERROR, M4ERROR_AT_LINE): Delete.
(m4_error, m4_error_at_line): Change prototype.
(m4_warn, m4_warn_at_line): New prototypes.
* src/m4.c (m4_verror_at_line): New helper function.
(m4_error, m4_error_at_line): Use new function, and properly call
va_end.
(m4_warn, m4_warn_at_line): New functions.
(stackovf_handler, main): All callers changed.
* src/builtin.c: Likewise.
* src/debug.c: Likewise.
* src/eval.c: Likewise.
* src/format.c: Likewise.
* src/freeze.c: Likewise.
* src/input.c: Likewise.
* src/macro.c: Likewise.
* doc/m4.texinfo (Indir, Builtin, Dumpdef, Incr, Eval, Substr)
(Improved forloop): Adjust tests accordingly.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 20 ++++++++
doc/m4.texinfo | 40 ++++++++--------
src/builtin.c | 135 ++++++++++++++++++++-----------------------------------
src/debug.c | 17 +++-----
src/eval.c | 30 ++++--------
src/format.c | 6 +--
src/freeze.c | 35 ++++++++-------
src/input.c | 26 ++++-------
src/m4.c | 132 ++++++++++++++++++++++++++++++++++++++++++++----------
src/m4.h | 16 ++++---
src/macro.c | 13 +++---
src/output.c | 54 ++++++++++++-----------
src/path.c | 6 +--
13 files changed, 289 insertions(+), 241 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 4d8ec23..2c2cd8c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,25 @@
2007-11-22 Eric Blake <address@hidden>
+ Refactor error messages to avoid macros.
+ * src/m4.h (_): Define, as a placeholder for now.
+ (M4ERROR, M4ERROR_AT_LINE): Delete.
+ (m4_error, m4_error_at_line): Change prototype.
+ (m4_warn, m4_warn_at_line): New prototypes.
+ * src/m4.c (m4_verror_at_line): New helper function.
+ (m4_error, m4_error_at_line): Use new function, and properly call
+ va_end.
+ (m4_warn, m4_warn_at_line): New functions.
+ (stackovf_handler, main): All callers changed.
+ * src/builtin.c: Likewise.
+ * src/debug.c: Likewise.
+ * src/eval.c: Likewise.
+ * src/format.c: Likewise.
+ * src/freeze.c: Likewise.
+ * src/input.c: Likewise.
+ * src/macro.c: Likewise.
+ * doc/m4.texinfo (Indir, Builtin, Dumpdef, Incr, Eval, Substr)
+ (Improved forloop): Adjust tests accordingly.
+
Security fix: avoid arbitrary code execution with 'm4 -F'.
* src/freeze.c (produce_frozen_state): Never pass raw file name as
printf format.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 6ae09f7..3cc3539 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -2367,7 +2367,7 @@ f(define(`f', `2'))
indir(`f', define(`f', `3'))
@result{}3
indir(`f', undefine(`f'))
address@hidden:stdin:4: indir: undefined macro `f'
address@hidden:stdin:4: Warning: indir: undefined macro `f'
@result{}
@end example
@@ -2389,7 +2389,7 @@ indir(`define', `foo', defn(`divnum'))
foo
@result{}0
indir(`divert', defn(`foo'))
address@hidden:stdin:5: divert: empty string treated as 0
address@hidden:stdin:5: Warning: divert: empty string treated as 0
@result{}
@end example
@@ -2452,10 +2452,10 @@ $ @kbd{m4 -P}
m4_builtin(`divnum')
@result{}0
m4_builtin(`m4_divnum')
address@hidden:stdin:2: m4_builtin: undefined builtin `m4_divnum'
address@hidden:stdin:2: Warning: m4_builtin: undefined builtin `m4_divnum'
@result{}
m4_indir(`divnum')
address@hidden:stdin:3: m4_indir: undefined macro `divnum'
address@hidden:stdin:3: Warning: m4_indir: undefined macro `divnum'
@result{}
m4_indir(`m4_divnum')
@result{}0
@@ -2469,13 +2469,13 @@ recognized; but it will provoke a warning, and result
in a void expansion.
builtin
@result{}builtin
builtin()
address@hidden:stdin:2: builtin: undefined builtin `'
address@hidden:stdin:2: Warning: builtin: undefined builtin `'
@result{}
builtin(`builtin')
@error{}m4:stdin:3: Warning: builtin: too few arguments: 0 < 1
@result{}
builtin(`builtin',)
address@hidden:stdin:4: builtin: undefined builtin `'
address@hidden:stdin:4: Warning: builtin: undefined builtin `'
@result{}
@end example
@@ -3133,7 +3133,7 @@ f(popdef(`f')dumpdef(`f'))
@error{}f:@tabchar{}``$0'1'
@result{}f2
f(popdef(`f')dumpdef(`f'))
address@hidden:stdin:3: dumpdef: undefined macro `f'
address@hidden:stdin:3: Warning: dumpdef: undefined macro `f'
@result{}f1
@end example
@@ -3231,7 +3231,7 @@ undefine(`foo')
ifdef(`foo', `yes', `no')
@result{}no
indir(`foo')
address@hidden:stdin:8: indir: undefined macro `foo'
address@hidden:stdin:8: Warning: indir: undefined macro `foo'
@result{}
define(`foo', `blah')
@result{}
@@ -4920,7 +4920,7 @@ substr(`abc')
@error{}m4:stdin:1: Warning: substr: too few arguments: 1 < 2
@result{}abc
substr(`abc',)
address@hidden:stdin:2: substr: empty string treated as 0
address@hidden:stdin:2: Warning: substr: empty string treated as 0
@result{}abc
@end example
@@ -5266,10 +5266,10 @@ incr(`4')
decr(`7')
@result{}6
incr()
address@hidden:stdin:3: incr: empty string treated as 0
address@hidden:stdin:3: Warning: incr: empty string treated as 0
@result{}1
decr()
address@hidden:stdin:4: decr: empty string treated as 0
address@hidden:stdin:4: Warning: decr: empty string treated as 0
@result{}-1
@end example
@@ -5388,12 +5388,12 @@ eval(`+ + - ~ ! ~ 0')
eval(`2 || 1 / 0')
@result{}1
eval(`0 || 1 / 0')
address@hidden:stdin:9: eval: divide by zero: 0 || 1 / 0
address@hidden:stdin:9: Warning: eval: divide by zero: 0 || 1 / 0
@result{}
eval(`0 && 1 % 0')
@result{}0
eval(`2 && 1 % 0')
address@hidden:stdin:11: eval: modulo by zero: 2 && 1 % 0
address@hidden:stdin:11: Warning: eval: modulo by zero: 2 && 1 % 0
@result{}
@end example
@@ -5414,9 +5414,9 @@ eval(`2 ** 0')
@result{}1
eval(`0 ** 0')
@result{}
address@hidden:stdin:5: eval: divide by zero: 0 ** 0
address@hidden:stdin:5: Warning: eval: divide by zero: 0 ** 0
eval(`4 ** -2')
address@hidden:stdin:6: eval: negative exponent: 4 ** -2
address@hidden:stdin:6: Warning: eval: negative exponent: 4 ** -2
@result{}
@end example
@@ -5461,7 +5461,7 @@ square(square(`5')` + 1')
define(`foo', `666')
@result{}
eval(`foo / 6')
address@hidden:stdin:11: eval: bad expression: foo / 6
address@hidden:stdin:11: Warning: eval: bad expression: foo / 6
@result{}
eval(foo / 6)
@result{}111
@@ -5529,13 +5529,13 @@ eval(`10', `', `0')
eval(`10', `16')
@result{}a
eval(`1', `37')
address@hidden:stdin:9: eval: radix 37 out of range
address@hidden:stdin:9: Warning: eval: radix 37 out of range
@result{}
eval(`1', , `-1')
address@hidden:stdin:10: eval: negative width
address@hidden:stdin:10: Warning: eval: negative width
@result{}
eval()
address@hidden:stdin:11: eval: empty string treated as 0
address@hidden:stdin:11: Warning: eval: empty string treated as 0
@result{}0
@end example
@@ -6769,7 +6769,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')
address@hidden:stdin:6: eval: bad expression (bad input): (b) >= (a)
address@hidden:stdin:6: Warning: eval: bad expression (bad input): (b) >= (a)
@result{}
@end example
diff --git a/src/builtin.c b/src/builtin.c
index 48df3d6..e10bbde 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -374,11 +374,9 @@ set_macro_sequence (const char *regexp)
msg = re_compile_pattern (regexp, strlen (regexp), ¯o_sequence_buf);
if (msg != NULL)
- {
- M4ERROR ((EXIT_FAILURE, 0,
- "--warn-macro-sequence: bad regular expression `%s': %s",
- regexp, msg));
- }
+ m4_error (EXIT_FAILURE, 0, NULL,
+ _("--warn-macro-sequence: bad regular expression `%s': %s"),
+ regexp, msg);
re_set_registers (¯o_sequence_buf, ¯o_sequence_regs,
macro_sequence_regs.num_regs,
macro_sequence_regs.start, macro_sequence_regs.end);
@@ -439,16 +437,15 @@ define_user_macro (const char *name, const char *text,
symbol_lookup mode)
offset = macro_sequence_regs.end[0];
tmp = defn[offset];
defn[offset] = '\0';
- M4ERROR ((warning_status, 0,
- "Warning: definition of `%s' contains sequence `%s'",
- name, defn + macro_sequence_regs.start[0]));
+ m4_warn (0, NULL, _("definition of `%s' contains sequence `%s'"),
+ name, defn + macro_sequence_regs.start[0]);
defn[offset] = tmp;
}
}
if (offset == -2)
- M4ERROR ((warning_status, 0,
- "error checking --warn-macro-sequence for macro `%s'",
- name));
+ m4_warn (0, NULL,
+ _("problem checking --warn-macro-sequence for macro `%s'"),
+ name);
}
}
@@ -505,16 +502,11 @@ bad_argc (const char *name, int argc, unsigned int min,
unsigned int max)
{
if (argc - 1 < min)
{
- if (!suppress_warnings)
- M4ERROR ((warning_status, 0,
- "Warning: %s: too few arguments: %d < %d",
- name, argc - 1, min));
+ m4_warn (0, name, _("too few arguments: %d < %d"), argc - 1, min);
return true;
}
- if (argc - 1 > max && !suppress_warnings)
- M4ERROR ((warning_status, 0,
- "Warning: %s: extra arguments ignored: %d > %d",
- name, argc - 1, max));
+ if (argc - 1 > max)
+ m4_warn (0, name, _("extra arguments ignored: %d > %d"), argc - 1, max);
return false;
}
@@ -532,7 +524,7 @@ numeric_arg (const char *name, const char *arg, int *valuep)
if (*arg == '\0')
{
*valuep = 0;
- M4ERROR ((warning_status, 0, "%s: empty string treated as 0", name));
+ m4_warn (0, name, _("empty string treated as 0"));
}
else
{
@@ -540,16 +532,13 @@ numeric_arg (const char *name, const char *arg, int
*valuep)
*valuep = strtol (arg, &endp, 10);
if (*endp != '\0')
{
- M4ERROR ((warning_status, 0,
- "%s: non-numeric argument `%s'", name, arg));
+ m4_warn (0, name, _("non-numeric argument `%s'"), arg);
return false;
}
if (isspace (to_uchar (*arg)))
- M4ERROR ((warning_status, 0,
- "%s: leading whitespace ignored", name));
+ m4_warn (0, name, _("leading whitespace ignored"));
else if (errno == ERANGE)
- M4ERROR ((warning_status, 0,
- "%s: numeric overflow detected", name));
+ m4_warn (0, name, _("numeric overflow detected"));
}
return true;
}
@@ -664,8 +653,7 @@ define_macro (int argc, token_data **argv, symbol_lookup
mode)
if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
{
- M4ERROR ((warning_status, 0,
- "Warning: %s: invalid macro name ignored", me));
+ m4_warn (0, me, _("invalid macro name ignored"));
return;
}
@@ -864,8 +852,7 @@ m4_dumpdef (struct obstack *obs, int argc, token_data
**argv)
if (s != NULL && SYMBOL_TYPE (s) != TOKEN_VOID)
dump_symbol (s, &data);
else
- M4ERROR ((warning_status, 0,
- "%s: undefined macro `%s'", me, ARG (i)));
+ m4_warn (0, me, _("undefined macro `%s'"), ARG (i));
}
}
@@ -925,16 +912,14 @@ m4_builtin (struct obstack *obs, int argc, token_data
**argv)
return;
if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
{
- M4ERROR ((warning_status, 0,
- "Warning: %s: invalid macro name ignored", me));
+ m4_warn (0, me, _("invalid macro name ignored"));
return;
}
name = ARG (1);
bp = find_builtin_by_name (name);
if (bp->func == m4_placeholder)
- M4ERROR ((warning_status, 0,
- "%s: undefined builtin `%s'", me, name));
+ m4_warn (0, me, _("undefined builtin `%s'"), name);
else
{
int i;
@@ -967,16 +952,14 @@ m4_indir (struct obstack *obs, int argc, token_data
**argv)
return;
if (TOKEN_DATA_TYPE (argv[1]) != TOKEN_TEXT)
{
- M4ERROR ((warning_status, 0,
- "Warning: %s: invalid macro name ignored", me));
+ m4_warn (0, me, _("invalid macro name ignored"));
return;
}
name = ARG (1);
s = lookup_symbol (name, SYMBOL_LOOKUP);
if (s == NULL || SYMBOL_TYPE (s) == TOKEN_VOID)
- M4ERROR ((warning_status, 0,
- "%s: undefined macro `%s'", me, name));
+ m4_warn (0, me, _("undefined macro `%s'"), name);
else
{
int i;
@@ -1025,12 +1008,11 @@ m4_defn (struct obstack *obs, int argc, token_data
**argv)
case TOKEN_FUNC:
b = SYMBOL_FUNC (s);
if (b == m4_placeholder)
- M4ERROR ((warning_status, 0, "\
-Warning: %s: builtin `%s' requested by frozen file not found", me, ARG (i)));
+ m4_warn (0, me,
+ _("builtin `%s' requested by frozen file not found"),
+ ARG (i));
else if (argc != 2)
- M4ERROR ((warning_status, 0,
- "Warning: %s: cannot concatenate builtin `%s'",
- me, ARG (i)));
+ m4_warn (0, me, _("cannot concatenate builtin `%s'"), ARG (i));
else
push_macro (b);
break;
@@ -1122,8 +1104,7 @@ m4_esyscmd (struct obstack *obs, int argc, token_data
**argv)
pin = popen (ARG (1), "r");
if (pin == NULL)
{
- M4ERROR ((warning_status, errno,
- "%s: cannot open pipe to command `%s'", me, ARG (1)));
+ m4_warn (errno, me, _("cannot open pipe to command `%s'"), ARG (1));
sysval = -1;
}
else
@@ -1164,8 +1145,7 @@ m4_eval (struct obstack *obs, int argc, token_data **argv)
if (radix < 1 || radix > (int) strlen (digits))
{
- M4ERROR ((warning_status, 0,
- "%s: radix %d out of range", me, radix));
+ m4_warn (0, me, _("radix %d out of range"), radix);
return;
}
@@ -1173,13 +1153,12 @@ m4_eval (struct obstack *obs, int argc, token_data
**argv)
return;
if (min < 0)
{
- M4ERROR ((warning_status, 0, "%s: negative width", me));
+ m4_warn (0, me, _("negative width"));
return;
}
if (!*ARG (1))
- M4ERROR ((warning_status, 0,
- "%s: empty string treated as 0", me));
+ m4_warn (0, me, _("empty string treated as 0"));
else if (evaluate (me, ARG (1), &value))
return;
@@ -1300,8 +1279,7 @@ m4_undivert (struct obstack *obs, int argc, token_data
**argv)
if (*endp == '\0' && !isspace (to_uchar (*str)))
insert_diversion (file);
else if (no_gnu_extensions)
- M4ERROR ((warning_status, 0,
- "%s: non-numeric argument `%s'", me, str));
+ m4_warn (0, me, _("non-numeric argument `%s'"), str);
else
{
fp = m4_path_search (str, NULL);
@@ -1309,12 +1287,10 @@ m4_undivert (struct obstack *obs, int argc, token_data
**argv)
{
insert_file (fp);
if (fclose (fp) == EOF)
- M4ERROR ((warning_status, errno,
- "%s: error undiverting `%s'", me, str));
+ m4_warn (errno, me, _("error undiverting `%s'"), str);
}
else
- M4ERROR ((warning_status, errno,
- "%s: cannot undivert `%s'", me, str));
+ m4_warn (errno, me, _("cannot undivert `%s'"), str);
}
}
}
@@ -1420,11 +1396,7 @@ include (int argc, token_data **argv, bool silent)
if (fp == NULL)
{
if (!silent)
- {
- M4ERROR ((warning_status, errno, "%s: cannot open `%s'",
- me, ARG (1)));
- retcode = EXIT_FAILURE;
- }
+ m4_error (0, errno, me, _("cannot open `%s'"), ARG (1));
return;
}
@@ -1483,7 +1455,7 @@ mkstemp_helper (struct obstack *obs, const char *me,
const char *name)
fd = mkstemp ((char *) obstack_base (obs));
if (fd < 0)
{
- M4ERROR ((0, errno, "%s: cannot create tempfile `%s'", me, name));
+ m4_warn (errno, me, _("cannot create tempfile `%s'"), name);
obstack_free (obs, obstack_finish (obs));
}
else
@@ -1515,7 +1487,7 @@ m4_maketemp (struct obstack *obs, int argc, token_data
**argv)
int i;
int len2;
- M4ERROR ((warning_status, 0, "%s: recommend using mkstemp instead", me));
+ m4_warn (0, me, _("recommend using mkstemp instead"));
for (i = len; i > 1; i--)
if (str[i - 1] != 'X')
break;
@@ -1607,8 +1579,7 @@ m4_m4exit (struct obstack *obs, int argc, token_data
**argv)
exit_code = EXIT_FAILURE;
if (exit_code < 0 || exit_code > 255)
{
- M4ERROR ((warning_status, 0,
- "%s: exit status out of range: `%d'", me, exit_code));
+ m4_warn (0, me, _("exit status out of range: %d"), exit_code);
exit_code = EXIT_FAILURE;
}
/* Change debug stream back to stderr, to force flushing debug stream and
@@ -1730,8 +1701,7 @@ m4_debugmode (struct obstack *obs, int argc, token_data
**argv)
}
if (new_debug_level < 0)
- M4ERROR ((warning_status, 0,
- "%s: bad debug flags: `%s'", me, str));
+ m4_warn (0, me, _("bad debug flags: `%s'"), str);
else
{
switch (change_flag)
@@ -1767,8 +1737,7 @@ m4_debugfile (struct obstack *obs, int argc, token_data
**argv)
if (argc == 1)
debug_set_output (NULL);
else if (!debug_set_output (ARG (1)))
- M4ERROR ((warning_status, errno,
- "%s: cannot set error file: `%s'", me, ARG (1)));
+ m4_warn (errno, me, _("cannot set error file: `%s'"), ARG (1));
}
/* This section contains text processing macros: "len", "index",
@@ -2020,8 +1989,8 @@ substitute (struct obstack *obs, const char *me, const
char *victim,
case '0':
if (!substitute_warned)
{
- M4ERROR ((warning_status, 0, "\
-Warning: %s: \\0 will disappear, use \\& instead in replacements", me));
+ m4_warn (0, me, _("\
+\\0 will disappear, use \\& instead in replacements"));
substitute_warned = 1;
}
/* Fall through. */
@@ -2036,16 +2005,14 @@ Warning: %s: \\0 will disappear, use \\& instead in
replacements", me));
case '7': case '8': case '9':
ch -= '0';
if (!regs || regs->num_regs - 1 <= ch)
- M4ERROR ((warning_status, 0,
- "Warning: %s: sub-expression %d not present", me, ch));
+ m4_warn (0, me, _("sub-expression %d not present"), ch);
else if (regs->end[ch] > 0)
obstack_grow (obs, victim + regs->start[ch],
regs->end[ch] - regs->start[ch]);
break;
case '\0':
- M4ERROR ((warning_status, 0,
- "Warning: %s: trailing \\ ignored in replacement", me));
+ m4_warn (0, me, _("trailing \\ ignored in replacement"));
return;
default:
@@ -2125,8 +2092,7 @@ m4_regexp (struct obstack *obs, int argc, token_data
**argv)
msg = compile_pattern (regexp, strlen (regexp), &buf, ®s);
if (msg != NULL)
{
- M4ERROR ((warning_status, 0,
- "%s: bad regular expression: `%s': %s", me, regexp, msg));
+ m4_warn (0, me, _("bad regular expression: `%s': %s"), regexp, msg);
return;
}
@@ -2136,8 +2102,7 @@ m4_regexp (struct obstack *obs, int argc, token_data
**argv)
argc == 3 ? NULL : regs);
if (startpos == -2)
- M4ERROR ((warning_status, 0,
- "%s: error matching regular expression `%s'", me, regexp));
+ m4_warn (0, me, _("problem matching regular expression `%s'"), regexp);
else if (argc == 3)
shipout_int (obs, startpos);
else if (startpos >= 0)
@@ -2195,8 +2160,7 @@ m4_patsubst (struct obstack *obs, int argc, token_data
**argv)
msg = compile_pattern (regexp, strlen (regexp), &buf, ®s);
if (msg != NULL)
{
- M4ERROR ((warning_status, 0,
- "%s: bad regular expression `%s': %s", me, regexp, msg));
+ m4_warn (0, me, _("bad regular expression `%s': %s"), regexp, msg);
return;
}
@@ -2216,9 +2180,8 @@ m4_patsubst (struct obstack *obs, int argc, token_data
**argv)
copied verbatim. */
if (matchpos == -2)
- M4ERROR ((warning_status, 0,
- "%s: error matching regular expression `%s'",
- me, regexp));
+ m4_warn (0, me, _("problem matching regular expression `%s'"),
+ regexp);
else if (offset < length)
obstack_grow (obs, victim + offset, length - offset);
break;
@@ -2262,8 +2225,8 @@ m4_patsubst (struct obstack *obs, int argc, token_data
**argv)
void
m4_placeholder (struct obstack *obs, int argc, token_data **argv)
{
- M4ERROR ((warning_status, 0, "\
-builtin `%s' requested by frozen file not found", ARG (0)));
+ m4_warn (0, NULL, _("builtin `%s' requested by frozen file not found"),
+ ARG (0));
}
/*-------------------------------------------------------------------------.
diff --git a/src/debug.c b/src/debug.c
index 998ccb9..4173f9b 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -134,10 +134,8 @@ debug_set_file (FILE *fp)
if (debug != NULL && debug != stderr && debug != stdout
&& close_stream (debug) != 0)
- {
- M4ERROR ((warning_status, errno, "error writing to debug stream"));
- retcode = EXIT_FAILURE;
- }
+ /* FIXME - report on behalf of macro caller. */
+ m4_error (0, errno, NULL, _("error writing to debug stream"));
debug = fp;
if (debug != NULL && debug != stdout)
@@ -154,11 +152,8 @@ debug_set_file (FILE *fp)
&& stdout_stat.st_ino != 0)
{
if (debug != stderr && close_stream (debug) != 0)
- {
- M4ERROR ((warning_status, errno,
- "error writing to debug stream"));
- retcode = EXIT_FAILURE;
- }
+ /* FIXME - report on behalf of macro caller. */
+ m4_error (0, errno, NULL, _("error writing to debug stream"));
debug = stdout;
}
}
@@ -217,8 +212,8 @@ debug_set_output (const char *name)
return false;
if (set_cloexec_flag (fileno (fp), true) != 0)
- M4ERROR ((warning_status, errno,
- "Warning: cannot protect debug file across forks"));
+ /* FIXME - report on behalf of macro caller. */
+ m4_warn (errno, NULL, _("cannot protect debug file across forks"));
debug_set_file (fp);
}
return true;
diff --git a/src/eval.c b/src/eval.c
index 1af596e..fdb50b7 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -310,45 +310,36 @@ evaluate (const char *me, const char *expr, int32_t *val)
break;
case MISSING_RIGHT:
- M4ERROR ((warning_status, 0,
- "%s: bad expression (missing right parenthesis): %s",
- me, expr));
+ m4_warn (0, me, _("bad expression (missing right parenthesis): %s"),
+ expr);
break;
case SYNTAX_ERROR:
- M4ERROR ((warning_status, 0,
- "%s: bad expression: %s", me, expr));
+ m4_warn (0, me, _("bad expression: %s"), expr);
break;
case UNKNOWN_INPUT:
- M4ERROR ((warning_status, 0,
- "%s: bad expression (bad input): %s", me, expr));
+ m4_warn (0, me, _("bad expression (bad input): %s"), expr);
break;
case EXCESS_INPUT:
- M4ERROR ((warning_status, 0,
- "%s: bad expression (excess input): %s", me, expr));
+ m4_warn (0, me, _("bad expression (excess input): %s"), expr);
break;
case INVALID_OPERATOR:
- M4ERROR ((warning_status, 0,
- "%s: invalid operator: %s", me, expr));
- retcode = EXIT_FAILURE;
+ m4_error (0, 0, me, _("invalid operator: %s"), expr);
break;
case DIVIDE_ZERO:
- M4ERROR ((warning_status, 0,
- "%s: divide by zero: %s", me, expr));
+ m4_warn (0, me, _("divide by zero: %s"), expr);
break;
case MODULO_ZERO:
- M4ERROR ((warning_status, 0,
- "%s: modulo by zero: %s", me, expr));
+ m4_warn (0, me, _("modulo by zero: %s"), expr);
break;
case NEGATIVE_EXPONENT:
- M4ERROR ((warning_status, 0,
- "%s: negative exponent: %s", me, expr));
+ m4_warn (0, me, _("negative exponent: %s"), expr);
break;
default:
@@ -530,8 +521,7 @@ equality_term (const char *me, eval_token et, int32_t *v1)
if (op == ASSIGN)
{
- M4ERROR ((warning_status, 0, "\
-Warning: %s: recommend ==, not =, for equality", me));
+ m4_warn (0, me, _("recommend ==, not =, for equality"));
op = EQ;
}
*v1 = (op == EQ) == (*v1 == v2);
diff --git a/src/format.c b/src/format.c
index a9e7150..96ac562 100644
--- a/src/format.c
+++ b/src/format.c
@@ -233,8 +233,7 @@ format (struct obstack *obs, int argc, token_data **argv)
c = *fmt++;
if (c > sizeof ok || !ok[c])
{
- M4ERROR ((warning_status, 0,
- "Warning: %s: unrecognized specifier in `%s'", me, f));
+ m4_warn (0, me, _("unrecognized specifier in `%s'"), f);
if (c == '\0')
fmt--;
continue;
@@ -308,8 +307,7 @@ format (struct obstack *obs, int argc, token_data **argv)
Issue a warning, then proceed. */
if (str == NULL)
{
- M4ERROR ((warning_status, 0,
- "Warning: %s: unable to format output for `%s'", me, f));
+ m4_warn (0, me, _("unable to format output for `%s'"), f);
continue;
}
diff --git a/src/freeze.c b/src/freeze.c
index df68f3a..16a4ed2 100644
--- a/src/freeze.c
+++ b/src/freeze.c
@@ -56,9 +56,10 @@ produce_frozen_state (const char *name)
symbol *sym;
const builtin *bp;
- if (file = fopen (name, O_BINARY ? "wb" : "w"), !file)
+ file = fopen (name, O_BINARY ? "wb" : "w");
+ if (!file)
{
- M4ERROR ((warning_status, errno, "%s", name));
+ m4_error (0, errno, NULL, _("cannot open %s"), name);
return;
}
@@ -151,7 +152,7 @@ produce_frozen_state (const char *name)
fputs ("# End of frozen state file\n", file);
if (close_stream (file) != 0)
- M4ERROR ((EXIT_FAILURE, errno, "unable to create frozen state"));
+ m4_error (EXIT_FAILURE, errno, NULL, _("unable to create frozen state"));
}
/*----------------------------------------------------------------------.
@@ -162,10 +163,10 @@ static void
issue_expect_message (int expected)
{
if (expected == '\n')
- M4ERROR ((EXIT_FAILURE, 0, "expecting line feed in frozen file"));
+ m4_error (EXIT_FAILURE, 0, NULL, _("expecting line feed in frozen file"));
else
- M4ERROR ((EXIT_FAILURE, 0, "expecting character `%c' in frozen file",
- expected));
+ m4_error (EXIT_FAILURE, 0, NULL,
+ _("expecting character `%c' in frozen file"), expected);
}
/*-------------------------------------------------.
@@ -226,7 +227,7 @@ reload_frozen_state (const char *name)
file = m4_path_search (name, NULL);
if (file == NULL)
- M4ERROR ((EXIT_FAILURE, errno, "cannot open %s", name));
+ m4_error (EXIT_FAILURE, errno, NULL, _("cannot open %s"), name);
allocated[0] = 100;
string[0] = xcharalloc ((size_t) allocated[0]);
@@ -239,12 +240,12 @@ reload_frozen_state (const char *name)
GET_CHARACTER;
GET_NUMBER (number[0]);
if (number[0] > 1)
- M4ERROR ((EXIT_MISMATCH, 0,
- "frozen file version %d greater than max supported of 1",
- number[0]));
+ m4_error (EXIT_MISMATCH, 0, NULL,
+ _("frozen file version %d greater than max supported of 1"),
+ number[0]);
else if (number[0] < 1)
- M4ERROR ((EXIT_FAILURE, 0,
- "ill-formed frozen file, version directive expected"));
+ m4_error (EXIT_FAILURE, 0, NULL,
+ _("ill-formed frozen file, version directive expected"));
VALIDATE ('\n');
GET_DIRECTIVE;
@@ -253,7 +254,7 @@ reload_frozen_state (const char *name)
switch (character)
{
default:
- M4ERROR ((EXIT_FAILURE, 0, "ill-formed frozen file"));
+ m4_error (EXIT_FAILURE, 0, NULL, _("ill-formed frozen file"));
case 'C':
case 'D':
@@ -292,7 +293,8 @@ reload_frozen_state (const char *name)
if (number[0] > 0)
if (!fread (string[0], (size_t) number[0], 1, file))
- M4ERROR ((EXIT_FAILURE, 0, "premature end of frozen file"));
+ m4_error (EXIT_FAILURE, 0, NULL,
+ _("premature end of frozen file"));
string[0][number[0]] = '\0';
}
@@ -308,7 +310,8 @@ reload_frozen_state (const char *name)
if (number[1] > 0)
if (!fread (string[1], (size_t) number[1], 1, file))
- M4ERROR ((EXIT_FAILURE, 0, "premature end of frozen file"));
+ m4_error (EXIT_FAILURE, 0, NULL,
+ _("premature end of frozen file"));
string[1][number[1]] = '\0';
GET_CHARACTER;
@@ -372,7 +375,7 @@ reload_frozen_state (const char *name)
free (string[1]);
errno = 0;
if (ferror (file) || fclose (file) != 0)
- M4ERROR ((EXIT_FAILURE, errno, "unable to read frozen state"));
+ m4_error (EXIT_FAILURE, errno, NULL, _("unable to read frozen state"));
#undef GET_CHARACTER
#undef GET_DIRECTIVE
diff --git a/src/input.c b/src/input.c
index 58f24be..156df33 100644
--- a/src/input.c
+++ b/src/input.c
@@ -354,16 +354,12 @@ pop_input (bool cleanup)
if (ferror (isp->u.u_f.fp))
{
- M4ERROR ((warning_status, 0, "read error"));
+ m4_error (0, 0, NULL, _("read error"));
if (isp->u.u_f.close)
fclose (isp->u.u_f.fp);
- retcode = EXIT_FAILURE;
}
else if (isp->u.u_f.close && fclose (isp->u.u_f.fp) == EOF)
- {
- M4ERROR ((warning_status, errno, "error reading file"));
- retcode = EXIT_FAILURE;
- }
+ m4_error (0, errno, NULL, _("error reading file"));
start_of_input_line = isp->u.u_f.advance;
output_current_line = -1;
break;
@@ -575,8 +571,8 @@ skip_line (const char *name)
if (ch == CHAR_EOF)
/* current_file changed to "" if we see CHAR_EOF, use the
previous value we stored earlier. */
- M4ERROR_AT_LINE ((warning_status, 0, file, line,
- "Warning: %s: end of file treated as newline", name));
+ m4_warn_at_line (0, file, line, name,
+ _("end of file treated as newline"));
/* On the rare occasion that dnl crosses include file boundaries
(either the input file did not end in a newline, or changeword
was used), calling next_char can update current_file and
@@ -776,8 +772,8 @@ set_word_regexp (const char *regexp)
if (msg != NULL)
{
- M4ERROR ((warning_status, 0,
- "bad regular expression `%s': %s", regexp, msg));
+ /* FIXME - report on behalf of macro caller. */
+ m4_warn (0, NULL, _("bad regular expression `%s': %s"), regexp, msg);
return;
}
@@ -874,9 +870,8 @@ next_token (token_data *td, int *line, const char *caller)
else
/* current_file changed to "" if we see CHAR_EOF, use the
previous value we stored earlier. */
- M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, *line,
- "%s%send of file in comment",
- caller ? caller : "", caller ? ": " : ""));
+ m4_error_at_line (EXIT_FAILURE, 0, file, *line, caller,
+ _("end of file in comment"));
type = TOKEN_STRING;
}
@@ -958,9 +953,8 @@ next_token (token_data *td, int *line, const char *caller)
if (ch == CHAR_EOF)
/* current_file changed to "" if we see CHAR_EOF, use
the previous value we stored earlier. */
- M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, *line,
- "%s%send of file in string",
- caller ? caller : "", caller ? ": " : ""));
+ m4_error_at_line (EXIT_FAILURE, 0, file, *line, caller,
+ _("end of file in string"));
if (MATCH (ch, rquote.string, true))
{
diff --git a/src/m4.c b/src/m4.c
index 38e26e9..de9abc0 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -24,6 +24,7 @@
#include <getopt.h>
#include <limits.h>
#include <signal.h>
+#include <stdarg.h>
#include "version-etc.h"
@@ -83,34 +84,115 @@ typedef struct macro_definition macro_definition;
/* Error handling functions. */
-/*-----------------------.
-| Wrapper around error. |
-`-----------------------*/
+/*------------------------------------------------------------------.
+| Helper for all the error reporting, as a wrapper around |
+| error_at_line. Report error message based on FORMAT and ARGS, on |
+| behalf of MACRO, at the location FILE and LINE (but with no |
+| location if LINE is 0). If ERRNUM, decode the errno value that |
+| caused the error. If STATUS, exit immediately with that status. |
+| If WARN, prepend 'Warning: '. |
+`------------------------------------------------------------------*/
+
+static void
+m4_verror_at_line (bool warn, int status, int errnum, const char *file,
+ int line, const char *macro, const char *format,
+ va_list args)
+{
+ char *full = NULL;
+ /* Prepend warning and the macro name, as needed. But if that fails
+ for non-memory reasons (unlikely), then still use the original
+ format. */
+ if (warn && macro)
+ full = xasprintf (_("Warning: %s: %s"), macro, format);
+ else if (warn)
+ full = xasprintf (_("Warning: %s"), format);
+ else if (macro)
+ full = xasprintf (_("%s: %s"), macro, format);
+ verror_at_line (status, errnum, line ? file : NULL, line,
+ full ? full : format, args);
+ free (full);
+ if ((!warn || fatal_warnings) && !retcode)
+ retcode = EXIT_FAILURE;
+}
+
+/*----------------------------------------------------------------.
+| Wrapper around error. Report error message based on FORMAT and |
+| subsequent args, on behalf of MACRO, and the current input line |
+| (if any). If ERRNUM, decode the errno value that caused the |
+| error. If STATUS, exit immediately with that status. |
+`----------------------------------------------------------------*/
void
-m4_error (int status, int errnum, const char *format, ...)
+m4_error (int status, int errnum, const char *macro, const char *format, ...)
{
va_list args;
va_start (args, format);
- verror_at_line (status, errnum, current_line ? current_file : NULL,
- current_line, format, args);
- if (fatal_warnings && ! retcode)
- retcode = EXIT_FAILURE;
+ if (status == EXIT_SUCCESS && warning_status)
+ status = EXIT_FAILURE;
+ m4_verror_at_line (false, status, errnum, current_file, current_line,
+ macro, format, args);
+ va_end (args);
}
-/*-------------------------------.
-| Wrapper around error_at_line. |
-`-------------------------------*/
+/*----------------------------------------------------------------.
+| Wrapper around error_at_line. Report error message based on |
+| FORMAT and subsequent args, on behalf of MACRO, at the location |
+| FILE and LINE (but with no location if LINE is 0). If ERRNUM, |
+| decode the errno value that caused the error. If STATUS, exit |
+| immediately with that status. |
+`----------------------------------------------------------------*/
void
m4_error_at_line (int status, int errnum, const char *file, int line,
- const char *format, ...)
+ const char *macro, const char *format, ...)
{
va_list args;
va_start (args, format);
- verror_at_line (status, errnum, line ? file : NULL, line, format, args);
- if (fatal_warnings && ! retcode)
- retcode = EXIT_FAILURE;
+ if (status == EXIT_SUCCESS && warning_status)
+ status = EXIT_FAILURE;
+ m4_verror_at_line (false, status, errnum, file, line, macro, format, args);
+ va_end (args);
+}
+
+/*------------------------------------------------------------------.
+| Wrapper around error. Report warning message based on FORMAT and |
+| subsequent args, on behalf of MACRO, and the current input line |
+| (if any). If ERRNUM, decode the errno value that caused the |
+| warning. |
+`------------------------------------------------------------------*/
+
+void
+m4_warn (int errnum, const char *macro, const char *format, ...)
+{
+ va_list args;
+ if (!suppress_warnings)
+ {
+ va_start (args, format);
+ m4_verror_at_line (true, warning_status, errnum, current_file,
+ current_line, macro, format, args);
+ va_end (args);
+ }
+}
+
+/*----------------------------------------------------------------.
+| Wrapper around error_at_line. Report warning message based on |
+| FORMAT and subsequent args, on behalf of MACRO, at the location |
+| FILE and LINE (but with no location if LINE is 0). If ERRNUM, |
+| decode the errno value that caused the warning. |
+`----------------------------------------------------------------*/
+
+void
+m4_warn_at_line (int errnum, const char *file, int line, const char *macro,
+ const char *format, ...)
+{
+ va_list args;
+ if (!suppress_warnings)
+ {
+ va_start (args, format);
+ m4_verror_at_line (true, warning_status, errnum, file, line, macro,
+ format, args);
+ va_end (args);
+ }
}
#ifdef USE_STACKOVF
@@ -122,8 +204,8 @@ m4_error_at_line (int status, int errnum, const char *file,
int line,
static void
stackovf_handler (void)
{
- M4ERROR ((EXIT_FAILURE, 0,
- "ERROR: stack overflow. (Infinite define recursion?)"));
+ m4_error (EXIT_FAILURE, 0, NULL,
+ _("ERROR: stack overflow. (Infinite define recursion?)"));
}
#endif /* USE_STACKOV */
@@ -406,7 +488,7 @@ main (int argc, char *const *argv, char *const *envp)
break;
case 'E':
- if (! fatal_warnings)
+ if (!fatal_warnings)
fatal_warnings = true;
else
warning_status = EXIT_FAILURE;
@@ -485,11 +567,11 @@ main (int argc, char *const *argv, char *const *envp)
break;
case WARN_MACRO_SEQUENCE_OPTION:
- /* Don't call set_macro_sequence here, as it can exit.
- --warn-macro-sequence sets optarg to NULL (which uses the
- default regexp); --warn-macro-sequence= sets optarg to ""
- (which disables these warnings). */
- macro_sequence = optarg;
+ /* Don't call set_macro_sequence here, as it can exit.
+ --warn-macro-sequence sets optarg to NULL (which uses the
+ default regexp); --warn-macro-sequence= sets optarg to ""
+ (which disables these warnings). */
+ macro_sequence = optarg;
break;
case VERSION_OPTION:
@@ -506,7 +588,7 @@ main (int argc, char *const *argv, char *const *envp)
/* Do the basic initializations. */
if (debugfile && !debug_set_output (debugfile))
- M4ERROR ((0, errno, "cannot set debug file `%s'", debugfile));
+ m4_error (0, errno, NULL, _("cannot set debug file `%s'"), debugfile);
input_init ();
output_init ();
@@ -564,7 +646,7 @@ main (int argc, char *const *argv, char *const *envp)
case '\1':
seen_file = true;
- process_file (defines->arg);
+ process_file (defines->arg);
break;
default:
diff --git a/src/m4.h b/src/m4.h
index c372ffd..d1fe1ae 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -69,6 +69,10 @@
/* Used for version mismatch, when -R detects a frozen file it can't parse. */
#define EXIT_MISMATCH 63
+
+/* M4 1.4.x is not yet internationalized. But when it is, this can be
+ redefined as gettext(). */
+#define _(STRING) STRING
/* Various declarations. */
@@ -128,12 +132,12 @@ extern const char *user_word_regexp; /* -W */
extern int retcode;
extern const char *program_name;
-void m4_error (int, int, const char *, ...) M4_GNUC_PRINTF(3, 4);
-void m4_error_at_line (int, int, const char *, int,
- const char *, ...) M4_GNUC_PRINTF(5, 6);
-
-#define M4ERROR(Arglist) (m4_error Arglist)
-#define M4ERROR_AT_LINE(Arglist) (m4_error_at_line Arglist)
+void m4_error (int, int, const char *, const char *, ...) M4_GNUC_PRINTF(4, 5);
+void m4_error_at_line (int, int, const char *, int, const char *,
+ const char *, ...) M4_GNUC_PRINTF(6, 7);
+void m4_warn (int, const char *, const char *, ...) M4_GNUC_PRINTF(3, 4);
+void m4_warn_at_line (int, const char *, int, const char *,
+ const char *, ...) M4_GNUC_PRINTF(5, 6);
#ifdef USE_STACKOVF
void setup_stackovf_trap (char *const *, char *const *,
diff --git a/src/macro.c b/src/macro.c
index 6781cd9..8a678d4 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -134,8 +134,7 @@ warn_builtin_concat (const char *caller, builtin_func *func)
{
const builtin *bp = find_builtin_by_addr (func);
assert (bp);
- M4ERROR ((warning_status, 0, "Warning: %s: cannot concatenate builtin `%s'",
- caller, bp->name));
+ m4_warn (0, caller, _("cannot concatenate builtin `%s'"), bp->name);
}
/*-------------------------------------------------------------------.
@@ -202,8 +201,8 @@ expand_argument (struct obstack *obs, token_data *argp,
const char *caller)
case TOKEN_EOF:
/* current_file changed to "" if we see TOKEN_EOF, use the
previous value we stored earlier. */
- M4ERROR_AT_LINE ((EXIT_FAILURE, 0, file, line,
- "%s: end of file in argument list", caller));
+ m4_error_at_line (EXIT_FAILURE, 0, file, line, caller,
+ _("end of file in argument list"));
break;
case TOKEN_WORD:
@@ -342,9 +341,9 @@ expand_macro (symbol *sym)
SYMBOL_PENDING_EXPANSIONS (sym)++;
expansion_level++;
if (nesting_limit > 0 && expansion_level > nesting_limit)
- M4ERROR ((EXIT_FAILURE, 0,
- "recursion limit of %d exceeded, use -L<N> to change it",
- nesting_limit));
+ m4_error (EXIT_FAILURE, 0, NULL,
+ _("recursion limit of %d exceeded, use -L<N> to change it"),
+ nesting_limit);
macro_call_id++;
my_call_id = macro_call_id;
diff --git a/src/output.c b/src/output.c
index 5873d8c..478d3b2 100644
--- a/src/output.c
+++ b/src/output.c
@@ -169,8 +169,8 @@ cleanup_tmpfile (void)
if (!diversion->size && diversion->u.file
&& close_stream_temp (diversion->u.file) != 0)
{
- M4ERROR ((0, errno,
- "cannot clean temporary file for diversion"));
+ m4_warn (errno, NULL,
+ _("cannot clean temporary file for diversion"));
fail = true;
}
}
@@ -198,8 +198,8 @@ m4_tmpname (int divnum)
tail = strrchr (buffer, '-') + 1;
}
if (sprintf (tail, "%d", divnum) < 0)
- M4ERROR ((EXIT_FAILURE, errno,
- "cannot create temporary file for diversion"));
+ m4_error (EXIT_FAILURE, errno, NULL,
+ _("cannot create temporary file for diversion"));
return buffer;
}
@@ -219,8 +219,8 @@ m4_tmpfile (int divnum)
{
output_temp_dir = create_temp_dir ("m4-", NULL, true);
if (output_temp_dir == NULL)
- M4ERROR ((EXIT_FAILURE, errno,
- "cannot create temporary file for diversion"));
+ m4_error (EXIT_FAILURE, errno, NULL,
+ _("cannot create temporary file for diversion"));
atexit (cleanup_tmpfile);
}
name = m4_tmpname (divnum);
@@ -229,12 +229,11 @@ m4_tmpfile (int divnum)
if (file == NULL)
{
unregister_temp_file (output_temp_dir, name);
- M4ERROR ((EXIT_FAILURE, errno,
- "cannot create temporary file for diversion"));
+ m4_error (EXIT_FAILURE, errno, NULL,
+ _("cannot create temporary file for diversion"));
}
else if (set_cloexec_flag (fileno (file), true) != 0)
- M4ERROR ((warning_status, errno,
- "Warning: cannot protect diversion across forks"));
+ m4_warn (errno, NULL, _("cannot protect diversion across forks"));
return file;
}
@@ -249,16 +248,15 @@ m4_tmpopen (int divnum)
file = fopen_temp (name, O_BINARY ? "ab+" : "a+");
if (file == NULL)
- M4ERROR ((EXIT_FAILURE, errno,
- "cannot create temporary file for diversion"));
+ m4_error (EXIT_FAILURE, errno, NULL,
+ _("cannot create temporary file for diversion"));
else if (set_cloexec_flag (fileno (file), true) != 0)
- M4ERROR ((warning_status, errno,
- "Warning: cannot protect diversion across forks"));
+ m4_warn (errno, NULL, _("cannot protect diversion across forks"));
/* POSIX states that it is undefined whether an append stream starts
at offset 0 or at the end. We want the beginning. */
else if (fseeko (file, 0, SEEK_SET) != 0)
- M4ERROR ((EXIT_FAILURE, errno,
- "cannot seek to beginning of diversion"));
+ m4_error (EXIT_FAILURE, errno, NULL,
+ _("cannot seek to beginning of diversion"));
return file;
}
@@ -351,8 +349,8 @@ make_room_for (int length)
count = fwrite (selected_buffer, (size_t) selected_diversion->used,
1, selected_diversion->u.file);
if (count != 1)
- M4ERROR ((EXIT_FAILURE, errno,
- "ERROR: cannot flush diversion to temporary file"));
+ m4_error (EXIT_FAILURE, errno, NULL,
+ _("cannot flush diversion to temporary file"));
}
/* Reclaim the buffer space for other diversions. */
@@ -379,7 +377,8 @@ make_room_for (int length)
FILE *file = selected_diversion->u.file;
selected_diversion->u.file = NULL;
if (m4_tmpclose (file) != 0)
- M4ERROR ((0, errno, "cannot close temporary file for diversion"));
+ m4_warn (errno, NULL,
+ _("cannot close temporary file for diversion"));
}
/* The current buffer may be safely reallocated. */
@@ -441,7 +440,7 @@ output_text (const char *text, int length)
{
count = fwrite (text, length, 1, output_file);
if (count != 1)
- M4ERROR ((EXIT_FAILURE, errno, "ERROR: copying inserted file"));
+ m4_error (EXIT_FAILURE, errno, NULL, _("error copying inserted file"));
}
else
{
@@ -605,7 +604,8 @@ make_diversion (int divnum)
FILE *file = output_diversion->u.file;
output_diversion->u.file = NULL;
if (m4_tmpclose (file) != 0)
- M4ERROR ((0, errno, "cannot close temporary file for diversion"));
+ m4_warn (errno, NULL,
+ _("cannot close temporary file for diversion"));
}
output_diversion = NULL;
output_file = NULL;
@@ -689,7 +689,7 @@ insert_file (FILE *file)
{
length = fread (buffer, 1, COPY_BUFFER_SIZE, file);
if (ferror (file))
- M4ERROR ((EXIT_FAILURE, errno, "ERROR: reading inserted file"));
+ m4_error (EXIT_FAILURE, errno, NULL, _("error reading inserted file"));
if (length == 0)
break;
output_text (buffer, length);
@@ -736,10 +736,11 @@ insert_diversion_helper (m4_diversion *diversion)
diversion->u.file = NULL;
diversion->used = 0;
if (m4_tmpclose (file) != 0)
- M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
+ m4_warn (errno, NULL,
+ _("cannot clean temporary file for diversion"));
}
if (m4_tmpremove (diversion->divnum) != 0)
- M4ERROR ((0, errno, "cannot clean temporary file for diversion"));
+ m4_warn (errno, NULL, _("cannot clean temporary file for diversion"));
}
gl_oset_remove (diversion_table, diversion);
diversion->u.next = free_list;
@@ -819,10 +820,11 @@ freeze_diversions (FILE *file)
struct stat file_stat;
diversion->u.file = m4_tmpopen (diversion->divnum);
if (fstat (fileno (diversion->u.file), &file_stat) < 0)
- M4ERROR ((EXIT_FAILURE, errno, "cannot stat diversion"));
+ m4_error (EXIT_FAILURE, errno, NULL,
+ _("cannot stat diversion"));
if (file_stat.st_size < 0
|| file_stat.st_size != (unsigned long int) file_stat.st_size)
- M4ERROR ((EXIT_FAILURE, 0, "diversion too large"));
+ m4_error (EXIT_FAILURE, 0, NULL, _("diversion too large"));
xfprintf (file, "D%d,%lu\n", diversion->divnum,
(unsigned long int) file_stat.st_size);
}
diff --git a/src/path.c b/src/path.c
index 27ac4cc..98d4567 100644
--- a/src/path.c
+++ b/src/path.c
@@ -133,8 +133,7 @@ m4_path_search (const char *file, char **result)
if (fp != NULL)
{
if (set_cloexec_flag (fileno (fp), true) != 0)
- M4ERROR ((warning_status, errno,
- "Warning: cannot protect input file across forks"));
+ m4_warn (errno, NULL, _("cannot protect input file across forks"));
if (result)
*result = xstrdup (file);
return fp;
@@ -163,8 +162,7 @@ m4_path_search (const char *file, char **result)
if (debug_level & DEBUG_TRACE_PATH)
DEBUG_MESSAGE2 ("path search for `%s' found `%s'", file, name);
if (set_cloexec_flag (fileno (fp), true) != 0)
- M4ERROR ((warning_status, errno,
- "Warning: cannot protect input file across forks"));
+ m4_warn (errno, NULL, _("cannot protect input file across forks"));
if (result)
*result = name;
else
--
1.5.3.5
>From 9de0b8950ca83762363605805c40f8f8614acbc8 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 22 Nov 2007 19:54:32 -0700
Subject: [PATCH] More error messages tied to macro names.
* src/input.c (set_word_regexp): Take additional parameter.
(input_init): Adjust caller.
* src/debug.c (debug_set_file, debug_set_output): Take additional
parameter.
(debug_init): Adjust caller.
(expansion_level): Move declaration...
* src/m4.h (expansion_level): ...here.
(debug_set_output, set_word_regexp): Adjust prototypes.
* src/builtin.c (m4_changeword, m4_m4exit, m4_debugfile): Adjust
callers.
* src/m4.c (main): Likewise.
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 13 +++++++++++++
src/builtin.c | 15 +++++++--------
src/debug.c | 36 ++++++++++++++++--------------------
src/input.c | 6 +++---
src/m4.c | 4 ++--
src/m4.h | 6 ++++--
6 files changed, 45 insertions(+), 35 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 2c2cd8c..9bbf726 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2007-11-22 Eric Blake <address@hidden>
+ More error messages tied to macro names.
+ * src/input.c (set_word_regexp): Take additional parameter.
+ (input_init): Adjust caller.
+ * src/debug.c (debug_set_file, debug_set_output): Take additional
+ parameter.
+ (debug_init): Adjust caller.
+ (expansion_level): Move declaration...
+ * src/m4.h (expansion_level): ...here.
+ (debug_set_output, set_word_regexp): Adjust prototypes.
+ * src/builtin.c (m4_changeword, m4_m4exit, m4_debugfile): Adjust
+ callers.
+ * src/m4.c (main): Likewise.
+
Refactor error messages to avoid macros.
* src/m4.h (_): Define, as a placeholder for now.
(M4ERROR, M4ERROR_AT_LINE): Delete.
diff --git a/src/builtin.c b/src/builtin.c
index e10bbde..cc4e469 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -24,8 +24,6 @@
#include "m4.h"
-extern FILE *popen ();
-
#include "regex.h"
#if HAVE_SYS_WAIT_H
@@ -1365,10 +1363,11 @@ m4_changecom (struct obstack *obs, int argc, token_data
**argv)
static void
m4_changeword (struct obstack *obs, int argc, token_data **argv)
{
- if (bad_argc (ARG (0), argc, 1, 1))
- return;
+ const char *me = ARG (0);
- set_word_regexp (ARG (1));
+ if (bad_argc (me, argc, 1, 1))
+ return;
+ set_word_regexp (me, ARG (1));
}
#endif /* ENABLE_CHANGEWORD */
@@ -1584,7 +1583,7 @@ m4_m4exit (struct obstack *obs, int argc, token_data
**argv)
}
/* Change debug stream back to stderr, to force flushing debug stream and
detect any errors it might have encountered. */
- debug_set_output (NULL);
+ debug_set_output (me, NULL);
debug_flush_files ();
if (exit_code == EXIT_SUCCESS && retcode != EXIT_SUCCESS)
exit_code = retcode;
@@ -1735,8 +1734,8 @@ m4_debugfile (struct obstack *obs, int argc, token_data
**argv)
bad_argc (me, argc, 0, 1);
if (argc == 1)
- debug_set_output (NULL);
- else if (!debug_set_output (ARG (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));
}
diff --git a/src/debug.c b/src/debug.c
index 4173f9b..c22a482 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -30,9 +30,7 @@ FILE *debug = NULL;
/* Obstack for trace messages. */
static struct obstack trace;
-extern int expansion_level;
-
-static void debug_set_file (FILE *);
+static void debug_set_file (const char *, FILE *);
/*----------------------------------.
| Initialise the debugging module. |
@@ -41,7 +39,7 @@ static void debug_set_file (FILE *);
void
debug_init (void)
{
- debug_set_file (stderr);
+ debug_set_file (NULL, stderr);
obstack_init (&trace);
}
@@ -128,14 +126,13 @@ debug_decode (const char *opts)
`------------------------------------------------------------------------*/
static void
-debug_set_file (FILE *fp)
+debug_set_file (const char *caller, FILE *fp)
{
struct stat stdout_stat, debug_stat;
if (debug != NULL && debug != stderr && debug != stdout
&& close_stream (debug) != 0)
- /* FIXME - report on behalf of macro caller. */
- m4_error (0, errno, NULL, _("error writing to debug stream"));
+ m4_error (0, errno, caller, _("error writing to debug stream"));
debug = fp;
if (debug != NULL && debug != stdout)
@@ -152,8 +149,7 @@ debug_set_file (FILE *fp)
&& stdout_stat.st_ino != 0)
{
if (debug != stderr && close_stream (debug) != 0)
- /* FIXME - report on behalf of macro caller. */
- m4_error (0, errno, NULL, _("error writing to debug stream"));
+ m4_error (0, errno, caller, _("error writing to debug stream"));
debug = stdout;
}
}
@@ -190,21 +186,22 @@ debug_flush_files (void)
}
}
-/*-------------------------------------------------------------------------.
-| Change the debug output to file NAME. If NAME is NULL, debug output is |
-| reverted to stderr, and if empty debug output is discarded. Return true |
-| iff the output stream was changed. |
-`-------------------------------------------------------------------------*/
+/*-------------------------------------------------------------------.
+| Change the debug output to file NAME. If NAME is NULL, debug |
+| output is reverted to stderr, and if empty, debug output is |
+| discarded. Return true iff the output stream was changed. Report |
+| errors on behalf of CALLER. |
+`-------------------------------------------------------------------*/
bool
-debug_set_output (const char *name)
+debug_set_output (const char *caller, const char *name)
{
FILE *fp;
if (name == NULL)
- debug_set_file (stderr);
+ debug_set_file (caller, stderr);
else if (*name == '\0')
- debug_set_file (NULL);
+ debug_set_file (caller, NULL);
else
{
fp = fopen (name, "a");
@@ -212,9 +209,8 @@ debug_set_output (const char *name)
return false;
if (set_cloexec_flag (fileno (fp), true) != 0)
- /* FIXME - report on behalf of macro caller. */
- m4_warn (errno, NULL, _("cannot protect debug file across forks"));
- debug_set_file (fp);
+ m4_warn (errno, caller, _("cannot protect debug file across forks"));
+ debug_set_file (caller, fp);
}
return true;
}
diff --git a/src/input.c b/src/input.c
index 156df33..3d96ec7 100644
--- a/src/input.c
+++ b/src/input.c
@@ -687,7 +687,7 @@ input_init (void)
ecomm.length = strlen (ecomm.string);
#ifdef ENABLE_CHANGEWORD
- set_word_regexp (user_word_regexp);
+ set_word_regexp (NULL, user_word_regexp);
#endif
}
@@ -752,7 +752,7 @@ set_comment (const char *bc, const char *ec)
#ifdef ENABLE_CHANGEWORD
void
-set_word_regexp (const char *regexp)
+set_word_regexp (const char *caller, const char *regexp)
{
int i;
char test[2];
@@ -773,7 +773,7 @@ set_word_regexp (const char *regexp)
if (msg != NULL)
{
/* FIXME - report on behalf of macro caller. */
- m4_warn (0, NULL, _("bad regular expression `%s': %s"), regexp, msg);
+ m4_warn (0, caller, _("bad regular expression `%s': %s"), regexp, msg);
return;
}
diff --git a/src/m4.c b/src/m4.c
index de9abc0..217d389 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -587,7 +587,7 @@ main (int argc, char *const *argv, char *const *envp)
defines = head;
/* Do the basic initializations. */
- if (debugfile && !debug_set_output (debugfile))
+ if (debugfile && !debug_set_output (NULL, debugfile))
m4_error (0, errno, NULL, _("cannot set debug file `%s'"), debugfile);
input_init ();
@@ -676,7 +676,7 @@ main (int argc, char *const *argv, char *const *envp)
/* Change debug stream back to stderr, to force flushing the debug
stream and detect any errors it might have encountered. The
three standard streams are closed by close_stdin. */
- debug_set_output (NULL);
+ debug_set_output (NULL, NULL);
if (frozen_file_to_write)
produce_frozen_state (frozen_file_to_write);
diff --git a/src/m4.h b/src/m4.h
index d1fe1ae..4f1fa1f 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -231,7 +231,7 @@ extern FILE *debug;
void debug_init (void);
int debug_decode (const char *);
void debug_flush_files (void);
-bool debug_set_output (const char *);
+bool debug_set_output (const char *, const char *);
void debug_message_prefix (void);
void trace_prepre (const char *, int);
@@ -318,7 +318,7 @@ extern STRING lquote, rquote;
void set_quotes (const char *, const char *);
void set_comment (const char *, const char *);
#ifdef ENABLE_CHANGEWORD
-void set_word_regexp (const char *);
+void set_word_regexp (const char *, const char *);
#endif
/* File: output.c --- output functions. */
@@ -388,6 +388,8 @@ void hack_all_symbols (hack_symbol *, void *);
/* File: macro.c --- macro expansion. */
+extern int expansion_level;
+
void expand_input (void);
void call_macro (symbol *, int, token_data **, struct obstack *);
--
1.5.3.5
- improved error messages,
Eric Blake <=