diff options
author | Eric Blake <ebb9@byu.net> | 2008-12-02 22:51:14 -0700 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2008-12-02 22:51:14 -0700 |
commit | 41d0c77062c8046730101d82b56f682edc70957e (patch) | |
tree | c4f887b503240ede7246dd10c2dfba838189ed8b /modules/format.c | |
parent | c6628fa51d6c7756f38d1dfaa2055656446ee93a (diff) | |
download | m4-41d0c77062c8046730101d82b56f682edc70957e.tar.gz |
Stage 27: Allow embedded NUL in text processing macros.
* modules/m4.c (m4_expand_ranges): Don't append extra bytes.
(translit): Manage NUL bytes.
* modules/format.c (format): Likewise.
* modules/gnu.c (substitute, regexp_substitute): Likewise.
(m4_resyntax_encode_safe): Add parameter.
(regexp, patsubst, renamesyms): Update callers.
(regexp_compile): Adjust error message.
* modules/evalparse.c (m4_evaluate): Use consistent message.
(end_text): New variable.
(eval_init_lex): Add parameter.
(eval_lex): Detect embedded NUL.
* src/freeze.c (reload_frozen_state): Likewise.
* doc/m4.texinfo (Format): Update to cover new behavior.
(Eval): Mention that result is unquoted.
* tests/freeze.at (reloading nul): Enhance test.
* tests/null.m4: Likewise.
* tests/null.err: Update expected output.
* tests/null.out: Likewise.
* tests/options.at (--regexp-syntax): Likewise.
Signed-off-by: Eric Blake <ebb9@byu.net>
Diffstat (limited to 'modules/format.c')
-rw-r--r-- | modules/format.c | 43 |
1 files changed, 27 insertions, 16 deletions
diff --git a/modules/format.c b/modules/format.c index e2a1a423..af983cdc 100644 --- a/modules/format.c +++ b/modules/format.c @@ -123,11 +123,12 @@ format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) { const m4_call_info *me = m4_arg_info (argv); 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. */ @@ -156,25 +157,24 @@ format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) int result = 0; enum {CHAR, INT, LONG, DOUBLE, STR} datatype; - f = fmt = ARG_STR (i, argc, argv); + f = fmt = M4ARG (1); + f_len = M4ARGLEN (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) - m4_bad_argc (context, argc, me, i, i, true); - return; - } obstack_1grow (obs, c); + continue; } if (*fmt == '%') { obstack_1grow (obs, '%'); fmt++; + f_len--; continue; } @@ -225,7 +225,7 @@ format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) break; } } - while (!(flags & DONE) && fmt++); + while (!(flags & DONE) && (f_len--, fmt++)); if (flags & THOUSANDS) *p++ = '\''; if (flags & PLUS) @@ -247,12 +247,14 @@ format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) { width = ARG_INT (i, argc, argv); fmt++; + f_len--; } else while (isdigit ((unsigned char) *fmt)) { width = 10 * width + *fmt - '0'; fmt++; + f_len--; } /* Maximum precision; an explicit negative precision is the same @@ -263,10 +265,12 @@ format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) if (*fmt == '.') { ok['c'] = 0; + f_len--; if (*(++fmt) == '*') { prec = ARG_INT (i, argc, argv); ++fmt; + f_len--; } else { @@ -275,6 +279,7 @@ format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) { prec = 10 * prec + *fmt - '0'; fmt++; + f_len--; } } } @@ -285,30 +290,34 @@ format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *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 (context, 0, me, _("unrecognized specifier in `%s'"), f); + m4_warn (context, 0, me, _("unrecognized specifier in %s"), + quotearg_style_mem (locale_quoting_style, f, M4ARGLEN (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) @@ -382,4 +391,6 @@ format (m4 *context, m4_obstack *obs, int argc, m4_macro_args *argv) we constructed fstart, the result should not be negative. */ assert (0 <= result); } + if (valid_format) + m4_bad_argc (context, argc, me, i, i, true); } |