Index: EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-time/src/time.c
===================================================================
--- EcnlProtoTool/trunk/mruby-1.2.0/mrbgems/mruby-time/src/time.c	(revision 321)
+++ EcnlProtoTool/trunk/mruby-1.3.0/mrbgems/mruby-time/src/time.c	(revision 331)
@@ -6,9 +6,27 @@
 
 #include <math.h>
+#include <time.h>
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#ifndef DISABLE_STDIO
 #include <stdio.h>
-#include <time.h>
-#include "mruby.h"
-#include "mruby/class.h"
-#include "mruby/data.h"
+#else
+#include <string.h>
+#endif
+
+#define NDIV(x,y) (-(-((x)+1)/(y))-1)
+
+#if _MSC_VER < 1800
+double round(double x) {
+  if (x >= 0.0) {
+    return (double)((int)(x + 0.5));
+  }
+  else {
+    return (double)((int)(x - 0.5));
+  }
+}
+#endif
 
 #if !defined(__MINGW64__) && defined(_WIN32)
@@ -42,4 +60,11 @@
 #endif
 #endif
+
+/* asctime(3) */
+/* mruby usually use its own implementation of struct tm to string conversion */
+/* except when DISABLE_STDIO is set. In that case, it uses asctime() or asctime_r(). */
+/* By default mruby tries to use asctime_r() which is reentrant. */
+/* Undef following macro on platforms that does not have asctime_r(). */
+/* #define NO_ASCTIME_R */
 
 /* timegm(3) */
@@ -154,4 +179,5 @@
 };
 
+#ifndef DISABLE_STDIO
 static const char mon_names[12][4] = {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
@@ -161,4 +187,5 @@
   "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
 };
+#endif
 
 struct mrb_time {
@@ -174,5 +201,5 @@
 seconds setting. Returns self on success, NULL of failure. */
 static struct mrb_time*
-mrb_time_update_datetime(struct mrb_time *self)
+time_update_datetime(mrb_state *mrb, struct mrb_time *self)
 {
   struct tm *aid;
@@ -184,5 +211,9 @@
     aid = localtime_r(&self->sec, &self->datetime);
   }
-  if (!aid) return NULL;
+  if (!aid) {
+    mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, (mrb_float)self->sec));
+    /* not reached */
+    return NULL;
+  }
 #ifdef NO_GMTIME_R
   self->datetime = *aid; /* copy data */
@@ -198,4 +229,5 @@
 }
 
+void mrb_check_num_exact(mrb_state *mrb, mrb_float num);
 
 /* Allocates a mrb_time object and initializes it. */
@@ -204,6 +236,9 @@
 {
   struct mrb_time *tm;
-
-  tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time));
+  time_t tsec = 0;
+
+  mrb_check_num_exact(mrb, (mrb_float)sec);
+  mrb_check_num_exact(mrb, (mrb_float)usec);
+
   if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) {
     goto out_of_range;
@@ -212,20 +247,24 @@
     goto out_of_range;
   }
-  tm->sec  = (time_t)sec;
-  if ((sec > 0 && tm->sec < 0) || (sec < 0 && (double)tm->sec > sec)) {
+  tsec  = (time_t)sec;
+  if ((sec > 0 && tsec < 0) || (sec < 0 && (double)tsec > sec)) {
   out_of_range:
     mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec));
   }
+  tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time));
+  tm->sec  = tsec;
   tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec);
