From 743f2bf879bf1f49d0c26867827b5f1db050f315 Mon Sep 17 00:00:00 2001 From: nobu Date: Thu, 24 Mar 2016 08:44:03 +0000 Subject: [PATCH] strftime.c: fix FMTV * strftime.c (FMT_PADDING): extract format for padding. * strftime.c (FMT_PRECISION): extract precision formula. * strftime.c (FMTV): append formatted string to expand the result. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54246 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 8 ++++++++ strftime.c | 45 +++++++++++++++++++++++++----------------- test/ruby/test_time.rb | 3 +++ 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index f91c97267d..58cdbc2a06 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Thu Mar 24 17:44:02 2016 Nobuyoshi Nakada + + * strftime.c (FMT_PADDING): extract format for padding. + + * strftime.c (FMT_PRECISION): extract precision formula. + + * strftime.c (FMTV): append formatted string to expand the result. + Thu Mar 24 14:20:21 2016 Nobuyoshi Nakada * strftime.c (STRFTIME): deal with case conversion flags for diff --git a/strftime.c b/strftime.c index 6502ec6f8f..f7f3714c33 100644 --- a/strftime.c +++ b/strftime.c @@ -195,6 +195,17 @@ case_conv(char *s, ptrdiff_t i, int flags) return s; } +static VALUE +format_value(const char *fmt, VALUE val, int precision) +{ + struct RString fmtv; + VALUE str = rb_setup_fake_str(&fmtv, fmt, strlen(fmt), 0); + VALUE args[2]; + args[0] = INT2FIX(precision); + args[1] = val; + return rb_str_format(2, args, str); +} + /* * enc is the encoding of the format. It is used as the encoding of resulted * string, but the name of the month and weekday are always US-ASCII. So it @@ -267,15 +278,20 @@ rb_strftime_with_timespec(VALUE ftime, const char *format, size_t format_len, NEEDS(i); \ } \ } while (0); +#define FMT_PADDING(fmt, def_pad) \ + (&"%*"fmt"\0""%0*"fmt[\ + (padding == '0' || (!padding && (def_pad) == '0')) ? \ + rb_strlen_lit("%*"fmt)+1 : 0]) +#define FMT_PRECISION(def_prec) \ + ((flags & BIT_OF(LEFT)) ? (precision = 1) : \ + (precision <= 0) ? (precision = (def_prec)) : (precision)) #define FMT(def_pad, def_prec, fmt, val) \ do { \ - if (precision <= 0) precision = (def_prec); \ - if (flags & BIT_OF(LEFT)) precision = 1; \ + precision = FMT_PRECISION(def_prec); \ len = s - start; \ NEEDS(precision); \ rb_str_set_len(ftime, len); \ - rb_str_catf(ftime, \ - ((padding == '0' || (!padding && (def_pad) == '0')) ? "%0*"fmt : "%*"fmt), \ + rb_str_catf(ftime, FMT_PADDING(fmt, def_pad), \ precision, (val)); \ RSTRING_GETMEM(ftime, s, len); \ endp = (start = s) + rb_str_capacity(ftime); \ @@ -307,20 +323,13 @@ rb_strftime_with_timespec(VALUE ftime, const char *format, size_t format_len, FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \ } \ else { \ - VALUE args[2], result; \ - size_t l; \ - if (precision <= 0) precision = (def_prec); \ - if (flags & BIT_OF(LEFT)) precision = 1; \ - args[0] = INT2FIX(precision); \ - args[1] = (val); \ - if (padding == '0' || (!padding && (def_pad) == '0')) \ - result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \ - else \ - result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \ - l = strlcpy(s, StringValueCStr(result), endp-s); \ - if ((size_t)(endp-s) <= l) \ - goto err; \ - s += l; \ + const char *fmts = FMT_PADDING(fmt, def_pad); \ + precision = FMT_PRECISION(def_prec); \ + tmp = format_value(fmts, tmp, precision); \ + rb_str_append(ftime, tmp); \ + RSTRING_GETMEM(ftime, s, len); \ + endp = (start = s) + rb_str_capacity(ftime); \ + s += len; \ } \ } while (0) diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb index 24545b216c..bf38374f62 100644 --- a/test/ruby/test_time.rb +++ b/test/ruby/test_time.rb @@ -756,6 +756,9 @@ class TestTime < Test::Unit::TestCase t = Time.utc(-1,1,4) assert_equal("-0001", t.strftime("%Y")) assert_equal("-0001", t.strftime("%G")) + + t = Time.utc(10000000000000000000000,1,1) + assert_equal("10000000000000000000000", t.strftime("%Y")) end def test_strftime_weeknum