summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--configure.in1
-rw-r--r--include/ruby/win32.h3
-rw-r--r--win32/Makefile.sub1
-rw-r--r--win32/win32.c105
5 files changed, 114 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 6218232921..3b76bc9394 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,7 @@
-Mon Apr 16 16:08:18 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon Apr 16 16:22:40 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (gmtime_r, localtime_r): POSIX compliant reentrant
+ versions.
* configure.in (RUBY_MSVCRT_VERSION): define on mingw too.
diff --git a/configure.in b/configure.in
index f7e6f3cd95..0dd9203792 100644
--- a/configure.in
+++ b/configure.in
@@ -1089,6 +1089,7 @@ main()
rb_cv_negative_time_t=no
ac_cv_func_fcntl=yes
ac_cv_func_flock=yes
+ ac_cv_func_gmtime_r=yes
rb_cv_large_fd_select=yes
AC_LIBOBJ([langinfo])
: ${enable_win95=maybe}
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index 302bf5e8cf..1f966484b8 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -690,6 +690,9 @@ struct tms {
int rb_w32_times(struct tms *);
+struct tm *gmtime_r(const time_t *, struct tm *);
+struct tm *localtime_r(const time_t *, struct tm *);
+
/* thread stuff */
int rb_w32_sleep(unsigned long msec);
int rb_w32_putc(int, FILE*);
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;
+}