diff options
author | Eric Blake <ebb9@byu.net> | 2007-11-22 14:13:49 -0700 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2007-11-22 14:13:49 -0700 |
commit | 910837ec453663d0423f73eb79c17740486450a0 (patch) | |
tree | 78ca321ec29090df39b8f6fe19f9a4fe3dabc4f7 | |
parent | 031a71a80442ed2ad3c2ee14d5811c786a12c51b (diff) | |
download | m4-910837ec453663d0423f73eb79c17740486450a0.tar.gz |
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 <ebb9@byu.net>
-rw-r--r-- | ChangeLog | 20 | ||||
-rw-r--r-- | doc/m4.texinfo | 40 | ||||
-rw-r--r-- | src/builtin.c | 135 | ||||
-rw-r--r-- | src/debug.c | 17 | ||||
-rw-r--r-- | src/eval.c | 30 | ||||
-rw-r--r-- | src/format.c | 6 | ||||
-rw-r--r-- | src/freeze.c | 35 | ||||
-rw-r--r-- | src/input.c | 26 | ||||
-rw-r--r-- | src/m4.c | 132 | ||||
-rw-r--r-- | src/m4.h | 16 | ||||
-rw-r--r-- | src/macro.c | 13 | ||||
-rw-r--r-- | src/output.c | 54 | ||||
-rw-r--r-- | src/path.c | 6 |
13 files changed, 289 insertions, 241 deletions
@@ -1,5 +1,25 @@ 2007-11-22 Eric Blake <ebb9@byu.net> + 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 6ae09f77..3cc3539b 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')) -@error{}m4:stdin:4: indir: undefined macro `f' +@error{}m4: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')) -@error{}m4:stdin:5: divert: empty string treated as 0 +@error{}m4: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') -@error{}m4:stdin:2: m4_builtin: undefined builtin `m4_divnum' +@error{}m4:stdin:2: Warning: m4_builtin: undefined builtin `m4_divnum' @result{} m4_indir(`divnum') -@error{}m4:stdin:3: m4_indir: undefined macro `divnum' +@error{}m4: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() -@error{}m4:stdin:2: builtin: undefined builtin `' +@error{}m4:stdin:2: Warning: builtin: undefined builtin `' @result{} builtin(`builtin') @error{}m4:stdin:3: Warning: builtin: too few arguments: 0 < 1 @result{} builtin(`builtin',) -@error{}m4:stdin:4: builtin: undefined builtin `' +@error{}m4: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')) -@error{}m4:stdin:3: dumpdef: undefined macro `f' +@error{}m4: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') -@error{}m4:stdin:8: indir: undefined macro `foo' +@error{}m4: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',) -@error{}m4:stdin:2: substr: empty string treated as 0 +@error{}m4:stdin:2: Warning: substr: empty string treated as 0 @result{}abc @end example @@ -5266,10 +5266,10 @@ incr(`4') decr(`7') @result{}6 incr() -@error{}m4:stdin:3: incr: empty string treated as 0 +@error{}m4:stdin:3: Warning: incr: empty string treated as 0 @result{}1 decr() -@error{}m4:stdin:4: decr: empty string treated as 0 +@error{}m4: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') -@error{}m4:stdin:9: 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: eval: modulo by zero: 2 && 1 % 0 +@error{}m4: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{} -@error{}m4:stdin:5: eval: divide by zero: 0 ** 0 +@error{}m4:stdin:5: Warning: eval: divide by zero: 0 ** 0 eval(`4 ** -2') -@error{}m4:stdin:6: eval: negative exponent: 4 ** -2 +@error{}m4: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') -@error{}m4:stdin:11: eval: bad expression: foo / 6 +@error{}m4: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') -@error{}m4:stdin:9: eval: radix 37 out of range +@error{}m4:stdin:9: Warning: eval: radix 37 out of range @result{} eval(`1', , `-1') -@error{}m4:stdin:10: eval: negative width +@error{}m4:stdin:10: Warning: eval: negative width @result{} eval() -@error{}m4:stdin:11: eval: empty string treated as 0 +@error{}m4: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') -@error{}m4:stdin:6: eval: bad expression (bad input): (b) >= (a) +@error{}m4:stdin:6: Warning: eval: bad expression (bad input): (b) >= (a) @result{} @end example diff --git a/src/builtin.c b/src/builtin.c index 48df3d62..e10bbde2 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 998ccb9b..4173f9b4 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; @@ -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 a9e71504..96ac5628 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 df68f3ad..16a4ed23 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 58f24beb..156df330 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)) { @@ -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: @@ -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 6781cd97..8a678d49 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 5873d8c4..478d3b28 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); } @@ -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 |