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