marshal_dump() private

No documentation

This method has no description. You can help the Ruby community by adding new notes.

Hide source
static VALUE
time_mdump(VALUE time)
{
    struct time_object *tobj;
    unsigned long p, s;
    char buf[8];
    int i;
    VALUE str;

    struct vtm vtm;
    long year;
    long usec, nsec;
    VALUE subsecx, nano, subnano, v, zone;

    GetTimeval(time, tobj);

    gmtimew(tobj->timew, &vtm);

    if (FIXNUM_P(vtm.year)) {
        year = FIX2LONG(vtm.year);
        if (year < 1900 || 1900+0xffff < year)
            rb_raise(rb_eArgError, "year too %s to marshal: %ld UTC",
                     (year < 1900 ? "small" : "big"), year);
    }
    else {
        rb_raise(rb_eArgError, "year too %s to marshal: %"PRIsVALUE" UTC",
                 (le(vtm.year, INT2FIX(1900)) ? "small" : "big"), vtm.year);
    }

    subsecx = vtm.subsecx;

    nano = mulquov(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
    divmodv(nano, INT2FIX(1), &v, &subnano);
    nsec = FIX2LONG(v);
    usec = nsec / 1000;
    nsec = nsec % 1000;

    nano = addv(LONG2FIX(nsec), subnano);

    p = 0x1UL            << 31 | /*  1 */
        TZMODE_UTC_P(tobj) << 30 | /*  1 */
        (year-1900)      << 14 | /* 16 */
        (vtm.mon-1)      << 10 | /*  4 */
        vtm.mday         <<  5 | /*  5 */
        vtm.hour;                /*  5 */
    s = (unsigned long)vtm.min << 26 | /*  6 */
        vtm.sec          << 20 | /*  6 */
        usec;    /* 20 */

    for (i=0; i<4; i++) {
        buf[i] = (unsigned char)p;
        p = RSHIFT(p, 8);
    }
    for (i=4; i<8; i++) {
        buf[i] = (unsigned char)s;
        s = RSHIFT(s, 8);
    }

    str = rb_str_new(buf, 8);
    rb_copy_generic_ivar(str, time);
    if (!rb_equal(nano, INT2FIX(0))) {
        if (RB_TYPE_P(nano, T_RATIONAL)) {
            rb_ivar_set(str, id_nano_num, RRATIONAL(nano)->num);
            rb_ivar_set(str, id_nano_den, RRATIONAL(nano)->den);
        }
        else {
            rb_ivar_set(str, id_nano_num, nano);
            rb_ivar_set(str, id_nano_den, INT2FIX(1));
        }
    }
    if (nsec) { /* submicro is only for Ruby 1.9.1 compatibility */
        /*
         * submicro is formatted in fixed-point packed BCD (without sign).
         * It represent digits under microsecond.
         * For nanosecond resolution, 3 digits (2 bytes) are used.
         * However it can be longer.
         * Extra digits are ignored for loading.
         */
        char buf[2];
        int len = (int)sizeof(buf);
        buf[1] = (char)((nsec % 10) << 4);
        nsec /= 10;
        buf[0] = (char)(nsec % 10);
        nsec /= 10;
        buf[0] |= (char)((nsec % 10) << 4);
        if (buf[1] == 0)
            len = 1;
        rb_ivar_set(str, id_submicro, rb_str_new(buf, len));
    }
    if (!TZMODE_UTC_P(tobj)) {
        VALUE off = rb_time_utc_offset(time), div, mod;
        divmodv(off, INT2FIX(1), &div, &mod);
        if (rb_equal(mod, INT2FIX(0)))
            off = rb_Integer(div);
        rb_ivar_set(str, id_offset, off);
    }
    zone = tobj->vtm.zone;
    if (maybe_tzobj_p(zone)) {
        zone = rb_funcallv(zone, id_name, 0, 0);
    }
    rb_ivar_set(str, id_zone, zone);
    return str;
}
Register or log in to add new notes.