summaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-16 07:22:43 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-04-16 07:22:43 +0000
commitf2979f3101a0cb1467971ea3b4794c19c6b639dd (patch)
tree3d71a8b25c869ac5fc69a59baae1711ce2e7db92 /win32
parent72fffe5cee069d9f47a7a8dc808885aec67da225 (diff)
* win32/win32.c (gmtime_r, localtime_r): POSIX compliant reentrant
versions. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35348 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'win32')
-rw-r--r--win32/Makefile.sub1
-rw-r--r--win32/win32.c105
2 files changed, 106 insertions, 0 deletions
diff --git a/win32/Makefile.sub b/win32/Makefile.sub
index 33ea9835d1..10bb4003e0 100644
--- a/win32/Makefile.sub
+++ b/win32/Makefile.sub
@@ -651,6 +651,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_SIGNBIT 1
#define HAVE_TZNAME 1
#define HAVE_DAYLIGHT 1
+#define HAVE_GMTIME_R 1
#define SETPGRP_VOID 1
#define RSHIFT(x,y) ((x)>>(int)y)
#define HAVE_RB_FD_INIT 1
diff --git a/win32/win32.c b/win32/win32.c
index c114aa7660..687d8bd04a 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -6257,3 +6257,108 @@ char
rb_w32_fd_is_text(int fd) {
return _osfile(fd) & FTEXT;
}
+
+#if RUBY_MSVCRT_VERSION < 80
+static int
+unixtime_to_systemtime(const time_t t, SYSTEMTIME *st)
+{
+ FILETIME ft;
+ if (unixtime_to_filetime(t, &ft)) return -1;
+ if (!FileTimeToSystemTime(&ft, st)) return -1;
+ return 0;
+}
+
+static void
+systemtime_to_tm(const SYSTEMTIME *st, struct tm *t)
+{
+ int y = st->wYear, m = st->wMonth, d = st->wDay;
+ t->tm_sec = st->wSecond;
+ t->tm_min = st->wMinute;
+ t->tm_hour = st->wHour;
+ t->tm_mday = st->wDay;
+ t->tm_mon = st->wMonth - 1;
+ t->tm_year = y - 1900;
+ t->tm_wday = st->wDayOfWeek;
+ switch (m) {
+ case 1:
+ break;
+ case 2:
+ d += 31;
+ break;
+ default:
+ d += 31 + 28 + (!(y % 4) && ((y % 100) || !(y % 400)));
+ d += ((m - 3) * 153 + 2) / 5;
+ break;
+ }
+ t->tm_yday = d - 1;
+}
+
+static int
+systemtime_to_localtime(TIME_ZONE_INFORMATION *tz, SYSTEMTIME *gst, SYSTEMTIME *lst)
+{
+ TIME_ZONE_INFORMATION stdtz;
+ SYSTEMTIME sst;
+
+ if (!SystemTimeToTzSpecificLocalTime(tz, gst, lst)) return -1;
+ if (!tz) {
+ GetTimeZoneInformation(&stdtz);
+ tz = &stdtz;
+ }
+ if (tz->StandardBias == tz->DaylightBias) return 0;
+ if (!tz->StandardDate.wMonth) return 0;
+ if (!tz->DaylightDate.wMonth) return 0;
+ if (tz != &stdtz) stdtz = *tz;
+
+ stdtz.StandardDate.wMonth = stdtz.DaylightDate.wMonth = 0;
+ if (!SystemTimeToTzSpecificLocalTime(&stdtz, gst, &sst)) return 0;
+ if (lst->wMinute == sst.wMinute && lst->wHour == sst.wHour)
+ return 0;
+ return 1;
+}
+#endif
+
+struct tm *
+gmtime_r(const time_t *tp, struct tm *rp)
+{
+ int e = EINVAL;
+ if (!tp || !rp) {
+ error:
+ errno = e;
+ return NULL;
+ }
+#if RUBY_MSVCRT_VERSION >= 80
+ e = gmtime_s(rp, tp);
+ if (e != 0) goto error;
+#else
+ {
+ SYSTEMTIME st;
+ if (unixtime_to_systemtime(*tp, &st)) goto error;
+ rp->tm_isdst = 0;
+ systemtime_to_tm(&st, rp);
+ }
+#endif
+ return rp;
+}
+
+struct tm *
+localtime_r(const time_t *tp, struct tm *rp)
+{
+ int e = EINVAL;
+ if (!tp || !rp) {
+ error:
+ errno = e;
+ return NULL;
+ }
+#if RUBY_MSVCRT_VERSION >= 80
+ e = localtime_s(rp, tp);
+ if (e) goto error;
+#else
+ {
+ SYSTEMTIME gst, lst;
+ if (unixtime_to_systemtime(*tp, &gst)) goto error;
+ rp->tm_isdst = systemtime_to_localtime(NULL, &gst, &lst);
+ systemtime_to_tm(&lst, rp);
+ }
+#endif
+ return rp;
+}