-  while (tm->usec < 0) {
-    tm->sec--;
-    tm->usec += 1000000;
-  }
-  while (tm->usec >= 1000000) {
-    tm->sec++;
-    tm->usec -= 1000000;
+  if (tm->usec < 0) {
+    long sec2 = (long)NDIV(usec,1000000); /* negative div */
+    tm->usec -= sec2 * 1000000;
+    tm->sec += sec2;
+  }
+  else if (tm->usec >= 1000000) {
+    long sec2 = (long)(usec / 1000000);
+    tm->usec -= sec2 * 1000000;
+    tm->sec += sec2;
   }
   tm->timezone = timezone;
-  mrb_time_update_datetime(tm);
+  time_update_datetime(mrb, tm);
 
   return tm;
@@ -279,5 +318,5 @@
 #endif
   tm->timezone = MRB_TIMEZONE_LOCAL;
-  mrb_time_update_datetime(tm);
+  time_update_datetime(mrb, tm);
 
   return tm;
@@ -317,4 +356,13 @@
   nowtime.tm_sec   = (int)asec;
   nowtime.tm_isdst = -1;
+
+  if (nowtime.tm_mon  < 0 || nowtime.tm_mon  > 11
+      || nowtime.tm_mday < 1 || nowtime.tm_mday > 31
+      || nowtime.tm_hour < 0 || nowtime.tm_hour > 24
+      || (nowtime.tm_hour == 24 && (nowtime.tm_min > 0 || nowtime.tm_sec > 0))
+      || nowtime.tm_min  < 0 || nowtime.tm_min  > 59
+      || nowtime.tm_sec  < 0 || nowtime.tm_sec  > 60)
+    mrb_raise(mrb, E_RUNTIME_ERROR, "argument out of range");
+
   if (timezone == MRB_TIMEZONE_UTC) {
     nowsecs = timegm(&nowtime);
@@ -357,4 +405,15 @@
 }
 
+static struct mrb_time*
+time_get_ptr(mrb_state *mrb, mrb_value time)
+{
+  struct mrb_time *tm;
+
+  tm = DATA_GET_PTR(mrb, time, &mrb_time_type, struct mrb_time);
+  if (!tm) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized time");
+  }
+  return tm;
+}
 
 static mrb_value
@@ -366,5 +425,5 @@
 
   mrb_get_args(mrb, "o", &other);
-  tm1 = DATA_CHECK_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm1 = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
   tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
   eq_p = tm1 && tm2 && tm1->sec == tm2->sec && tm1->usec == tm2->usec;
@@ -380,5 +439,5 @@
 
   mrb_get_args(mrb, "o", &other);
-  tm1 = DATA_CHECK_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm1 = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
   tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
   if (!tm1 || !tm2) return mrb_nil_value();
@@ -406,5 +465,5 @@
 
   mrb_get_args(mrb, "f", &f);
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_time_make(mrb, mrb_obj_class(mrb, self), (double)tm->sec+f, (double)tm->usec, tm->timezone);
 }
@@ -418,6 +477,5 @@
 
   mrb_get_args(mrb, "o", &other);
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
-
+  tm = time_get_ptr(mrb, self);
   tm2 = DATA_CHECK_GET_PTR(mrb, other, &mrb_time_type, struct mrb_time);
   if (tm2) {
@@ -439,5 +497,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_wday);
 }
@@ -450,5 +508,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_yday + 1);
 }
@@ -461,5 +519,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_year + 1900);
 }
@@ -472,5 +530,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   if (tm->timezone <= MRB_TIMEZONE_NONE) return mrb_nil_value();
   if (tm->timezone >= MRB_TIMEZONE_LAST) return mrb_nil_value();
@@ -485,11 +543,20 @@
 mrb_time_asctime(mrb_state *mrb, mrb_value self)
 {
-  struct mrb_time *tm;
-  struct tm *d;
+  struct mrb_time *tm = time_get_ptr(mrb, self);
+  struct tm *d = &tm->datetime;
+  int len;
+
+#if defined(DISABLE_STDIO)
+  char *s;
+# ifdef NO_ASCTIME_R
+  s = asctime(d);
+# else
+  char buf[32];
+  s = asctime_r(d, buf);
+# endif
+  len = strlen(s)-1;            /* truncate the last newline */
+#else
   char buf[256];
-  int len;
-
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
-  d = &tm->datetime;
+
   len = snprintf(buf, sizeof(buf), "%s %s %02d %02d:%02d:%02d %s%d",
     wday_names[d->tm_wday], mon_names[d->tm_mon], d->tm_mday,
@@ -497,4 +564,5 @@
     tm->timezone == MRB_TIMEZONE_UTC ? "UTC " : "",
     d->tm_year + 1900);
+#endif
   return mrb_str_new(mrb, buf, len);
 }
