summaryrefslogtreecommitdiff
path: root/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'time.c')
-rw-r--r--time.c80
1 files changed, 65 insertions, 15 deletions
diff --git a/time.c b/time.c
index 016ec879f3..757e42cb14 100644
--- a/time.c
+++ b/time.c
@@ -60,7 +60,7 @@ time_s_now(klass)
VALUE obj;
struct time_object *tobj;
- obj = Data_Make_Struct(klass, struct time_object, 0, 0, tobj);
+ obj = Data_Make_Struct(klass, struct time_object, 0, free, tobj);
tobj->tm_got=0;
if (gettimeofday(&(tobj->tv), 0) == -1) {
@@ -79,7 +79,9 @@ time_new_internal(klass, sec, usec)
VALUE obj;
struct time_object *tobj;
- obj = Data_Make_Struct(klass, struct time_object, 0, 0, tobj);
+ if (sec < 0 || (sec == 0 && usec < 0))
+ rb_raise(rb_eArgError, "time must be positive");
+ obj = Data_Make_Struct(klass, struct time_object, 0, free, tobj);
tobj->tm_got = 0;
tobj->tv.tv_sec = sec;
tobj->tv.tv_usec = usec;
@@ -103,27 +105,23 @@ rb_time_timeval(time)
switch (TYPE(time)) {
case T_FIXNUM:
- t.tv_sec = FIX2UINT(time);
+ t.tv_sec = FIX2INT(time);
if (t.tv_sec < 0)
rb_raise(rb_eArgError, "time must be positive");
t.tv_usec = 0;
break;
case T_FLOAT:
- {
- double seconds, microseconds;
-
- if (RFLOAT(time)->value < 0.0)
- rb_raise(rb_eArgError, "time must be positive");
- seconds = floor(RFLOAT(time)->value);
- microseconds = (RFLOAT(time)->value - seconds) * 1000000.0;
- t.tv_sec = seconds;
- t.tv_usec = microseconds;
- }
+ if (RFLOAT(time)->value < 0.0)
+ rb_raise(rb_eArgError, "time must be positive");
+ t.tv_sec = floor(RFLOAT(time)->value);
+ t.tv_usec = (RFLOAT(time)->value - t.tv_sec) * 1000000.0;
break;
case T_BIGNUM:
t.tv_sec = NUM2INT(time);
+ if (t.tv_sec < 0)
+ rb_raise(rb_eArgError, "time must be positive");
t.tv_usec = 0;
break;
@@ -231,8 +229,8 @@ time_arg(argc, argv, args)
|| args[1] < 0 || args[1] > 11
|| args[2] < 1 || args[2] > 31
|| args[3] < 0 || args[3] > 23
- || args[4] < 0 || args[4] > 60
- || args[5] < 0 || args[5] > 61)
+ || args[4] < 0 || args[4] > 59
+ || args[5] < 0 || args[5] > 60)
rb_raise(rb_eArgError, "argument out of range");
}
@@ -796,6 +794,54 @@ time_s_times(obj)
#endif
}
+static VALUE
+time_dump(time, limit)
+ VALUE time, limit;
+{
+ struct time_object *tobj;
+ int sec, usec;
+ unsigned char buf[8];
+ int i;
+
+ GetTimeval(time, tobj);
+ sec = tobj->tv.tv_sec;
+ usec = tobj->tv.tv_usec;
+
+ for (i=0; i<4; i++) {
+ buf[i] = sec & 0xff;
+ sec = RSHIFT(sec, 8);
+ }
+ for (i=4; i<8; i++) {
+ buf[i] = usec & 0xff;
+ usec = RSHIFT(usec, 8);
+ }
+ return rb_str_new(buf, 8);
+}
+
+static VALUE
+time_load(klass, str)
+ VALUE klass, str;
+{
+ int sec, usec;
+ unsigned char *buf;
+ int i;
+
+ buf = str2cstr(str, &i);
+ if (i != 8) {
+ rb_raise(rb_eTypeError, "marshaled time format differ");
+ }
+
+ sec = usec = 0;
+ for (i=0; i<4; i++) {
+ sec |= buf[i]<<(8*i);
+ }
+ for (i=4; i<8; i++) {
+ usec |= buf[i]<<(8*(i-4));
+ }
+
+ return time_new_internal(klass, sec, usec);
+}
+
void
Init_Time()
{
@@ -850,4 +896,8 @@ Init_Time()
#if defined(HAVE_TIMES) || defined(NT)
S_Tms = rb_struct_define("Tms", "utime", "stime", "cutime", "cstime", 0);
#endif
+
+ /* methods for marshaling */
+ rb_define_singleton_method(rb_cTime, "_load", time_load, 1);
+ rb_define_method(rb_cTime, "_dump", time_dump, 1);
}