diff options
Diffstat (limited to 'sprintf.c')
| -rw-r--r-- | sprintf.c | 44 |
1 files changed, 25 insertions, 19 deletions
@@ -65,18 +65,30 @@ sign_bits(int base, const char *p) #define FPREC 64 #define FPREC0 128 +static long +expand_result(VALUE result, long bsiz, long blen, long l) +{ + int cr = ENC_CODERANGE(result); + RUBY_ASSERT(bsiz >= blen); + while (l > bsiz - blen) { + bsiz *= 2; + if (bsiz < 0) rb_raise(rb_eArgError, "too big specifier"); + } + rb_str_resize(result, bsiz); + ENC_CODERANGE_SET(result, cr); + return bsiz; +} + #define CHECK(l) do {\ - int cr = ENC_CODERANGE(result);\ - RUBY_ASSERT(bsiz >= blen); \ - while ((l) > bsiz - blen) {\ - bsiz*=2;\ - if (bsiz<0) rb_raise(rb_eArgError, "too big specifier");\ - }\ - rb_str_resize(result, bsiz);\ - ENC_CODERANGE_SET(result, cr);\ + bsiz = expand_result(result, bsiz, blen, l);\ buf = RSTRING_PTR(result);\ } while (0) +#define CHECK_WIDTH(l, w) do { \ + if ((l) > INT_MAX - (w)) rb_raise(rb_eArgError, "width too big");\ + CHECK((l)+(w));\ +} while (0) + #define PUSH(s, l) do { \ CHECK(l);\ PUSH_(s, l);\ @@ -469,19 +481,13 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) rb_enc_mbcput(c, &buf[blen], enc); blen += n; } - else if ((flags & FMINUS)) { - --width; - CHECK(n + (width > 0 ? width : 0)); - rb_enc_mbcput(c, &buf[blen], enc); - blen += n; - if (width > 0) FILL_(' ', width); - } else { --width; - CHECK(n + (width > 0 ? width : 0)); - if (width > 0) FILL_(' ', width); + CHECK_WIDTH(n, (width > 0 ? width : 0)); + if (!(flags & FMINUS) && (width > 0)) FILL_(' ', width); rb_enc_mbcput(c, &buf[blen], enc); blen += n; + if ((flags & FMINUS) && (width > 0)) FILL_(' ', width); } } break; @@ -518,7 +524,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) /* need to adjust multi-byte string pos */ if ((flags&FWIDTH) && (width > slen)) { width -= (int)slen; - CHECK(len + width); + CHECK_WIDTH(len, width); if (!(flags&FMINUS)) { FILL_(' ', width); width = 0; @@ -832,7 +838,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt) if (sign || (flags&FSPACE)) ++len; if (prec > 0) ++len; /* period */ fill = width > len ? width - len : 0; - CHECK(fill + len); + CHECK(fill + len); /* max(width, len) */ if (fill && !(flags&(FMINUS|FZERO))) { FILL_(' ', fill); } |