@@ -507,6 +575,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
-  if (!tm) return mrb_nil_value();
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_mday);
 }
@@ -520,5 +587,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_bool_value(tm->datetime.tm_isdst);
 }
@@ -532,9 +599,9 @@
   struct mrb_time *tm, *tm2;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
   *tm2 = *tm;
   tm2->timezone = MRB_TIMEZONE_UTC;
-  mrb_time_update_datetime(tm2);
+  time_update_datetime(mrb, tm2);
   return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2);
 }
@@ -547,9 +614,9 @@
   struct mrb_time *tm, *tm2;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   tm2 = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm));
   *tm2 = *tm;
   tm2->timezone = MRB_TIMEZONE_LOCAL;
-  mrb_time_update_datetime(tm2);
+  time_update_datetime(mrb, tm2);
   return mrb_time_wrap(mrb, mrb_obj_class(mrb, self), tm2);
 }
@@ -562,5 +629,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_hour);
 }
@@ -576,4 +643,6 @@
   struct mrb_time *tm;
 
+  n = mrb_get_args(mrb, "|iiiiiii",
+       &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec);
   tm = (struct mrb_time*)DATA_PTR(self);
   if (tm) {
@@ -582,6 +651,4 @@
   mrb_data_init(self, NULL, &mrb_time_type);
 
-  n = mrb_get_args(mrb, "|iiiiiii",
-       &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec);
   if (n == 0) {
     tm = current_mrb_time(mrb);
@@ -600,4 +667,5 @@
 {
   mrb_value src;
+  struct mrb_time *t1, *t2;
 
   mrb_get_args(mrb, "o", &src);
@@ -606,8 +674,14 @@
     mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
   }
-  if (!DATA_PTR(copy)) {
-    mrb_data_init(copy, mrb_malloc(mrb, sizeof(struct mrb_time)), &mrb_time_type);
-  }
-  *(struct mrb_time *)DATA_PTR(copy) = *(struct mrb_time *)DATA_PTR(src);
+  t1 = (struct mrb_time *)DATA_PTR(copy);
+  t2 = (struct mrb_time *)DATA_PTR(src);
+  if (!t2) {
+    mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized time");
+  }
+  if (!t1) {
+    t1 = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time));
+    mrb_data_init(copy, t1, &mrb_time_type);
+  }
+  *t1 = *t2;
   return copy;
 }
@@ -620,7 +694,7 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   tm->timezone = MRB_TIMEZONE_LOCAL;
-  mrb_time_update_datetime(tm);
+  time_update_datetime(mrb, tm);
   return self;
 }
@@ -633,5 +707,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_mday);
 }
@@ -644,5 +718,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_min);
 }
@@ -655,5 +729,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_mon + 1);
 }
@@ -666,5 +740,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_fixnum_value(tm->datetime.tm_sec);
 }
@@ -678,5 +752,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_float_value(mrb, (mrb_float)tm->sec + (mrb_float)tm->usec/1.0e6);
 }
@@ -689,5 +763,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   if (tm->sec > MRB_INT_MAX || tm->sec < MRB_INT_MIN) {
     return mrb_float_value(mrb, (mrb_float)tm->sec);
@@ -703,5 +777,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   if (tm->usec > MRB_INT_MAX || tm->usec < MRB_INT_MIN) {
     return mrb_float_value(mrb, (mrb_float)tm->usec);
@@ -717,7 +791,7 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   tm->timezone = MRB_TIMEZONE_UTC;
-  mrb_time_update_datetime(tm);
+  time_update_datetime(mrb, tm);
   return self;
 }
@@ -730,5 +804,5 @@
   struct mrb_time *tm;
 
-  tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time);
+  tm = time_get_ptr(mrb, self);
   return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC);
 }
