1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* ext/date/date_core.c: replacement of implementation of

strftime. It has some limitations that is same as Time's
	  one.  [experimental]
	* ext/date/date_strftime.c: new.
	* ext/date/lib/date/format.c: removed ruby version of strftime.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31135 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
tadf 2011-03-20 12:44:47 +00:00
parent 7bc47c0260
commit 434157444f
6 changed files with 1509 additions and 210 deletions

View file

@ -1,3 +1,11 @@
Sun Mar 20 21:34:49 2011 Tadayoshi Funaba <tadf@dotrb.org>
* ext/date/date_core.c: replacement of implementation of
strftime. It has some limitations that is same as Time's
one. [experimental]
* ext/date/date_strftime.c: new.
* ext/date/lib/date/format.c: removed ruby version of strftime.
Sun Mar 20 12:43:12 2011 Tanaka Akira <akr@fsij.org>
* ext/openssl/ossl_x509store.c: parenthesize macro arguments.

View file

@ -1464,6 +1464,17 @@ d_lite_year(VALUE self)
}
}
static const int yeartab[2][13] = {
{ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
{ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
};
static int
civil_to_yday(int y, int m, int d)
{
return yeartab[leap_p(y) ? 1 : 0][m] + d;
}
/*
* call-seq:
* d.yday
@ -1481,9 +1492,8 @@ d_lite_yday(VALUE self)
if (!light_mode_p(dat))
return iforward0("yday_r");
{
get_d_jd(dat);
jd_to_ordinal(dat->l.jd, dat->l.sg, &ry, &rd);
return INT2FIX(rd);
get_d_civil(dat);
return INT2FIX(civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday));
}
}
@ -2322,6 +2332,158 @@ d_lite_inspect(VALUE self)
}
}
#include <errno.h>
#include "timev.h"
size_t
date_strftime(char *s, size_t maxsize, const char *format,
const struct vtm *vtm, VALUE timev, int gmt);
#define SMALLBUF 100
static size_t
date_strftime_alloc(char **buf, const char *format,
struct vtm *vtm, VALUE timev)
{
size_t size, len, flen;
(*buf)[0] = '\0';
flen = strlen(format);
if (flen == 0) {
return 0;
}
errno = 0;
len = date_strftime(*buf, SMALLBUF, format, vtm, timev, 0);
if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
for (size=1024; ; size*=2) {
*buf = xmalloc(size);
(*buf)[0] = '\0';
len = date_strftime(*buf, size, format, vtm, timev, 0);
/*
* buflen can be zero EITHER because there's not enough
* room in the string, or because the control command
* goes to the empty string. Make a reasonable guess that
* if the buffer is 1024 times bigger than the length of the
* format string, it's not failing for lack of room.
*/
if (len > 0 || size >= 1024 * flen) break;
xfree(*buf);
}
return len;
}
static void
d_lite_set_vtm_and_timev(VALUE self, struct vtm *vtm, VALUE *timev)
{
get_d1(self);
if (!light_mode_p(dat)) {
vtm->year = iforward0("year_r");
vtm->mon = FIX2INT(iforward0("mon_r"));
vtm->mday = FIX2INT(iforward0("mday_r"));
vtm->hour = FIX2INT(iforward0("hour_r"));
vtm->min = FIX2INT(iforward0("min_r"));
vtm->sec = FIX2INT(iforward0("sec_r"));
vtm->subsecx = iforward0("sec_fraction_r");
vtm->utc_offset = INT2FIX(0);
vtm->wday = FIX2INT(iforward0("wday_r"));
vtm->yday = FIX2INT(iforward0("yday_r"));
vtm->isdst = 0;
vtm->zone = RSTRING_PTR(iforward0("zone_r"));
*timev = f_mul(f_sub(dat->r.ajd,
rb_rational_new2(INT2FIX(4881175), INT2FIX(2))),
INT2FIX(86400));
}
else {
get_d_jd(dat);
get_d_civil(dat);
vtm->year = LONG2NUM(dat->l.year);
vtm->mon = dat->l.mon;
vtm->mday = dat->l.mday;
vtm->hour = 0;
vtm->min = 0;
vtm->sec = 0;
vtm->subsecx = INT2FIX(0);
vtm->utc_offset = INT2FIX(0);
vtm->wday = jd_to_wday(dat->l.jd);
vtm->yday = civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday);
vtm->isdst = 0;
vtm->zone = "+00:00";
*timev = f_mul(INT2FIX(dat->l.jd - 2440588),
INT2FIX(86400));
}
}
static VALUE
date_strftime_internal(int argc, VALUE *argv, VALUE self,
const char *default_fmt,
void (*func)(VALUE, struct vtm *, VALUE *))
{
get_d1(self);
{
VALUE vfmt;
const char *fmt;
long len;
char buffer[SMALLBUF], *buf = buffer;
struct vtm vtm;
VALUE timev;
VALUE str;
rb_scan_args(argc, argv, "01", &vfmt);
if (argc < 1)
vfmt = rb_usascii_str_new2(default_fmt);
else {
StringValue(vfmt);
if (!rb_enc_str_asciicompat_p(vfmt)) {
rb_raise(rb_eArgError,
"format should have ASCII compatible encoding");
}
}
fmt = RSTRING_PTR(vfmt);
len = RSTRING_LEN(vfmt);
(*func)(self, &vtm, &timev);
if (memchr(fmt, '\0', len)) {
/* Ruby string may contain \0's. */
const char *p = fmt, *pe = fmt + len;
str = rb_str_new(0, 0);
while (p < pe) {
len = date_strftime_alloc(&buf, p, &vtm, timev);
rb_str_cat(str, buf, len);
p += strlen(p);
if (buf != buffer) {
xfree(buf);
buf = buffer;
}
for (fmt = p; p < pe && !*p; ++p);
if (p > fmt) rb_str_cat(str, fmt, p - fmt);
}
return str;
}
else
len = date_strftime_alloc(&buf, fmt, &vtm, timev);
str = rb_str_new(buf, len);
if (buf != buffer) xfree(buf);
rb_enc_copy(str, vfmt);
return str;
}
}
/*
* call-seq:
* d.strftime([format="%F"])
*
* Return a formatted string.
*/
static VALUE
d_lite_strftime(int argc, VALUE *argv, VALUE self)
{
return date_strftime_internal(argc, argv, self,
"%F", d_lite_set_vtm_and_timev);
}
/*
* call-seq:
* d.marshal_dump
@ -3074,10 +3236,8 @@ dt_lite_yday(VALUE self)
if (!light_mode_p(dat))
return iforward0("yday_r");
{
get_dt_jd(dat);
get_dt_df(dat);
jd_to_ordinal(local_jd(dat), dat->l.sg, &ry, &rd);
return INT2FIX(rd);
get_dt_civil(dat);
return INT2FIX(civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday));
}
}
@ -3806,6 +3966,64 @@ dt_lite_inspect(VALUE self)
}
}
static void
dt_lite_set_vtm_and_timev(VALUE self, struct vtm *vtm, VALUE *timev)
{
get_dt1(self);
if (!light_mode_p(dat)) {
vtm->year = iforward0("year_r");
vtm->mon = FIX2INT(iforward0("mon_r"));
vtm->mday = FIX2INT(iforward0("mday_r"));
vtm->hour = FIX2INT(iforward0("hour_r"));
vtm->min = FIX2INT(iforward0("min_r"));
vtm->sec = FIX2INT(iforward0("sec_r"));
vtm->subsecx = iforward0("sec_fraction_r");
vtm->utc_offset = INT2FIX(0);
vtm->wday = FIX2INT(iforward0("wday_r"));
vtm->yday = FIX2INT(iforward0("yday_r"));
vtm->isdst = 0;
vtm->zone = RSTRING_PTR(iforward0("zone_r"));
*timev = f_mul(f_sub(dat->r.ajd,
rb_rational_new2(INT2FIX(4881175), INT2FIX(2))),
INT2FIX(86400));
}
else {
get_dt_jd(dat);
get_dt_civil(dat);
get_dt_time(dat);
vtm->year = LONG2NUM(dat->l.year);
vtm->mon = dat->l.mon;
vtm->mday = dat->l.mday;
vtm->hour = dat->l.hour;
vtm->min = dat->l.min;
vtm->sec = dat->l.sec;
vtm->subsecx = LONG2NUM(dat->l.sf);
vtm->utc_offset = INT2FIX(dat->l.of);
vtm->wday = jd_to_wday(local_jd(dat));
vtm->yday = civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday);
vtm->isdst = 0;
vtm->zone = RSTRING_PTR(dt_lite_zone(self));
*timev = f_mul(f_sub(dt_lite_ajd(self),
rb_rational_new2(INT2FIX(4881175), INT2FIX(2))),
INT2FIX(86400));
}
}
/*
* call-seq:
* dt.strftime([format="%FT%T%:z"])
*
* Return a formatted string.
*/
static VALUE
dt_lite_strftime(int argc, VALUE *argv, VALUE self)
{
return date_strftime_internal(argc, argv, self,
"%FT%T%:z", dt_lite_set_vtm_and_timev);
}
/*
* call-seq:
* dt.marshal_dump
@ -4214,6 +4432,7 @@ Init_date_core(void)
rb_define_method(cDate, "to_s", d_lite_to_s, 0);
rb_define_method(cDate, "inspect", d_lite_inspect, 0);
rb_define_method(cDate, "strftime", d_lite_strftime, -1);
rb_define_method(cDate, "marshal_dump", d_lite_marshal_dump, 0);
rb_define_method(cDate, "marshal_load", d_lite_marshal_load, 1);
@ -4288,6 +4507,7 @@ Init_date_core(void)
rb_define_method(cDateTime, "to_s", dt_lite_to_s, 0);
rb_define_method(cDateTime, "inspect", dt_lite_inspect, 0);
rb_define_method(cDateTime, "strftime", dt_lite_strftime, -1);
rb_define_method(cDateTime, "marshal_dump", dt_lite_marshal_dump, 0);
rb_define_method(cDateTime, "marshal_load", dt_lite_marshal_load, 1);

1252
ext/date/date_strftime.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -131,208 +131,6 @@ class Date
end
def emit(e, f) # :nodoc:
case e
when Numeric
sign = %w(+ + -)[e <=> 0]
e = e.abs
end
s = e.to_s
if f[:s] && f[:p] == '0'
f[:w] -= 1
end
if f[:s] && f[:p] == "\s"
s[0,0] = sign
end
if f[:p] != '-'
s = s.rjust(f[:w], f[:p])
end
if f[:s] && f[:p] != "\s"
s[0,0] = sign
end
s = s.upcase if f[:u]
s = s.downcase if f[:d]
s
end
def emit_w(e, w, f) # :nodoc:
f[:w] = [f[:w], w].compact.max
emit(e, f)
end
def emit_n(e, w, f) # :nodoc:
f[:p] ||= '0'
emit_w(e, w, f)
end
def emit_sn(e, w, f) # :nodoc:
if e < 0
w += 1
f[:s] = true
end
emit_n(e, w, f)
end
def emit_z(e, w, f) # :nodoc:
w += 1
f[:s] = true
emit_n(e, w, f)
end
def emit_a(e, w, f) # :nodoc:
f[:p] ||= "\s"
emit_w(e, w, f)
end
def emit_ad(e, w, f) # :nodoc:
if f[:x]
f[:u] = true
f[:d] = false
end
emit_a(e, w, f)
end
def emit_au(e, w, f) # :nodoc:
if f[:x]
f[:u] = false
f[:d] = true
end
emit_a(e, w, f)
end
private :emit, :emit_w, :emit_n, :emit_sn, :emit_z,
:emit_a, :emit_ad, :emit_au
def strftime(fmt='%F')
fmt.gsub(/%([-_0^#]+)?(\d+)?([EO]?(?::{1,3}z|.))/m) do
f = {}
m = $&
s, w, c = $1, $2, $3
if s
s.scan(/./) do |k|
case k
when '-'; f[:p] = '-'
when '_'; f[:p] = "\s"
when '0'; f[:p] = '0'
when '^'; f[:u] = true
when '#'; f[:x] = true
end
end
end
if w
f[:w] = w.to_i
end
case c
when 'A'; emit_ad(DAYNAMES[wday], 0, f)
when 'a'; emit_ad(ABBR_DAYNAMES[wday], 0, f)
when 'B'; emit_ad(MONTHNAMES[mon], 0, f)
when 'b'; emit_ad(ABBR_MONTHNAMES[mon], 0, f)
when 'C', 'EC'; emit_sn((year / 100).floor, 2, f)
when 'c', 'Ec'; emit_a(strftime('%a %b %e %H:%M:%S %Y'), 0, f)
when 'D'; emit_a(strftime('%m/%d/%y'), 0, f)
when 'd', 'Od'; emit_n(mday, 2, f)
when 'e', 'Oe'; emit_a(mday, 2, f)
when 'F'
if m == '%F'
format('%.4d-%02d-%02d', year, mon, mday) # 4p
else
emit_a(strftime('%Y-%m-%d'), 0, f)
end
when 'G'; emit_sn(cwyear, 4, f)
when 'g'; emit_n(cwyear % 100, 2, f)
when 'H', 'OH'; emit_n(hour, 2, f)
when 'h'; emit_ad(strftime('%b'), 0, f)
when 'I', 'OI'; emit_n((hour % 12).nonzero? || 12, 2, f)
when 'j'; emit_n(yday, 3, f)
when 'k'; emit_a(hour, 2, f)
when 'L'
f[:p] = nil
w = f[:w] || 3
u = 10**w
emit_n((sec_fraction * u).floor, w, f)
when 'l'; emit_a((hour % 12).nonzero? || 12, 2, f)
when 'M', 'OM'; emit_n(min, 2, f)
when 'm', 'Om'; emit_n(mon, 2, f)
when 'N'
f[:p] = nil
w = f[:w] || 9
u = 10**w
emit_n((sec_fraction * u).floor, w, f)
when 'n'; emit_a("\n", 0, f)
when 'P'; emit_ad(strftime('%p').downcase, 0, f)
when 'p'; emit_au(if hour < 12 then 'AM' else 'PM' end, 0, f)
when 'Q'
s = ((ajd - UNIX_EPOCH_IN_AJD) / MILLISECONDS_IN_DAY).round
emit_sn(s, 1, f)
when 'R'; emit_a(strftime('%H:%M'), 0, f)
when 'r'; emit_a(strftime('%I:%M:%S %p'), 0, f)
when 'S', 'OS'; emit_n(sec, 2, f)
when 's'
s = ((ajd - UNIX_EPOCH_IN_AJD) / SECONDS_IN_DAY).round
emit_sn(s, 1, f)
when 'T'
if m == '%T'
format('%02d:%02d:%02d', hour, min, sec) # 4p
else
emit_a(strftime('%H:%M:%S'), 0, f)
end
when 't'; emit_a("\t", 0, f)
when 'U', 'W', 'OU', 'OW'
emit_n(if c[-1,1] == 'U' then wnum0 else wnum1 end, 2, f)
when 'u', 'Ou'; emit_n(cwday, 1, f)
when 'V', 'OV'; emit_n(cweek, 2, f)
when 'v'; emit_a(strftime('%e-%b-%Y'), 0, f)
when 'w', 'Ow'; emit_n(wday, 1, f)
when 'X', 'EX'; emit_a(strftime('%H:%M:%S'), 0, f)
when 'x', 'Ex'; emit_a(strftime('%m/%d/%y'), 0, f)
when 'Y', 'EY'; emit_sn(year, 4, f)
when 'y', 'Ey', 'Oy'; emit_n(year % 100, 2, f)
when 'Z'; emit_au(strftime('%:z'), 0, f)
when /\A(:{0,3})z/
t = $1.size
sign = if offset < 0 then -1 else +1 end
fr = offset.abs
ss = fr.div(SECONDS_IN_DAY) # 4p
hh, ss = ss.divmod(3600)
mm, ss = ss.divmod(60)
if t == 3
if ss.nonzero? then t = 2
elsif mm.nonzero? then t = 1
else t = -1
end
end
case t
when -1
tail = []
sep = ''
when 0
f[:w] -= 2 if f[:w]
tail = ['%02d' % mm]
sep = ''
when 1
f[:w] -= 3 if f[:w]
tail = ['%02d' % mm]
sep = ':'
when 2
f[:w] -= 6 if f[:w]
tail = ['%02d' % mm, '%02d' % ss]
sep = ':'
end
([emit_z(sign * hh, 2, f)] + tail).join(sep)
when '%'; emit_a('%', 0, f)
when '+'; emit_a(strftime('%a %b %e %H:%M:%S %Z %Y'), 0, f)
else
m
end
end
end
# alias_method :format, :strftime
def asctime() strftime('%c') end

21
ext/date/timev.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef RUBY_TIMEV_H
#define RUBY_TIMEV_H
struct vtm {
VALUE year; /* 2000 for example. Integer. */
int mon; /* 1..12 */
int mday; /* 1..31 */
int hour; /* 0..23 */
int min; /* 0..59 */
int sec; /* 0..60 */
VALUE subsecx; /* 0 <= subsecx < TIME_SCALE. possibly Rational. */
VALUE utc_offset; /* -3600 as -01:00 for example. possibly Rational. */
int wday; /* 0:Sunday, 1:Monday, ..., 6:Saturday */
int yday; /* 1..366 */
int isdst; /* 0:StandardTime 1:DayLightSavingTime */
const char *zone; /* "JST", "EST", "EDT", etc. */
};
#define TIME_SCALE 1000000000
#endif

View file

@ -47,7 +47,7 @@ class TestDateStrftime < Test::Unit::TestCase
'%t'=>["\t",{}],
'%u'=>['6',{:cwday=>6}],
'%V'=>['05',{:cweek=>5}],
'%v'=>[' 3-Feb-2001',{:mday=>3,:mon=>2,:year=>2001}],
'%v'=>[' 3-FEB-2001',{:mday=>3,:mon=>2,:year=>2001}],
'%z'=>['+0000',{:zone=>'+0000',:offset=>0}],
'%+'=>['Sat Feb 3 00:00:00 +00:00 2001',
{:wday=>6,:mon=>2,:mday=>3,