summaryrefslogtreecommitdiff
path: root/sprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'sprintf.c')
-rw-r--r--sprintf.c54
1 files changed, 31 insertions, 23 deletions
diff --git a/sprintf.c b/sprintf.c
index cb266a9841..b91d758957 100644
--- a/sprintf.c
+++ b/sprintf.c
@@ -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);\
@@ -440,8 +452,8 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)
{
VALUE val = GETARG();
VALUE tmp;
- unsigned int c;
- int n;
+ unsigned int c = 0;
+ int n, encidx = 0;
tmp = rb_check_string_type(val);
if (!NIL_P(tmp)) {
@@ -451,11 +463,13 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)
goto format_s1;
}
n = NUM2INT(val);
- if (n >= 0) n = rb_enc_codelen((c = n), enc);
+ if (n >= 0) {
+ n = rb_enc_codelen((c = n), enc);
+ encidx = rb_ascii8bit_appendable_encoding_index(enc, c);
+ }
if (n <= 0) {
rb_raise(rb_eArgError, "invalid character");
}
- int encidx = rb_ascii8bit_appendable_encoding_index(enc, c);
if (encidx >= 0 && encidx != rb_enc_to_index(enc)) {
/* special case */
rb_enc_associate_index(result, encidx);
@@ -467,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;
@@ -516,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;
@@ -830,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);
}